Sub-Agents

Sub-Agents sind Hintergrund-Agent-Läufe, die von einem bestehenden Agent-Lauf gestartet werden. Sie laufen in ihrer eigenen Session (agent:<agentId>:subagent:<uuid>) und melden ihr Ergebnis zurück an den Chat-Channel des Anforderers, sobald sie fertig sind.

Slash-Befehl

Mit /subagents kannst du Sub-Agent-Läufe für die aktuelle Session inspizieren oder steuern:

  • /subagents list
  • /subagents stop <id|#|all>
  • /subagents log <id|#> [limit] [tools]
  • /subagents info <id|#>
  • /subagents send <id|#> <message>

/subagents info zeigt Run-Metadaten (Status, Zeitstempel, Session-ID, Transkript-Pfad, Cleanup).

Hauptziele:

  • “Research / lange Tasks / langsame Tools” parallelisieren, ohne den Haupt-Lauf zu blockieren.
  • Sub-Agents standardmäßig isoliert halten (Session-Trennung + optionales Sandboxing).
  • Die Tool-Oberfläche schwer missbrauchbar machen: Sub-Agents bekommen standardmäßig keine Session-Tools.
  • Verschachtelte Fan-Outs vermeiden: Sub-Agents können keine Sub-Agents starten.

Kosten-Hinweis: Jeder Sub-Agent hat seinen eigenen Context und Token-Verbrauch. Bei aufwändigen oder sich wiederholenden Tasks solltest du ein günstigeres Modell für Sub-Agents setzen und deinen Haupt-Agent auf einem hochwertigeren Modell lassen. Du kannst das über agents.defaults.subagents.model oder per-Agent-Overrides konfigurieren.

Tool

Verwende sessions_spawn:

  • Startet einen Sub-Agent-Lauf (deliver: false, globale Lane: subagent)
  • Führt dann einen Announce-Step aus und postet die Announce-Antwort an den Chat-Channel des Anforderers
  • Standard-Modell: erbt vom Aufrufer, außer du setzt agents.defaults.subagents.model (oder per-Agent agents.list[].subagents.model); ein explizites sessions_spawn.model gewinnt trotzdem.

Tool-Parameter:

  • task (erforderlich)
  • label? (optional)
  • agentId? (optional; startet unter einer anderen Agent-ID, falls erlaubt)
  • model? (optional; überschreibt das Sub-Agent-Modell; ungültige Werte werden übersprungen und der Sub-Agent läuft mit dem Standard-Modell mit einer Warnung im Tool-Result)
  • thinking? (optional; überschreibt das Thinking-Level für den Sub-Agent-Lauf)
  • runTimeoutSeconds? (Standard 0; wenn gesetzt, wird der Sub-Agent-Lauf nach N Sekunden abgebrochen)
  • cleanup? (delete|keep, Standard keep)

Allowlist:

  • agents.list[].subagents.allowAgents: Liste von Agent-IDs, die über agentId angesprochen werden können (["*"] erlaubt alle). Standard: nur der anfordernde Agent.

Discovery:

  • Verwende agents_list, um zu sehen, welche Agent-IDs aktuell für sessions_spawn erlaubt sind.

Auto-Archivierung:

  • Sub-Agent-Sessions werden automatisch nach agents.defaults.subagents.archiveAfterMinutes archiviert (Standard: 60).
  • Die Archivierung nutzt sessions.delete und benennt das Transkript in *.deleted.<timestamp> um (gleicher Ordner).
  • cleanup: "delete" archiviert sofort nach dem Announce (behält das Transkript trotzdem via Umbenennung).
  • Auto-Archivierung ist Best-Effort; ausstehende Timer gehen verloren, wenn das Gateway neu startet.
  • runTimeoutSeconds archiviert nicht automatisch; es stoppt nur den Lauf. Die Session bleibt bis zur Auto-Archivierung bestehen.

Authentifizierung

Sub-Agent-Auth wird über die Agent-ID aufgelöst, nicht über den Session-Typ:

  • Der Sub-Agent-Session-Key ist agent:<agentId>:subagent:<uuid>.
  • Der Auth-Store wird aus dem agentDir dieses Agents geladen.
  • Die Auth-Profile des Haupt-Agents werden als Fallback zusammengeführt; Agent-Profile überschreiben Haupt-Profile bei Konflikten.

Hinweis: Das Merging ist additiv, sodass Haupt-Profile immer als Fallbacks verfügbar sind. Vollständig isolierte Auth pro Agent wird noch nicht unterstützt.

Announce

Sub-Agents melden sich über einen Announce-Step zurück:

  • Der Announce-Step läuft innerhalb der Sub-Agent-Session (nicht in der Anforderer-Session).
  • Wenn der Sub-Agent exakt ANNOUNCE_SKIP antwortet, wird nichts gepostet.
  • Andernfalls wird die Announce-Antwort über einen Follow-up-agent-Call (deliver=true) an den Chat-Channel des Anforderers gepostet.
  • Announce-Antworten behalten Thread/Topic-Routing bei, wenn verfügbar (Slack-Threads, Telegram-Topics, Matrix-Threads).
  • Announce-Nachrichten werden auf ein stabiles Template normalisiert:
    • Status: abgeleitet vom Run-Outcome (success, error, timeout oder unknown).
    • Result: der Summary-Content aus dem Announce-Step (oder (not available), falls fehlend).
    • Notes: Fehlerdetails und anderer nützlicher Kontext.
  • Status wird nicht aus der Modell-Ausgabe abgeleitet; er kommt von Runtime-Outcome-Signalen.

Announce-Payloads enthalten am Ende eine Stats-Zeile (auch wenn umgebrochen):

  • Runtime (z.B. runtime 5m12s)
  • Token-Verbrauch (Input/Output/Total)
  • Geschätzte Kosten, wenn Modell-Preise konfiguriert sind (models.providers.*.models[].cost)
  • sessionKey, sessionId und Transkript-Pfad (damit der Haupt-Agent die History via sessions_history abrufen oder die Datei auf der Disk inspizieren kann)

Tool-Policy (Sub-Agent-Tools)

Standardmäßig bekommen Sub-Agents alle Tools außer Session-Tools:

  • sessions_list
  • sessions_history
  • sessions_send
  • sessions_spawn

Override via Config:

{
  agents: {
    defaults: {
      subagents: {
        maxConcurrent: 1,
      },
    },
  },
  tools: {
    subagents: {
      tools: {
        // deny wins
        deny: ["gateway", "cron"],
        // if allow is set, it becomes allow-only (deny still wins)
        // allow: ["read", "exec", "process"]
      },
    },
  },
}

Concurrency

Sub-Agents nutzen eine dedizierte In-Process-Queue-Lane:

  • Lane-Name: subagent
  • Concurrency: agents.defaults.subagents.maxConcurrent (Standard 8)

Stoppen

  • Wenn du /stop im Anforderer-Chat sendest, wird die Anforderer-Session abgebrochen und alle aktiven Sub-Agent-Läufe, die von ihr gestartet wurden, werden gestoppt.

Einschränkungen

  • Sub-Agent-Announce ist Best-Effort. Wenn das Gateway neu startet, geht ausstehende “Announce-Back”-Arbeit verloren.
  • Sub-Agents teilen sich immer noch die gleichen Gateway-Prozess-Ressourcen; behandle maxConcurrent als Sicherheitsventil.
  • sessions_spawn ist immer non-blocking: Es gibt sofort { status: "accepted", runId, childSessionKey } zurück.
  • Sub-Agent-Context injiziert nur AGENTS.md + TOOLS.md (kein SOUL.md, IDENTITY.md, USER.md, HEARTBEAT.md oder BOOTSTRAP.md).