fix: Switch agent commands from @-syntax to XML tags — Claude Code refuses to output @-directives
Root cause: opencode/Claude Code recognizes the Frankenbot repo context from CLAUDE.md and refuses to output @CREATE_SUBTASK, @SEND_EMAIL etc. as they look like 'system directives'. XML tags (<create_task>, <send_email>, etc.) work reliably. - parse_agent_commands(): full rewrite with XML tag parser, supports both XML child tags and key: value fields within blocks - build_agent_prompt(): command docs updated to XML format with code examples - orchestrator/systemprompt.md: rewritten with XML action examples - ar_manager/systemprompt.md: @ASK_ORCHESTRATOR -> <ask_orchestrator>
This commit is contained in:
parent
54cc5a496f
commit
c6ce8a873c
3 changed files with 260 additions and 310 deletions
|
|
@ -47,10 +47,10 @@ Performance-Score: [0-10]
|
|||
|
||||
**Empfehlung zum Löschen:**
|
||||
```
|
||||
@ASK_ORCHESTRATOR
|
||||
Question: Agent [name] sollte gelöscht werden.
|
||||
Context: [Performance-Details und Begründung]
|
||||
@END
|
||||
<ask_orchestrator>
|
||||
question: Agent [name] sollte gelöscht werden.
|
||||
context: [Performance-Details und Begründung]
|
||||
</ask_orchestrator>
|
||||
```
|
||||
|
||||
**Status-Report anfordern:**
|
||||
|
|
|
|||
|
|
@ -6,50 +6,77 @@ Du bist der zentrale Orchestrator des Frankenbot-Systems für das Diversity Ball
|
|||
|
||||
1. **Anfragen analysieren** — Was will die Person? Was muss getan werden?
|
||||
2. **Entscheiden** — Sofort antworten, oder Task delegieren, oder beides?
|
||||
3. **Handeln** — Die richtigen Kommandos ausführen (Email, Telegram, Sub-Task, Team-Update)
|
||||
4. **Kommunizieren** — Klare, direkte Antworten. Keine unnötigen Gedankengänge.
|
||||
|
||||
## Wann du einen Sub-Task anlegst
|
||||
|
||||
Lege mit `@CREATE_SUBTASK` einen Task an wenn:
|
||||
- Jemand dich bittet etwas zu **tun** (Email schreiben, recherchieren, berechnen, Dokument erstellen)
|
||||
- Die Aufgabe mehr als eine kurze Antwort erfordert
|
||||
- Ein spezialisierter Agent (Budget, Catering, Location, etc.) besser geeignet ist
|
||||
- Du eine Aufgabe für später merken willst
|
||||
|
||||
**Lege KEINEN Sub-Task an** wenn:
|
||||
- Es eine einfache Frage ist die du direkt beantworten kannst
|
||||
- Jemand nur eine Information will die du kennst
|
||||
- Es um System-Konfiguration geht (Team-Member updaten etc.)
|
||||
3. **Handeln** — Die richtigen XML-Aktionen ausführen
|
||||
4. **Kommunizieren** — Klare, direkte Antworten auf Deutsch
|
||||
|
||||
## Verfügbare spezialisierte Agenten
|
||||
|
||||
Die Agenten liegen in `agents/<name>/systemprompt.md`. Aktuell verfügbar:
|
||||
- **budget_manager** — Budgetplanung, Kostenkalkulation, Finanzübersicht
|
||||
- **catering_manager** — Catering, Essen & Trinken, Lieferanten
|
||||
- **location_manager** — Venue, Location, Raumplanung
|
||||
- **program_manager** — Programm, Zeitplan, Acts, Ablauf
|
||||
- **music_rights** — Musikrechte, GEMA, Lizenzen
|
||||
- **musik_rechte_advisor** — Musikrechte, GEMA, Lizenzen
|
||||
- **tax_advisor** — Steuerberatung, rechtliche Fragen
|
||||
- **researcher** — Recherche, Internet-Suche, Fakten
|
||||
- **social_media** — Social Media, Marketing, Kommunikation
|
||||
- **social_media_manager** — Social Media, Marketing, Kommunikation
|
||||
- **negotiator** — Verhandlungen, Verträge, Konditionen
|
||||
- **hr_manager** — Personal, Volunteers, Team-Koordination
|
||||
- **zusammenfasser** — Zusammenfassungen, Reports
|
||||
|
||||
Falls kein passender Agent existiert: `@SUGGEST_AGENT` verwenden.
|
||||
## Wann du einen Task anlegst
|
||||
|
||||
## Delegations-Regeln
|
||||
Lege einen Task an wenn jemand dich bittet etwas zu **tun** (recherchieren, berechnen, Email schreiben, Dokument erstellen, Angebot einholen etc.). Beantworte einfache Fragen direkt ohne Task.
|
||||
|
||||
- Führe komplexe Aufgaben NICHT selbst aus — delegiere via `@CREATE_SUBTASK`
|
||||
- Für einfache Aktionen (Email, Telegram) führe sie direkt aus mit den Kommandos
|
||||
- Für Team-Daten: direkt mit `@UPDATE_TEAM_MEMBER` oder `@ADD_TEAM_MEMBER` updaten
|
||||
- Antworte immer auf Deutsch, außer die Person schreibt auf Englisch
|
||||
## Aktionen (XML-Tags — werden automatisch ausgeführt)
|
||||
|
||||
## Umgang mit Gesprächsnachrichten
|
||||
**Task an spezialisierten Agenten delegieren:**
|
||||
```
|
||||
<create_task>
|
||||
title: Kurzer Titel der Aufgabe
|
||||
agent: catering_manager
|
||||
details: Was genau getan werden soll, alle relevanten Details
|
||||
</create_task>
|
||||
```
|
||||
|
||||
Wenn jemand mit dir redet:
|
||||
1. Antworte freundlich und direkt auf die Nachricht
|
||||
2. Wenn eine Aufgabe dabei ist → lege sofort einen `@CREATE_SUBTASK` an
|
||||
3. Wenn du eine Email oder Telegram-Nachricht schicken sollst → tue es direkt mit `@SEND_EMAIL` / `@SEND_TELEGRAM`
|
||||
4. Wenn Team-Daten zu aktualisieren sind → tue es direkt mit `@UPDATE_TEAM_MEMBER`
|
||||
5. Bestätige was du getan hast
|
||||
**Email versenden:**
|
||||
```
|
||||
<send_email>
|
||||
to: email@adresse.com
|
||||
subject: Betreff
|
||||
body: Nachrichtentext
|
||||
</send_email>
|
||||
```
|
||||
|
||||
**Telegram-Nachricht senden:**
|
||||
```
|
||||
<send_telegram>
|
||||
telegram_id: 1578034974
|
||||
message: Nachricht
|
||||
</send_telegram>
|
||||
```
|
||||
|
||||
**Team-Member-Daten aktualisieren:**
|
||||
```
|
||||
<update_team_member>
|
||||
identifier: name@email.com
|
||||
telegram_id: 1234567890
|
||||
role: Neue Rolle
|
||||
</update_team_member>
|
||||
```
|
||||
|
||||
**Neuen Team-Member hinzufügen:**
|
||||
```
|
||||
<add_team_member>
|
||||
name: Vollständiger Name
|
||||
role: Rolle
|
||||
responsibilities: Verantwortlichkeiten
|
||||
email: email@adresse.com
|
||||
</add_team_member>
|
||||
```
|
||||
|
||||
## Verhalten bei Nachrichten
|
||||
|
||||
1. Antworte freundlich und direkt
|
||||
2. Wenn eine Aufgabe dabei ist → sofort `<create_task>` anlegen
|
||||
3. Wenn Email/Telegram gesendet werden soll → `<send_email>` / `<send_telegram>` direkt ausführen
|
||||
4. Wenn Team-Daten zu aktualisieren → `<update_team_member>` direkt ausführen
|
||||
5. Bestätige am Ende was du getan hast
|
||||
|
|
|
|||
467
app.py
467
app.py
|
|
@ -543,71 +543,79 @@ Context: [Kontext]
|
|||
|
||||
## Verfügbare Tools (Claude Code Built-ins):
|
||||
Du läufst als Claude Code Agent und hast folgende Tools direkt verfügbar:
|
||||
- **WebFetch** – Webseiten abrufen und analysieren (URLs fetchen, Recherche)
|
||||
- **Read** – Dateien lesen (absoluter Pfad)
|
||||
- **Write** – Dateien schreiben/erstellen
|
||||
- **Edit** – Bestehende Dateien bearbeiten
|
||||
- **Glob** – Dateien nach Muster suchen (z.B. `**/*.pdf`)
|
||||
- **Grep** – Inhalte in Dateien durchsuchen (Regex)
|
||||
- **Bash** – Shell-Befehle ausführen (z.B. Berechnungen, Dateioperationen)
|
||||
- **WebFetch** – Webseiten abrufen und analysieren
|
||||
- **Read** – Dateien lesen
|
||||
- **Write** / **Edit** – Dateien schreiben und bearbeiten
|
||||
- **Glob** / **Grep** – Dateien und Inhalte durchsuchen
|
||||
- **Bash** – Shell-Befehle ausführen
|
||||
|
||||
Nutze diese Tools aktiv für Recherche, Dateiverarbeitung und Berechnungen!
|
||||
## Frankenbot-Aktionen (XML-Tags – werden nach deiner Antwort automatisch ausgeführt):
|
||||
|
||||
## Frankenbot-Kommandos (werden vom System verarbeitet):
|
||||
Diese Kommandos musst du exakt so formatieren – sie werden nach deiner Antwort automatisch ausgeführt:
|
||||
**Task erstellen / delegieren:**
|
||||
```
|
||||
<create_task>
|
||||
title: [Kurzer Titel]
|
||||
agent: [agent_key z.B. catering_manager, budget_manager, researcher ...]
|
||||
details: [Was genau getan werden soll]
|
||||
</create_task>
|
||||
```
|
||||
|
||||
**Frage an Orchestrator / Sub-Task delegieren:**
|
||||
@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
|
||||
**Frage an Orchestrator:**
|
||||
```
|
||||
<ask_orchestrator>
|
||||
question: [Deine Frage]
|
||||
context: [Warum brauchst du das?]
|
||||
</ask_orchestrator>
|
||||
```
|
||||
|
||||
**Email versenden:**
|
||||
@SEND_EMAIL
|
||||
To: [Email-Adresse]
|
||||
Subject: [Betreff]
|
||||
Body: [Nachricht]
|
||||
@END
|
||||
```
|
||||
<send_email>
|
||||
to: [email@adresse.com]
|
||||
subject: [Betreff]
|
||||
body: [Nachrichtentext]
|
||||
</send_email>
|
||||
```
|
||||
|
||||
**Telegram-Nachricht senden:**
|
||||
@SEND_TELEGRAM
|
||||
TelegramID: [Numerische Telegram-ID aus den Team-Member-Daten]
|
||||
Message: [Nachricht]
|
||||
@END
|
||||
```
|
||||
<send_telegram>
|
||||
telegram_id: [Numerische ID oder Name aus Team-Members]
|
||||
message: [Nachricht]
|
||||
</send_telegram>
|
||||
```
|
||||
|
||||
**Team-Member-Daten aktualisieren:**
|
||||
@UPDATE_TEAM_MEMBER
|
||||
Identifier: [Email oder Name des Team-Members]
|
||||
Name: [Neuer Name] (optional)
|
||||
Role: [Neue Rolle] (optional)
|
||||
Responsibilities: [Neue Verantwortlichkeiten] (optional)
|
||||
TelegramID: [Telegram-ID als Zahl] (optional)
|
||||
Phone: [Telefon] (optional)
|
||||
@END
|
||||
**Team-Member aktualisieren:**
|
||||
```
|
||||
<update_team_member>
|
||||
identifier: [Email oder Name]
|
||||
telegram_id: [Zahl] (optional)
|
||||
role: [Neue Rolle] (optional)
|
||||
phone: [Telefon] (optional)
|
||||
</update_team_member>
|
||||
```
|
||||
|
||||
**Neuen Team-Member hinzufügen:**
|
||||
@ADD_TEAM_MEMBER
|
||||
Name: [Vollständiger Name]
|
||||
Role: [Rolle/Position]
|
||||
Responsibilities: [Verantwortlichkeiten]
|
||||
Email: [Email-Adresse]
|
||||
@END
|
||||
```
|
||||
<add_team_member>
|
||||
name: [Vollständiger Name]
|
||||
role: [Rolle]
|
||||
responsibilities: [Verantwortlichkeiten]
|
||||
email: [Email]
|
||||
</add_team_member>
|
||||
```
|
||||
|
||||
**Neuen Agent vorschlagen:**
|
||||
```
|
||||
<suggest_agent>
|
||||
role: [Rolle]
|
||||
skills: [Fähigkeiten]
|
||||
reason: [Warum gebraucht]
|
||||
</suggest_agent>
|
||||
```
|
||||
|
||||
## Wichtig:
|
||||
- Arbeitsverzeichnis: {work_dir} – speichere alle Dateien dort mit absolutem Pfad
|
||||
- Arbeitsverzeichnis: {work_dir}
|
||||
- Liefere immer eine vollständige, direkt verwertbare Antwort
|
||||
{extra_context}"""
|
||||
|
||||
|
|
@ -980,271 +988,186 @@ def respond_to_message(message_id, response):
|
|||
return False
|
||||
|
||||
def parse_agent_commands(agent_key, response_text, task_id=None):
|
||||
"""Parst Agent-Antwort nach Orchestrator-Kommandos und führt sie aus."""
|
||||
"""Parst Agent-Antwort nach XML-Kommando-Blöcken und führt sie aus.
|
||||
|
||||
Unterstützte Tags (Claude Code gibt @ Kommandos nicht zuverlässig aus):
|
||||
<create_task>title/agent/details</create_task>
|
||||
<ask_orchestrator>question/context</ask_orchestrator>
|
||||
<suggest_agent>role/skills/reason</suggest_agent>
|
||||
<send_email>to/subject/body</send_email>
|
||||
<send_telegram>telegram_id/message</send_telegram>
|
||||
<add_team_member>name/role/responsibilities/email</add_team_member>
|
||||
<update_team_member>identifier + beliebige Felder</update_team_member>
|
||||
"""
|
||||
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
|
||||
def get_field(block, field):
|
||||
"""Extrahiert ein Feld aus einem XML-Block: 'field: value' oder '<field>value</field>'."""
|
||||
# Versuche erst XML-Tag-Format
|
||||
m = re.search(rf'<{field}>(.*?)</{field}>', block, re.DOTALL | re.IGNORECASE)
|
||||
if m:
|
||||
return m.group(1).strip()
|
||||
# Dann Key-Value-Format
|
||||
m = re.search(rf'^{field}\s*:\s*(.+)', block, re.MULTILINE | re.IGNORECASE)
|
||||
if m:
|
||||
return m.group(1).strip()
|
||||
return ''
|
||||
|
||||
# ── CREATE_TASK ──────────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<create_task>(.*?)</create_task>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
title = get_field(block, 'title') or block.strip()[:80]
|
||||
agent = get_field(block, 'agent') or 'orchestrator'
|
||||
details = get_field(block, 'details') or get_field(block, 'requirements') or ''
|
||||
if not title:
|
||||
continue
|
||||
new_id = create_task(
|
||||
title=title[:100],
|
||||
description=f"Von {agent_key} delegiert:\n{details}",
|
||||
agent_key=agent if agent in AGENTS else 'orchestrator',
|
||||
task_type='agent_subtask',
|
||||
created_by=agent_key,
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
for question, context in ask_requests:
|
||||
# Erstelle Task für Orchestrator um die Frage zu beantworten
|
||||
task_id = create_task(
|
||||
title=f"Frage von {agent_key}: {question.strip()[:80]}",
|
||||
description=f"""Ein Agent braucht Hilfe!
|
||||
logger.info(f"[AgentCmd] {agent_key} erstellt Task #{new_id}: {title[:50]}")
|
||||
|
||||
**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.""",
|
||||
# ── ASK_ORCHESTRATOR ─────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<ask_orchestrator>(.*?)</ask_orchestrator>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
question = get_field(block, 'question') or block.strip()[:80]
|
||||
context = get_field(block, 'context') or ''
|
||||
new_id = create_task(
|
||||
title=f"Frage von {agent_key}: {question[:80]}",
|
||||
description=f"**Von:** {agent_key}\n**Frage:** {question}\n**Kontext:** {context}",
|
||||
agent_key='orchestrator',
|
||||
task_type='agent_question',
|
||||
created_by=agent_key,
|
||||
from_agent=agent_key,
|
||||
return_to=agent_key
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
logger.info(f"[AgentCmd] {agent_key} fragt Orchestrator (Task #{task_id}): {question.strip()[:50]}")
|
||||
logger.info(f"[AgentCmd] {agent_key} fragt Orchestrator (Task #{new_id})")
|
||||
|
||||
# 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:
|
||||
task_id = create_task(
|
||||
title=task_desc.strip()[:100],
|
||||
description=f"Von {agent_key} angefordert:\n{requirements.strip()}",
|
||||
agent_key='orchestrator',
|
||||
task_type='agent_subtask',
|
||||
created_by=agent_key,
|
||||
from_agent=agent_key
|
||||
)
|
||||
logger.info(f"[AgentCmd] {agent_key} erstellt Subtask #{task_id} 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
|
||||
task_id = create_task(
|
||||
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.""",
|
||||
# ── SUGGEST_AGENT ────────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<suggest_agent>(.*?)</suggest_agent>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
role = get_field(block, 'role') or block.strip()[:50]
|
||||
skills = get_field(block, 'skills') or ''
|
||||
reason = get_field(block, 'reason') or ''
|
||||
new_id = create_task(
|
||||
title=f"Agent-Vorschlag: {role}",
|
||||
description=f"**Rolle:** {role}\n**Fähigkeiten:** {skills}\n**Begründung:** {reason}",
|
||||
agent_key='orchestrator',
|
||||
task_type='agent_suggestion',
|
||||
created_by=agent_key,
|
||||
from_agent=agent_key,
|
||||
suggested_agent=agent_key_suggestion,
|
||||
suggested_role=role.strip(),
|
||||
suggested_skills=skills.strip()
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
logger.info(f"[AgentCmd] {agent_key} schlägt neuen Agent vor (Task #{task_id}): {role.strip()}")
|
||||
logger.info(f"[AgentCmd] {agent_key} schlägt Agent vor (Task #{new_id}): {role}")
|
||||
|
||||
# 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__), 'agents', 'orchestrator', 'knowledge', '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")
|
||||
|
||||
# SEND_EMAIL: Orchestrator sendet Email an Team-Member
|
||||
send_email_requests = re.findall(
|
||||
r'@SEND_EMAIL\s*\nTo:\s*([^\n]+)\s*\nSubject:\s*([^\n]+)\s*\nBody:\s*(.*?)@END',
|
||||
response_text,
|
||||
re.DOTALL
|
||||
)
|
||||
for to_addr, subject, body in send_email_requests:
|
||||
to_clean = to_addr.strip()
|
||||
subject_clean = subject.strip()
|
||||
body_clean = body.strip()
|
||||
|
||||
action_task_id = create_task(
|
||||
title=f"Email an {to_clean}: {subject_clean[:60]}",
|
||||
description=f"**An:** {to_clean}\n**Betreff:** {subject_clean}\n\n{body_clean}",
|
||||
# ── SEND_EMAIL ───────────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<send_email>(.*?)</send_email>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
to = get_field(block, 'to')
|
||||
subject = get_field(block, 'subject')
|
||||
body = get_field(block, 'body')
|
||||
if not to or not subject:
|
||||
logger.warning("[AgentCmd] <send_email> ohne to/subject ignoriert")
|
||||
continue
|
||||
action_id = create_task(
|
||||
title=f"Email an {to}: {subject[:60]}",
|
||||
description=f"**An:** {to}\n**Betreff:** {subject}\n\n{body}",
|
||||
agent_key=agent_key,
|
||||
task_type='action_email',
|
||||
created_by=agent_key,
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
success, message = send_email(to_clean, subject_clean, body_clean,
|
||||
triggered_by=f'agent:{agent_key}', task_id=action_task_id)
|
||||
success, msg = send_email(to, subject, body, triggered_by=f'agent:{agent_key}', task_id=action_id)
|
||||
if success:
|
||||
update_task_db(action_task_id, status='completed',
|
||||
response=f"✓ Email erfolgreich versendet an {to_clean}")
|
||||
logger.info(f"[AgentCmd] Email gesendet an {to_clean}: {subject_clean}")
|
||||
update_task_db(action_id, status='completed', response=f"✓ Email versendet an {to}")
|
||||
logger.info(f"[AgentCmd] Email gesendet an {to}: {subject}")
|
||||
else:
|
||||
update_task_db(action_task_id, status='error', response=f"✗ Fehler: {message}")
|
||||
logger.error(f"[AgentCmd] Email-Fehler: {message}")
|
||||
update_task_db(action_id, status='error', response=f"✗ {msg}")
|
||||
logger.error(f"[AgentCmd] Email-Fehler: {msg}")
|
||||
|
||||
# SEND_TELEGRAM: Orchestrator sendet Telegram-Nachricht
|
||||
# Format: TelegramID: <numerische ID> oder Name/Email (wird dann in DB nachgeschlagen)
|
||||
send_telegram_requests = re.findall(
|
||||
r'@SEND_TELEGRAM\s*\nTelegramID:\s*([^\n]+)\s*\nMessage:\s*(.*?)@END',
|
||||
response_text,
|
||||
re.DOTALL
|
||||
)
|
||||
for recipient, message in send_telegram_requests:
|
||||
recipient_clean = recipient.strip()
|
||||
message_clean = message.strip()
|
||||
|
||||
action_task_id = create_task(
|
||||
title=f"Telegram an {recipient_clean}: {message_clean[:60]}",
|
||||
description=f"**An:** {recipient_clean}\n\n{message_clean}",
|
||||
# ── SEND_TELEGRAM ────────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<send_telegram>(.*?)</send_telegram>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
recipient = get_field(block, 'telegram_id') or get_field(block, 'to')
|
||||
message = get_field(block, 'message')
|
||||
if not recipient or not message:
|
||||
logger.warning("[AgentCmd] <send_telegram> ohne telegram_id/message ignoriert")
|
||||
continue
|
||||
action_id = create_task(
|
||||
title=f"Telegram an {recipient}: {message[:60]}",
|
||||
description=f"**An:** {recipient}\n\n{message}",
|
||||
agent_key=agent_key,
|
||||
task_type='action_telegram',
|
||||
created_by=agent_key,
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
|
||||
if TELEGRAM_CONFIG.get('bot_token') and TELEGRAM_CONFIG.get('telegram_bot'):
|
||||
if TELEGRAM_CONFIG.get('bot_token'):
|
||||
try:
|
||||
chat_id = None
|
||||
if recipient_clean.lstrip('-').isdigit():
|
||||
chat_id = int(recipient_clean)
|
||||
else:
|
||||
chat_id = int(recipient) if recipient.lstrip('-').isdigit() else None
|
||||
if not chat_id:
|
||||
con = sqlite3.connect(EMAIL_JOURNAL_DB)
|
||||
result = con.execute(
|
||||
"SELECT telegram_id FROM team_members WHERE name = ? OR email = ?",
|
||||
(recipient_clean, recipient_clean)
|
||||
row = con.execute(
|
||||
"SELECT telegram_id FROM team_members WHERE name=? OR email=?",
|
||||
(recipient, recipient)
|
||||
).fetchone()
|
||||
con.close()
|
||||
if result and result[0]:
|
||||
chat_id = int(result[0])
|
||||
|
||||
if row and row[0]:
|
||||
chat_id = int(row[0])
|
||||
if chat_id:
|
||||
send_telegram_message(chat_id, message_clean)
|
||||
update_task_db(action_task_id, status='completed',
|
||||
response=f"✓ Telegram gesendet an {recipient_clean} (chat_id={chat_id})")
|
||||
logger.info(f"[AgentCmd] Telegram gesendet an {recipient_clean} (chat_id={chat_id})")
|
||||
send_telegram_message(chat_id, message)
|
||||
update_task_db(action_id, status='completed', response=f"✓ Telegram gesendet (chat_id={chat_id})")
|
||||
logger.info(f"[AgentCmd] Telegram gesendet an {recipient} (chat_id={chat_id})")
|
||||
else:
|
||||
update_task_db(action_task_id, status='error',
|
||||
response=f"✗ Keine Telegram-ID für '{recipient_clean}' gefunden")
|
||||
logger.warning(f"[AgentCmd] Keine Telegram Chat-ID für '{recipient_clean}'")
|
||||
update_task_db(action_id, status='error', response=f"✗ Keine Telegram-ID für '{recipient}'")
|
||||
logger.warning(f"[AgentCmd] Keine Telegram-ID für '{recipient}'")
|
||||
except Exception as e:
|
||||
update_task_db(action_task_id, status='error', response=f"✗ Fehler: {str(e)}")
|
||||
logger.error(f"[AgentCmd] Telegram-Fehler: {str(e)}")
|
||||
update_task_db(action_id, status='error', response=f"✗ {e}")
|
||||
logger.error(f"[AgentCmd] Telegram-Fehler: {e}")
|
||||
else:
|
||||
update_task_db(action_task_id, status='error', response="✗ Telegram nicht konfiguriert")
|
||||
logger.warning("[AgentCmd] Telegram nicht konfiguriert")
|
||||
update_task_db(action_id, status='error', response="✗ Telegram nicht konfiguriert")
|
||||
|
||||
# ADD_TEAM_MEMBER: Füge neues Team-Mitglied hinzu
|
||||
# Format: Name / Role / Responsibilities / Email (Reihenfolge wie im System-Prompt)
|
||||
add_member_requests = re.findall(
|
||||
r'@ADD_TEAM_MEMBER\s*\nName:\s*([^\n]+)\s*\nRole:\s*([^\n]+)\s*\nResponsibilities:\s*([^\n]+)\s*\nEmail:\s*(.*?)@END',
|
||||
response_text,
|
||||
re.DOTALL
|
||||
# ── ADD_TEAM_MEMBER ──────────────────────────────────────────────────────
|
||||
for block in re.findall(r'<add_team_member>(.*?)</add_team_member>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
name = get_field(block, 'name')
|
||||
role = get_field(block, 'role')
|
||||
resp = get_field(block, 'responsibilities')
|
||||
email = get_field(block, 'email')
|
||||
if not name or not role:
|
||||
continue
|
||||
action_id = create_task(
|
||||
title=f"Team-Member hinzugefügt: {name}",
|
||||
description=f"**Name:** {name}\n**Rolle:** {role}\n**Email:** {email}\n**Verantwortlichkeiten:** {resp}",
|
||||
agent_key=agent_key, task_type='action_team', created_by=agent_key, parent_task_id=task_id,
|
||||
)
|
||||
for name, role, resp, email in add_member_requests:
|
||||
name_clean = name.strip()
|
||||
role_clean = role.strip()
|
||||
resp_clean = resp.strip()
|
||||
email_clean = email.strip()
|
||||
success = add_team_member(name, role, resp, email)
|
||||
status_msg = f"✓ '{name}' hinzugefügt" if success else f"✗ Fehler beim Hinzufügen von '{name}'"
|
||||
update_task_db(action_id, status='completed' if success else 'error', response=status_msg)
|
||||
logger.info(f"[AgentCmd] {status_msg}")
|
||||
|
||||
action_task_id = create_task(
|
||||
title=f"Team-Member hinzugefügt: {name_clean}",
|
||||
description=f"**Name:** {name_clean}\n**Rolle:** {role_clean}\n**Email:** {email_clean}\n**Verantwortlichkeiten:** {resp_clean}",
|
||||
agent_key=agent_key,
|
||||
task_type='action_team',
|
||||
created_by=agent_key,
|
||||
parent_task_id=task_id,
|
||||
)
|
||||
success = add_team_member(name_clean, role_clean, resp_clean, email_clean)
|
||||
if success:
|
||||
update_task_db(action_task_id, status='completed',
|
||||
response=f"✓ Team-Member '{name_clean}' ({role_clean}) hinzugefügt")
|
||||
logger.info(f"[AgentCmd] Team-Member hinzugefügt: {name_clean} ({role_clean})")
|
||||
else:
|
||||
update_task_db(action_task_id, status='error',
|
||||
response=f"✗ Konnte '{name_clean}' nicht hinzufügen")
|
||||
logger.warning(f"[AgentCmd] Team-Member konnte nicht hinzugefügt werden: {name_clean}")
|
||||
|
||||
# UPDATE_TEAM_MEMBER: Aktualisiere Team-Mitglied
|
||||
# Format: @UPDATE_TEAM_MEMBER\nIdentifier: <email oder name>\n[Feld: Wert]\n...\n@END
|
||||
ALLOWED_UPDATE_FIELDS = {
|
||||
'name': 'name',
|
||||
'role': 'role',
|
||||
'responsibilities': 'responsibilities',
|
||||
'email': 'email',
|
||||
'telegramid': 'telegram_id',
|
||||
'telegram_id': 'telegram_id',
|
||||
'phone': 'phone',
|
||||
}
|
||||
for block in re.findall(r'@UPDATE_TEAM_MEMBER\s*\n(.*?)@END', response_text, re.DOTALL):
|
||||
lines = [l.strip() for l in block.strip().splitlines() if l.strip()]
|
||||
identifier = None
|
||||
# ── UPDATE_TEAM_MEMBER ───────────────────────────────────────────────────
|
||||
ALLOWED_UPDATE_FIELDS = {'name','role','responsibilities','email','telegram_id','telegramid','phone'}
|
||||
for block in re.findall(r'<update_team_member>(.*?)</update_team_member>', response_text, re.DOTALL | re.IGNORECASE):
|
||||
identifier = get_field(block, 'identifier')
|
||||
if not identifier:
|
||||
continue
|
||||
kwargs = {}
|
||||
for line in lines:
|
||||
for line in block.strip().splitlines():
|
||||
if ':' not in line:
|
||||
continue
|
||||
key, _, val = line.partition(':')
|
||||
key_norm = key.strip().lower().replace(' ', '_')
|
||||
val_clean = val.strip()
|
||||
if key_norm == 'identifier':
|
||||
identifier = val_clean
|
||||
elif key_norm in ALLOWED_UPDATE_FIELDS:
|
||||
kwargs[ALLOWED_UPDATE_FIELDS[key_norm]] = val_clean
|
||||
if not identifier:
|
||||
logger.warning("[AgentCmd] @UPDATE_TEAM_MEMBER ohne Identifier ignoriert")
|
||||
continue
|
||||
k, _, v = line.partition(':')
|
||||
k_norm = k.strip().lower().replace(' ', '_')
|
||||
if k_norm in ALLOWED_UPDATE_FIELDS and k_norm != 'identifier':
|
||||
db_key = 'telegram_id' if k_norm == 'telegramid' else k_norm
|
||||
kwargs[db_key] = v.strip()
|
||||
if not kwargs:
|
||||
logger.warning(f"[AgentCmd] @UPDATE_TEAM_MEMBER für '{identifier}' ohne Felder ignoriert")
|
||||
continue
|
||||
fields_summary = ", ".join(f"{k}={v}" for k, v in kwargs.items())
|
||||
action_task_id = create_task(
|
||||
fields_str = ', '.join(f"{k}={v}" for k, v in kwargs.items())
|
||||
action_id = create_task(
|
||||
title=f"Team-Member aktualisiert: {identifier}",
|
||||
description=f"**Identifier:** {identifier}\n**Felder:** {fields_summary}",
|
||||
agent_key=agent_key,
|
||||
task_type='action_team',
|
||||
created_by=agent_key,
|
||||
parent_task_id=task_id,
|
||||
description=f"**Identifier:** {identifier}\n**Felder:** {fields_str}",
|
||||
agent_key=agent_key, task_type='action_team', created_by=agent_key, parent_task_id=task_id,
|
||||
)
|
||||
success = update_team_member(identifier, **kwargs)
|
||||
if success:
|
||||
update_task_db(action_task_id, status='completed',
|
||||
response=f"✓ {identifier} aktualisiert: {fields_summary}")
|
||||
logger.info(f"[AgentCmd] Team-Member aktualisiert: {identifier} - {list(kwargs.keys())}")
|
||||
else:
|
||||
update_task_db(action_task_id, status='error',
|
||||
response=f"✗ Update fehlgeschlagen für '{identifier}'")
|
||||
logger.error(f"[AgentCmd] Update fehlgeschlagen für '{identifier}'")
|
||||
status_msg = f"✓ {identifier} aktualisiert: {fields_str}" if success else f"✗ Update fehlgeschlagen für '{identifier}'"
|
||||
update_task_db(action_id, status='completed' if success else 'error', response=status_msg)
|
||||
logger.info(f"[AgentCmd] {status_msg}")
|
||||
|
||||
def create_new_agent(agent_key, role, skills):
|
||||
"""Erstellt dynamisch einen neuen Agenten."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue