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

# Loop dell'agente

> Descrive come la Copilot CLI gestisce il ciclo dalla ricezione del prompt fino a session.idle.

## Loop dell'agente

Descrive come la Copilot CLI elabora end-to-end i messaggi dell'utente (dall'invio del prompt fino a `session.idle`).

## Architettura

```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
```

L'**SDK** è il livello di trasporto. Invia i prompt alla **Copilot CLI** tramite JSON-RPC e inoltra gli eventi all'applicazione. È la **CLI** a eseguire il loop di utilizzo degli strumenti in modo agentico, orchestrando una o più chiamate API all'LLM fino al completamento del task.

## Loop di utilizzo degli strumenti

Quando chiami `session.send({ prompt })`, la CLI entra nel seguente loop.

```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
```

A ogni chiamata il modello fa riferimento all'**intera cronologia della conversazione** (system prompt / user message / tutte le chiamate a strumenti e i relativi risultati fino a quel momento).

**Importante:** una iterazione di questo loop corrisponde esattamente a una chiamata API all'LLM e, nel log degli eventi, appare come una coppia `assistant.turn_start` / `assistant.turn_end`. Non ci sono chiamate nascoste.

## Cos'è un turn

Un **turn** è una singola chiamata API all'LLM e il suo risultato.

1. La CLI invia la cronologia della conversazione all'LLM
2. L'LLM risponde (eventualmente includendo richieste di strumenti)
3. Se ci sono richieste di strumenti, la CLI le esegue
4. Viene emesso `assistant.turn_end`

Un singolo messaggio dell'utente genera solitamente **più turn**. Ad esempio, per una domanda come "Come funziona X in questa codebase?" si ha qualcosa di simile.

| Turn | Comportamento del modello                               | toolRequests?    |
| ---- | ------------------------------------------------------- | ---------------- |
| 1    | Cerca nella codebase con `grep` e `glob`                | ✅ Sì             |
| 2    | Legge file specifici in base ai risultati della ricerca | ✅ Sì             |
| 3    | Legge ulteriori file per un contesto più approfondito   | ✅ Sì             |
| 4    | Genera la risposta testuale finale                      | ❌ No → loop ends |

A ogni turn il modello decide se "continuare a usare strumenti" o "passare alla risposta finale". Poiché ogni chiamata può vedere **tutto il contesto accumulato** (incluse le chiamate a strumenti passate e i loro risultati), può giudicare se le informazioni sono sufficienti.

## Flusso di eventi in caso di più turn

```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
```

## Chi avvia ciascun turn

| Attore          | Responsabilità                                                                                              |
| --------------- | ----------------------------------------------------------------------------------------------------------- |
| **La tua app**  | Invia il primo prompt con `session.send()`                                                                  |
| **Copilot CLI** | Esegue il loop di utilizzo degli strumenti e restituisce all'LLM i risultati come input del turn successivo |
| **LLM**         | Decide se richiedere altri strumenti e proseguire, oppure restituire la risposta finale e terminare         |
| **SDK**         | Si limita a inoltrare gli eventi. Non controlla il loop                                                     |

Il comportamento della CLI è meccanico ("il modello richiede uno strumento → esegue → richiama il modello"). Chi decide la condizione di arresto è il **modello**.

## Differenza tra `session.idle` e `session.task_complete`

Entrambi sono segnali di completamento, ma offrono garanzie molto diverse.

### `session.idle`

* **Sempre emesso** al termine del loop di utilizzo degli strumenti
* **Effimero (ephemeral)**. Non viene persistito su disco e non viene riprodotto alla ripresa della sessione
* Significato: "l'agente ha smesso di elaborare ed è pronto ad accettare il prossimo messaggio"
* Da usare come segnale affidabile di "completato"

Il metodo `sendAndWait()` dell'SDK attende questo evento.

```typescript theme={null}
// Attende finché non viene emesso session.idle
const response = await session.sendAndWait({ prompt: "Fix the bug" });
```

### `session.task_complete`

* **Emissione facoltativa** (solo se il modello lo segnala esplicitamente)
* **Persistito** (salvato nel log degli eventi della sessione)
* Significato: "l'agente stesso ha giudicato completato l'intero task"
* Può includere un `summary` opzionale

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

### Modalità autopilot: la CLI sollecita `task_complete`

In **modalità autopilot** (headless / autonoma), la CLI tiene traccia di se il modello ha chiamato `task_complete`. Se il loop di utilizzo degli strumenti termina senza `task_complete`, la CLI inserisce il seguente messaggio utente sintetico per sollecitare il modello.

> *"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."*

Questo di fatto riavvia il loop di utilizzo degli strumenti. Il modello riceve la sollecitazione come nuovo messaggio dell'utente e prosegue il lavoro. La sollecitazione include anche l'indicazione di "non chiamare `task_complete` troppo presto".

* Non chiamarlo se restano domande aperte. Decidi e continua a lavorare
* Non chiamarlo se hai appena incontrato un errore. Prova a risolverlo
* Non chiamarlo se ci sono task residui. Completali prima

In autopilot si ottiene quindi il seguente **meccanismo di completamento in due fasi**.

1. Il modello chiama `task_complete` con un summary → la CLI emette `session.task_complete` → completato
2. Il modello si ferma senza chiamarlo → la CLI sollecita → il modello prosegue oppure chiama `task_complete`

### Perché `task_complete` potrebbe non essere emesso

In **modalità interattiva** (chat normale), la CLI non sollecita `task_complete`. Il modello può ometterlo. I motivi principali sono i seguenti.

* **Q\&A conversazionale**: risponde alla domanda e termina, senza un "task completato" discreto
* **Decisione del modello**: restituisce il testo finale senza chiamare `task_complete`
* **Sessione interrotta**: la sessione termina prima che il modello raggiunga un punto di completamento

La CLI emette invece sempre `session.idle`. Questo perché non è un segnale semantico (il modello ha giudicato completato) ma un segnale meccanico (il loop è terminato).

### Quale usare

| Caso d'uso                                        | Segnale                               |
| ------------------------------------------------- | ------------------------------------- |
| "Attendere la fine dell'elaborazione dell'agente" | `session.idle` ✅                      |
| "Sapere che il task di coding è stato completato" | `session.task_complete` (best-effort) |
| "Gestione di timeout/errori"                      | `session.idle` + `session.error` ✅    |

## Contare il numero di chiamate all'LLM

Il numero di coppie `assistant.turn_start` / `assistant.turn_end` nel log degli eventi coincide con il numero totale di chiamate API all'LLM. Non ci sono chiamate nascoste per pianificazione, valutazione o conferma del completamento.

Esempio di verifica del numero di turn di una sessione:

```bash theme={null}
# Conta i turn nel log eventi della sessione
grep -c "assistant.turn_start" ~/.copilot/session-state/<sessionId>/events.jsonl
```

## Documenti correlati

* [Eventi di streaming](/it/packages/laravel-copilot-sdk/streaming-events) — riferimento a livello di campo per ciascun tipo di evento
* [Ripresa della sessione](/it/packages/laravel-copilot-sdk/resume) — salvataggio e ripresa della sessione
* [Hook di sessione](/it/packages/laravel-copilot-sdk/hooks) — intercettare eventi all'interno del loop (permessi · strumenti)


## Related topics

- [Introduzione a Laravel Nightwatch](/it/blog/nightwatch-introduction.md)
- [Creare un agente personalizzato per Boost](/it/advanced/boost-custom-agent.md)
- [Template Blade](/it/blade.md)
- [Creare un provider personalizzato per l'AI SDK](/it/advanced/ai-sdk-custom-provider.md)
- [laravel/agent-skills — la raccolta ufficiale di skill per agenti AI di Laravel](/it/blog/agent-skills-introduction.md)
