> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent-Loop

> Beschreibt, wie die Copilot CLI den Ablauf vom Empfang eines Prompts bis zu session.idle verarbeitet.

## Agent-Loop

Hier wird beschrieben, wie die Copilot CLI eine Benutzernachricht Ende-zu-Ende verarbeitet (vom Senden des Prompts bis `session.idle`).

## Architektur

```mermaid theme={null}
graph LR
    App["Your App"] -->|send prompt| SDK["SDK Session"]
    SDK -->|JSON-RPC| CLI["Copilot CLI"]
    CLI -->|API calls| LLM["LLM"]
    LLM -->|response| CLI
    CLI -->|events| SDK
    SDK -->|events| App
```

Das **SDK** ist die Transportschicht. Es sendet Prompts per JSON-RPC an die **Copilot CLI** und leitet Ereignisse an die Anwendung weiter. Die agentische Tool-Nutzungsschleife und die Orchestrierung eines oder mehrerer LLM-API-Aufrufe bis zum Abschluss der Aufgabe werden auf Seiten der **CLI** ausgeführt.

## Tool-Nutzungsschleife

Wenn Sie `session.send({ prompt })` aufrufen, tritt die CLI in die folgende Schleife ein.

```mermaid theme={null}
flowchart TD
    A["User prompt"] --> B["LLM API call<br>(= one turn)"]
    B --> C{"toolRequests<br>in response?"}
    C -->|Yes| D["Execute tools<br>Collect results"]
    D -->|"Results fed back<br>as next turn input"| B
    C -->|No| E["Final text<br>response"]
    E --> F(["session.idle"])

    style B fill:#1a1a2e,stroke:#58a6ff,color:#c9d1d9
    style D fill:#1a1a2e,stroke:#3fb950,color:#c9d1d9
    style F fill:#0d1117,stroke:#f0883e,color:#f0883e
```

Das Modell berücksichtigt bei jedem Aufruf den **gesamten Konversationsverlauf** (System-Prompt / User-Message / alle bisherigen Tool-Aufrufe und Ergebnisse).

**Wichtig:** Eine Iteration dieser Schleife entspricht exakt einem LLM-API-Aufruf und ist im Ereignis-Log als ein Paar `assistant.turn_start` / `assistant.turn_end` sichtbar. Es gibt keine versteckten Aufrufe.

## Was ist ein Turn?

Ein **Turn** ist ein einzelner LLM-API-Aufruf und dessen Ergebnis.

1. Die CLI sendet den Konversationsverlauf an das LLM
2. Das LLM antwortet (ggf. mit Tool-Anfragen)
3. Falls Tool-Anfragen vorliegen, führt die CLI sie aus
4. `assistant.turn_end` wird ausgelöst

Aus einer einzigen Benutzernachricht ergeben sich üblicherweise **mehrere Turns**. Bei einer Frage wie „Wie funktioniert X in diesem Codebase?" könnte es beispielsweise so aussehen:

| Turn | Verhalten des Modells                                | toolRequests?    |
| ---- | ---------------------------------------------------- | ---------------- |
| 1    | Codebase mit `grep` und `glob` durchsuchen           | ✅ Yes            |
| 2    | Auf Basis der Suchergebnisse bestimmte Dateien lesen | ✅ Yes            |
| 3    | Für tieferen Kontext weitere Dateien lesen           | ✅ Yes            |
| 4    | Endgültige Textantwort erzeugen                      | ❌ No → loop ends |

In jedem Turn entscheidet das Modell, ob es „weitere Tools nutzt" oder „zur endgültigen Antwort übergeht". Da jeder Aufruf den **gesamten akkumulierten Kontext** (einschließlich vergangener Tool-Aufrufe und deren Ergebnisse) sieht, kann es beurteilen, ob genügend Informationen vorliegen.

## Ereignisfluss bei mehreren Turns

```mermaid theme={null}
flowchart TD
    send["session.send({ prompt: &quot;Fix the bug in auth.ts&quot; })"]

    subgraph Turn1 ["Turn 1"]
        t1s["assistant.turn_start"]
        t1m["assistant.message (toolRequests)"]
        t1ts["tool.execution_start (read_file)"]
        t1tc["tool.execution_complete"]
        t1e["assistant.turn_end"]
        t1s --> t1m --> t1ts --> t1tc --> t1e
    end

    subgraph Turn2 ["Turn 2 — auto-triggered by CLI"]
        t2s["assistant.turn_start"]
        t2m["assistant.message (toolRequests)"]
        t2ts["tool.execution_start (edit_file)"]
        t2tc["tool.execution_complete"]
        t2e["assistant.turn_end"]
        t2s --> t2m --> t2ts --> t2tc --> t2e
    end

    subgraph Turn3 ["Turn 3"]
        t3s["assistant.turn_start"]
        t3m["assistant.message (no toolRequests)<br>&quot;Done, here's what I changed&quot;"]
        t3e["assistant.turn_end"]
        t3s --> t3m --> t3e
    end

    idle(["session.idle — ready for next message"])

    send --> Turn1 --> Turn2 --> Turn3 --> idle
```

## Wer startet welchen Turn

| Actor           | Responsibility                                                                                                |
| --------------- | ------------------------------------------------------------------------------------------------------------- |
| **Your app**    | Sendet den initialen Prompt via `session.send()`                                                              |
| **Copilot CLI** | Führt die Tool-Nutzungsschleife aus und gibt Tool-Ergebnisse als Eingabe des nächsten Turns an das LLM zurück |
| **LLM**         | Entscheidet, ob es mit Tool-Anfragen fortfährt oder mit einer endgültigen Antwort abschließt                  |
| **SDK**         | Leitet nur Ereignisse weiter. Es steuert die Schleife nicht                                                   |

Das Verhalten der CLI ist mechanisch („Modell fordert Tool an → Ausführung → erneuter Modellaufruf"). Die Entscheidung über den Abbruch trifft das **Modell**.

## Unterschied zwischen `session.idle` und `session.task_complete`

Beide sind Abschlusssignale, ihre Garantien unterscheiden sich jedoch deutlich.

### `session.idle`

* Wird beim Beenden der Tool-Nutzungsschleife **immer ausgelöst**
* **Flüchtig (ephemeral)**. Wird nicht auf die Festplatte persistiert und beim Fortsetzen der Session nicht wiedergegeben
* Bedeutung: „Der Agent hat die Verarbeitung angehalten und kann die nächste Nachricht entgegennehmen"
* Verwenden Sie dieses Signal als zuverlässiges „Fertig"-Signal

`sendAndWait()` des SDK wartet auf dieses Ereignis.

```typescript theme={null}
// Warten, bis session.idle ausgelöst wird
const response = await session.sendAndWait({ prompt: "Fix the bug" });
```

### `session.task_complete`

* **Optional** (wird nur ausgelöst, wenn das Modell dies explizit signalisiert)
* **Persistiert** (wird im Session-Event-Log gespeichert)
* Bedeutung: „Der Agent selbst hat die Gesamtaufgabe als erledigt bewertet"
* Kann eine optionale `summary` enthalten

```typescript theme={null}
session.on("session.task_complete", (event) => {
    console.log("Task done:", event.data.summary);
});
```

### Autopilot-Modus: Die CLI drängt zu `task_complete`

Im **Autopilot-Modus** (headless / autonom) verfolgt die CLI, ob das Modell `task_complete` aufgerufen hat. Endet die Tool-Nutzungsschleife ohne `task_complete`, fügt die CLI die folgende synthetische Benutzernachricht ein, um das Modell dazu zu bewegen.

> *"You have not yet marked the task as complete using the task\_complete tool. If you were planning, stop planning and start implementing. You aren't done until you have fully completed the task."*

Dadurch wird die Tool-Nutzungsschleife praktisch wieder aufgenommen. Das Modell empfängt diese Aufforderung als neue Benutzernachricht und setzt die Arbeit fort. Die Aufforderung enthält auch den Hinweis, „`task_complete` nicht zu früh aufzurufen".

* Rufen Sie es nicht auf, wenn offene Fragen bestehen. Entscheiden Sie und setzen Sie die Arbeit fort
* Rufen Sie es nicht auf, wenn Sie lediglich auf einen Fehler gestoßen sind. Versuchen Sie, ihn zu lösen
* Rufen Sie es nicht auf, wenn noch Aufgaben ausstehen. Erledigen Sie diese zuerst

Im Autopilot-Modus ergibt sich daraus folgender **zweistufiger Abschlussmechanismus**:

1. Das Modell ruft `task_complete` mit Summary auf → Die CLI löst `session.task_complete` aus → Abschluss
2. Das Modell stoppt ohne Aufruf → Die CLI drängt → Das Modell setzt fort oder ruft `task_complete` auf

### Warum `task_complete` ausbleibt

Im **Interactive-Modus** (normaler Chat) drängt die CLI nicht zu `task_complete`. Das Modell kann es weglassen. Die Hauptgründe sind:

* **Konversationelle Q\&A**: Frage beantworten und beenden, ohne diskrete „erledigte Aufgabe"
* **Modellentscheidung**: Endgültigen Text zurückgeben, ohne `task_complete` aufzurufen
* **Unterbrochene Sessions**: Die Session endet, bevor das Modell einen Abschlusspunkt erreicht

Die CLI löst dagegen immer `session.idle` aus. Dies ist kein semantisches Signal (Modell bewertet als abgeschlossen), sondern ein mechanisches Signal (Schleife beendet).

### Welches sollten Sie verwenden?

| Use case                                             | Signal                                |
| ---------------------------------------------------- | ------------------------------------- |
| „Auf das Ende der Agent-Verarbeitung warten"         | `session.idle` ✅                      |
| „Wissen, dass eine Coding-Aufgabe abgeschlossen ist" | `session.task_complete` (best-effort) |
| „Timeout-/Fehlerbehandlung"                          | `session.idle` + `session.error` ✅    |

## Anzahl der LLM-Aufrufe zählen

Die Anzahl der Paare `assistant.turn_start` / `assistant.turn_end` im Event-Log stimmt mit der Gesamtzahl der LLM-API-Aufrufe überein. Es gibt keine versteckten Aufrufe für Planung, Bewertung oder Abschlussprüfung.

Beispiel zum Prüfen der Anzahl der Turns in einer Session:

```bash theme={null}
# Anzahl der Turns im Session-Event-Log zählen
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl
```

## Verwandte Dokumentation

* [Streaming-Ereignisse](/de/packages/laravel-copilot-sdk/streaming-events) — Feldreferenz für jeden Event-Typ
* [Session fortsetzen](/de/packages/laravel-copilot-sdk/resume) — Speichern und Fortsetzen von Sessions
* [Session-Hooks](/de/packages/laravel-copilot-sdk/hooks) — Abfangen von Ereignissen innerhalb der Schleife (Berechtigungen, Tools)


## Related topics

- [Einen eigenen Provider für das AI SDK erstellen](/de/advanced/ai-sdk-custom-provider.md)
- [Blade-Templates](/de/blade.md)
- [Laravel Reverb](/de/reverb.md)
- [Laravel-Updates Mai 2026](/de/blog/changelog/202605.md)
- [laravel/agent-skills – Offizielle KI-Agent-Skills-Sammlung von Laravel](/de/blog/agent-skills-introduction.md)
