# Riferimento DSL

Complete reference for Goa-AI's DSL functions - agents, toolsets, policies, and MCP integration.

Source: https://goa.design/it/docs/2-goa-ai/dsl-reference/

Relative links resolve against the source URL above.


Questo documento fornisce un riferimento completo per le funzioni DSL di Goa-AI. Utilizzalo insieme alla guida [Runtime](./runtime.md) per comprendere in che modo i progetti si traducono in comportamento in fase di esecuzione.

## Riferimento rapido DSL


| Funzione | Contesto | Descrizione |
| ------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| **Funzioni dell'agente** |                          |                                                                                                                    |
| `Agent` | Servizio | Definisce un agente basato su LLM |
| `Completion` | Servizio | Dichiara contratto di proprietà di tipo assistente diretto-output |
| `Use` | Agente | Dichiara il consumo del set di strumenti |
| `Export` | Agente, Servizio | Espone i set di strumenti ad altri agenti |
| `AgentToolset` | Utilizzare l'argomento | Set di strumenti di riferimento da un altro agente |
| `Passthrough` | Strumento (in Esportazione) | Metodo di inoltro deterministico al servizio |
| `DisableAgentDocs` | API | Disabilita la generazione di AGENTS_QUICKSTART.md |
| **Funzioni del set di strumenti** |                          |                                                                                                                    |
| `Toolset` | Livello superiore | Dichiara un set di strumenti di proprietà del provider |
| `FromMCP` | Argomento del set di strumenti | Configura il set di strumenti supportato da MCP |
| `FromRegistry` | Argomento del set di strumenti | Configura il set di strumenti supportati dal registro |
| `Description` | Set di strumenti | Imposta la descrizione del set di strumenti |
| **Funzioni strumento** |                          |                                                                                                                    |
| `Tool` | Set di strumenti, Metodo | Definisce uno strumento richiamabile |
| `Args` | Strumento | Definisce lo schema dei parametri di input |
| `Return` | Strumento, Completamento | Definisce lo schema dei risultati visibili nel modello |
| `ServerData` | Strumento | Definisce lo schema dei dati solo del server (mai inviato ai fornitori di modelli) |
| `FromMethodResultField` | Dati server | Proietta i dati del server da un campo risultato del metodo di servizio associato |
| `AudienceTimeline` | Dati server | Contrassegna i dati del server come idonei per sequenza temporale/interfaccia utente (impostazione predefinita) |
| `AudienceInternal` | Dati server | Contrassegna i dati del server come allegato di composizione interna |
| `AudienceEvidence` | Dati server | Contrassegna i dati del server come provenienza o prova di controllo |
| `BoundedResult` | Strumento | Dichiara un contratto con risultati limitati di proprietà del runtime; il sub-DSL opzionale può dichiarare i campi del cursore di paging |
| `Cursor` | Risultato limitato | Dichiara quale campo del payload trasporta il cursore di paging (opzionale) |
| `ContinueWith` | Risultato limitato | Delega la paginazione meccanica a un'azione di continuazione correlata il cui cursore è associato dal runtime |
| `NextCursor` | Risultato limitato | Dichiara il nome del campo del risultato previsto per il cursore della pagina successiva (facoltativo) |
| `Tags` | Strumento, set di strumenti | Allega etichette di metadati |
| `Meta` | Strumento | Allega metadati di progettazione inerti e denominati, emessi in `ToolSpec.Meta` |
| `BindTo` | Strumento | Associa lo strumento al metodo del servizio |
| `Inject` | Strumento | Contrassegna i campi come inseriti dal runtime |
| `CallHintTemplate` | Strumento | Modello di visualizzazione per le invocazioni |
| `ResultHintTemplate` | Strumento | Modello di visualizzazione dei risultati |
| `ResultReminder` | Strumento | Promemoria di sistema statico dopo il risultato dello strumento |
| `Confirmation` | Strumento | Richiede una conferma esplicita fuori banda prima dell'esecuzione |
| `TerminalRun` | Strumento | Contrassegna il terminale dello strumento: l'esecuzione viene completata immediatamente dopo l'esecuzione (nessun turno di pianificazione successivo) |
| `Bookkeeping` | Strumento | Contrassegna lo strumento come contabilità: le chiamate non consumano il budget di recupero `MaxToolCalls` a livello di esecuzione e rimangono nascoste ai futuri turni di pianificazione per impostazione predefinita |
| **Funzioni politiche** |                          |                                                                                                                    |
| `RunPolicy` | Agente | Configura i vincoli di esecuzione |
| `DefaultCaps` | EseguiPolitica | Imposta i limiti delle risorse |
| `MaxToolCalls` | DefaultCaps | Numero massimo di invocazioni dello strumento |
| `MaxRecoveryTurns` | DefaultCaps | Numero massimo di nuove chiamate al pianificatore dopo un output rifiutato |
| `TimeBudget` | EseguiPolitica | Limite semplice dell'orologio da parete |
| `Timing` | EseguiPolitica | Configurazione dettagliata del timeout |
| `Budget` | Tempi | Budget di gestione complessivo |
| `Plan` | Tempi | Timeout attività pianificatore |
| `Tools` | Tempi | Timeout attività strumento |
| `History` | EseguiPolitica | Gestione della cronologia delle conversazioni |
| `KeepRecentTurns` | Storia | Politica della finestra scorrevole |
| `CompressAtTurns` | Storia | Trigger per riepilogo assistito dal modello basato sui turni |
| `CompressAtMaxInputTokens` | Storia | Trigger per riepilogo basato sui token di input contati a runtime |
| `KeepMaxTurns` | Storia | Limite di mantenimento esatto per turni completi recenti |
| `KeepMaxInputTokens` | Storia | Limite di mantenimento esatto per token, conservando solo turni completi |
| `Cache` | EseguiPolitica | Richiedi configurazione della memorizzazione nella cache |
| `AfterSystem` | Cache | Punto di controllo dopo i messaggi di sistema |
| `AfterTools` | Cache | Punto di controllo dopo le definizioni degli strumenti |
| `InterruptsAllowed` | EseguiPolitica | Abilita pausa/riprendi |
| `OnMissingFields` | EseguiPolitica | Comportamento di convalida |
| **Funzioni MCP** |                          |                                                                                                                    |
| `MCP` | Servizio | Abilita il supporto MCP |
| `ProtocolVersion` | Opzione MCP | Imposta la versione del protocollo MCP |
| `Tool` | Metodo | Contrassegna un metodo come strumento MCP in un servizio abilitato per MCP |
| `Toolset(FromMCP(...))` | Livello superiore | Dichiara un set di strumenti derivati ​​da MCP supportati da Goa |
| `Toolset("name", FromExternalMCP(...), func() { ... })` | Livello superiore | Dichiara un set di strumenti MCP esterno con schemi in linea |
| `Resource` | Metodo | Contrassegna il metodo come risorsa MCP |
| `StaticPrompt` | Servizio | Aggiunge il modello di prompt statico |
| **Funzioni di registro** |                          |                                                                                                                    |
| `Registry` | Livello superiore | Dichiara un'origine del registro |
| `URL` | Registro | Imposta l'endpoint del registro |
| `APIVersion` | Registro | Imposta la versione API |
| `Timeout` | Registro | Imposta il timeout HTTP |
| `Retry` | Registro | Configura la policy di ripetizione |
| `SyncInterval` | Registro | Imposta l'intervallo di aggiornamento del catalogo |
| `CacheTTL` | Registro | Imposta la durata della cache locale |
| `Federation` | Registro | Configura le importazioni del registro esterno |
| `Include` | Federazione | Modelli globali da importare |
| `Exclude` | Federazione | Modelli glob da saltare |
| `PublishTo` | Esporta | Configura la pubblicazione del registro |
| `Version` | Set di strumenti | Versione del set di strumenti del registro dei pin |
| **Funzioni dello schema** |                          |                                                                                                                    |
| `Attribute` | Argomenti, Ritorno, ServerData | Definisce il campo dello schema (uso generale) |
| `Field` | Argomenti, Ritorno, ServerData | Definisce il campo proto numerato (gRPC) |
| `Required` | Schema | Contrassegna i campi come obbligatori |
| `Example` | Schema | Allega un esempio esplicito; gli esempi di payload dello strumento di livello superiore vengono conservati nelle specifiche dello strumento generate e come prove strutturate per la correzione |

La tabella seguente precisa i contratti degli strumenti che influenzano il
controllo dell'esecuzione:

| Funzione | Contesto | Descrizione |
| --- | --- | --- |
| `Meta` | Strumento | Allega metadati di progettazione inerti e denominati, emessi in `ToolSpec.Meta` |
| `TerminalRun` | Strumento | Contrassegna lo strumento come terminale e di bookkeeping: il successo termina il run senza un turno successivo del planner |
| `Bookkeeping` | Strumento | Contrassegna un record di controllo: nessun budget di retrieval o di errori consecutivi, mentre chiamata e risultato esatti restano durevoli |

### DSL di valutazione

`goa.design/goa-ai/eval/dsl` aggiunge suite di valutazione al design Goa v3 di
un'applicazione. `Suite` dichiara una suite al livello superiore del design o
dentro `Agent`; `Scenario` dichiara un caso; `Input` dichiara il valore tipato
passato all'hook generato. `Description` e `Timeout` di Goa v3 insieme a
`Tags` di Goa-AI completano ogni caso. Il runner
gestisce la selezione di ID e tag, limita la concorrenza e verifica il giudice
semantico con quattro esempi prima di valutare le risposte. Consulta
[Valutazioni generate](evaluations/) per i contratti degli hook e di esecuzione.

### Esempi di payload degli strumenti

Per gli schemi dei payload degli strumenti, un `Example(...)` Goa di livello
superiore dichiarato è la fonte degli esempi di livello superiore esposti al
provider. Codegen conserva quell'esempio nella specifica generata come JSON
grezzo e come oggetto di input analizzato, ed emette anche lo schema annotato e
uno schema con solo l'`example` radice rimosso.

Gli adattatori dei provider usano direttamente queste proiezioni. I provider che
consumano annotazioni di schema usano il JSON Schema annotato. Anthropic diretto
e Bedrock Claude usano `input_examples` nativi con la proiezione senza esempio
radice; Bedrock trasmette i campi Anthropic tramite
`additionalModelRequestFields` quando lo richiede il contratto beta. Gli esempi
generati o sintetizzati non vengono mai promossi a esempi di provider di livello
superiore.


## Gestione dei prompt (percorso di integrazione v1)

Goa-AI v1 **non** richiede un prompt DSL dedicato (`Prompt(...)`, `Prompts(...)`).
La gestione dei prompt è attualmente guidata dal runtime:

- Registrare le specifiche del prompt di base in `runtime.PromptRegistry`.
- Configurare le sostituzioni con ambito con `runtime.WithPromptStore(...)`.
- Visualizzare le richieste dei pianificatori utilizzando `PlannerContext.RenderPrompt(...)`.
- Allegare la provenienza immediata resa alle chiamate del modello con `model.Request.PromptRefs`.

Per i flussi agente come strumento, associa gli ID strumento agli ID richiesta utilizzando opzioni di runtime come
`runtime.WithPromptSpec(...)` sulle registrazioni dello strumento agente.
Questo è facoltativo: quando non è configurato alcun contenuto del prompt lato consumatore, il runtime
utilizza il payload dello strumento JSON canonico come messaggio utente e provider nidificati
i pianificatori possono visualizzare i propri suggerimenti con il contesto lato server inserito.

### Campo vs Attributo

Sia `Field` che `Attribute` definiscono campi dello schema, ma hanno scopi diversi:

`**Attribute(name, type, description, dsl)`** - Definizione dello schema per scopi generali:

- Utilizzato per schemi solo JSON
- Nessuna numerazione dei campi richiesta
- Sintassi più semplice per la maggior parte dei casi d'uso

```go
Args(func() {
    Attribute("query", String, "Search query")
    Attribute("limit", Int, "Maximum results", func() {
        Default(10)
    })
    Required("query")
})
```

`**Field(number, name, type, description, dsl)**` - Campi numerati per gRPC/protobuf:

- Obbligatorio durante la generazione di servizi gRPC
- I numeri dei campi devono essere univoci e stabili
- Da utilizzare quando il servizio espone sia trasporti HTTP che gRPC

```go
Args(func() {
    Field(1, "query", String, "Search query")
    Field(2, "limit", Int, "Maximum results", func() {
        Default(10)
    })
    Required("query")
})
```

**Quando utilizzare quale:**

- Utilizzare `Attribute` per gli strumenti agente che utilizzano solo JSON (caso più comune)
- Utilizza `Field` quando il tuo servizio Goa ha il trasporto gRPC e gli strumenti si collegano a tali metodi
- La mescolanza è consentita ma non consigliata all'interno dello stesso schema

## Panoramica

Goa-AI estende il DSL di Goa con funzioni per la dichiarazione di agenti, set di strumenti e policy di runtime. Il DSL viene valutato dal motore `eval` di Goa, quindi si applicano le stesse regole del DSL di servizio/trasporto standard: le espressioni devono essere invocate nel contesto appropriato e le definizioni degli attributi riutilizzano il sistema di tipi di Goa (`Attribute`, `Field`, convalide, esempi, ecc.).

### Percorso di importazione

Aggiungi gli agenti DSL ai tuoi pacchetti di progettazione Goa:

```go
import (
    . "goa.design/goa/v3/dsl"
    . "goa.design/goa-ai/dsl"
)
```

### Punto di ingresso

Dichiarare gli agenti all'interno di una normale definizione Goa `Service`. Il DSL aumenta l'albero di progettazione di Goa e viene elaborato durante `goa gen`.

### Risultato

L'esecuzione di `goa gen` produce:

- Pacchetti agente (`gen/<service>/agents/<agent>`) con definizioni del flusso di lavoro, attività di pianificazione e assistenti per la registrazione
- Pacchetti di completamento di proprietà del servizio (`gen/<service>/completions`) quando il servizio dichiara `Completion(...)`
- Pacchetti proprietari del set di strumenti (`gen/<service>/toolset/<toolset>`) con strutture di payload/risultato digitate, specifiche, codec e (se applicabile) trasformazioni
- Gestori di attività per cicli di pianificazione/esecuzione/ripresa
- Aiutanti di registrazione che collegano il progetto al runtime

Un `AGENTS_QUICKSTART.md` contestuale viene scritto nella radice del modulo a meno che non sia disabilitato tramite `DisableAgentDocs()`.

### Esempio di avvio rapido

```go
package design

import (
    . "goa.design/goa/v3/dsl"
    . "goa.design/goa-ai/dsl"
)

var DocsToolset = Toolset("docs.search", func() {
    Tool("search", "Search indexed documentation", func() {
        Args(func() {
            Attribute("query", String, "Search phrase")
            Attribute("limit", Int, "Max results", func() { Default(5) })
            Required("query")
        })
        Return(func() {
            Attribute("documents", ArrayOf(String), "Matched snippets")
            Required("documents")
        })
        Tags("docs", "search")
    })
})

var AssistantSuite = Toolset(FromMCP("assistant", "assistant-mcp"))

var _ = Service("orchestrator", func() {
    Description("Human front door for the knowledge agent.")

    Agent("chat", "Conversational runner", func() {
        Use(DocsToolset)
        Use(AssistantSuite)
        Export("chat.tools", func() {
            Tool("summarize_status", "Produce operator-ready summaries", func() {
                Args(func() {
                    Attribute("prompt", String, "User instructions")
                    Required("prompt")
                })
                Return(func() {
                    Attribute("summary", String, "Assistant response")
                    Required("summary")
                })
                Tags("chat")
            })
        })
        RunPolicy(func() {
            DefaultCaps(
                MaxToolCalls(8),
                MaxRecoveryTurns(3),
            )
            TimeBudget("2m")
        })
    })
})
```

L'esecuzione di `goa gen example.com/assistant/design` produce:

- `gen/orchestrator/agents/chat`: flusso di lavoro + attività pianificatore + anagrafica agenti
- `gen/orchestrator/agents/chat/specs`: catalogo strumenti agente (aggregato `ToolSpec`s + `tool_schemas.json`)
- `gen/orchestrator/toolset/<toolset>`: tipi/specifiche/codec/trasformazioni di proprietà del set di strumenti per set di strumenti di proprietà del servizio
- `gen/orchestrator/agents/chat/exports/<export>`: pacchetti di set di strumenti esportati (agente come strumento).
- Supporti di registrazione compatibili con MCP quando si fa riferimento a un set di strumenti supportato da MCP tramite `Use`

### Identificatori degli strumenti digitati

Ogni pacchetto di specifiche per set di strumenti definisce gli identificatori dello strumento tipizzati (`tools.Ident`) per ogni strumento generato:

```go
const (
    Search tools.Ident = "orchestrator.search.search"
)

var Specs = []tools.ToolSpec{
    { Name: Search, /* ... */ },
}
```

Utilizza queste costanti ovunque sia necessario fare riferimento agli strumenti.

### Completamenti tipizzati di proprietà del servizio

Gli strumenti non sono l’unico contratto strutturato che Goa-AI può possedere. Utilizzare
`Completion(...)` quando l'assistente deve restituire direttamente una risposta finale digitata
invece di emettere una chiamata allo strumento:

```go
var Draft = Type("Draft", func() {
    Attribute("name", String, "Task name")
    Attribute("goal", String, "Outcome-style goal")
    Required("name", "goal")
})

var _ = Service("tasks", func() {
    Completion("draft_from_transcript", "Produce a task draft directly", func() {
        Return(Draft)
    })
})
```

I nomi di completamento fanno parte del contratto di output strutturato. Devono esserlo
Da 1 a 64 caratteri ASCII, possono contenere lettere, cifre, `_` e `-` e devono
iniziare con una lettera o una cifra.

`goa gen` emette un package sotto `gen/<service>/completions` con:

- tipi di risultato e unione tipizzati;
- schemi privati e codec generati;
- helper `Complete<Name>(ctx, client, req)`;
- helper tipizzati `StreamComplete<Name>(ctx, client, req)`;
- `<Name>Example()` quando il risultato radice ha un `Example(...)` dichiarato.

Gli helper unary decodificano direttamente la risposta finale. Gli helper di
streaming restituiscono `completion.Streamer[T]`: `Recv` espone frammenti
`completion_delta` validi solo come anteprima, mentre `Value()` resta
indisponibile fino alla chiusura pulita dello stream e alla validazione della
risposta terminale. Non esiste un decoder pubblico per chunk non verificati.

Gli aiutanti di completamento generati rifiutano le richieste abilitate allo strumento e fornite dal chiamante
`StructuredOutput`. I provider che non implementano l'output strutturato falliscono
esplicitamente con `model.ErrStructuredOutputUnsupported`.
Un output non conforme al codec generato restituisce
`planner.OutputContractError` e una risposta nil; non avvia una richiesta di
correzione.
Lo schema generato rimane il contratto di servizio canonico; gli adattatori del modello possono
normalizzarlo per la decodifica vincolata specifica del provider, ma devono rifiutarlo
fornitori che non possono rappresentare il contratto dichiarato.

### Composizione in linea tra processi

Quando l'agente A dichiara di "utilizzare" un set di strumenti esportato dall'agente B, Goa-AI collega automaticamente la composizione:

- Il pacchetto esportatore (agente B) include gli helper `agenttools` generati
- Il registro degli agenti consumer (agente A) utilizza questi helper quando si utilizza `Use(AgentToolset("service", "agent", "toolset"))`
- La funzione `Execute` generata crea messaggi di pianificazione nidificati, esegue l'agente del provider come flusso di lavoro figlio e adatta `RunOutput` dell'agente nidificato in un `planner.ToolResult`

Ciò produce un singolo flusso di lavoro deterministico per esecuzione dell'agente e un albero di esecuzione collegato per la composizione.

---

## Funzioni dell'agente

### Agente

`Agent(name, description, dsl)` dichiara un agente all'interno di un `Service`. Registra i metadati dell'agente con ambito servizio e collega i set di strumenti tramite `Use` e `Export`.

**Contesto**: All'interno di `Service`

Ogni agente diventa una registrazione runtime con:

- Una definizione del flusso di lavoro e gestori di attività temporali
- Attività PlanStart/PlanResume con opzioni di ripetizione/timeout derivate da DSL
- Un helper `Register<Agent>` che registra flussi di lavoro, attività e set di strumenti

```go
var _ = Service("orchestrator", func() {
    Agent("chat", "Conversational runner", func() {
        Use(DocsToolset)
        Export("chat.tools", func() {
            // tools defined here
        })
        RunPolicy(func() {
            DefaultCaps(MaxToolCalls(8))
            TimeBudget("2m")
        })
    })
})
```

### Utilizzo

`Use(value, dsl)` dichiara che un agente utilizza un set di strumenti. Il set di strumenti può essere:

- Una variabile `Toolset` di livello superiore
- Un set di strumenti dichiarato con `FromMCP(...)` o `FromExternalMCP(...)`
- Una definizione del set di strumenti in linea (nome stringa + DSL)
- Un riferimento `AgentToolset` per la composizione agente come strumento

**Contesto**: All'interno di `Agent`

```go
Agent("chat", "Conversational runner", func() {
    // Reference a top-level toolset
    Use(DocsToolset)
    
    // Reference with subsetting
    Use(CommonTools, func() {
        Tool("notify") // consume only this tool from CommonTools
    })
    
    // Reference an MCP toolset declared at top level
    Use(AssistantSuite)
    
    // Inline agent-local toolset definition
    Use("helpers", func() {
        Tool("answer", "Answer a question", func() {
            // tool definition
        })
    })
    
    // Agent-as-tool composition
    Use(AgentToolset("service", "agent", "toolset"))
})
```

### Esporta

`Export(value, dsl)` dichiara i set di strumenti esposti ad altri agenti o servizi. I set di strumenti esportati possono essere utilizzati da altri agenti tramite `Use(AgentToolset(...))`.

**Contesto**: All'interno di `Agent` o `Service`

```go
Agent("planner", "Planning agent", func() {
    Export("planning.tools", func() {
        Tool("create_plan", "Create a plan", func() {
            Args(func() {
                Attribute("goal", String, "Goal to plan for")
                Required("goal")
            })
            Return(func() {
                Attribute("plan", String, "Generated plan")
                Required("plan")
            })
        })
    })
})
```

### Set di strumenti dell'agente

`AgentToolset(service, agent, toolset)` references a toolset exported by another agent. Ciò consente la composizione dell'agente come strumento.

**Contesto**: argomento per `Use`

Utilizzare `AgentToolset` quando:

- Non disponi di un handle di espressione per il set di strumenti esportato
- Più agenti esportano set di strumenti con lo stesso nome
- Vuoi essere esplicito nel design per chiarezza

```go
// Agent A exports tools
Agent("planner", func() {
    Export("planning.tools", func() { /* tools */ })
})

// Agent B uses Agent A's tools
Agent("orchestrator", func() {
    Use(AgentToolset("service", "planner", "planning.tools"))
})
```

### Passaggio

`Passthrough(toolName, target, methodName)` definisce l'inoltro deterministico per uno strumento esportato a un metodo di servizio Goa. Questo bypassa completamente il pianificatore.

**Contesto**: all'interno di `Tool` nidificato sotto `Export`

```go
Export("logging-tools", func() {
    Tool("log_message", "Log a message", func() {
        Args(func() {
            Attribute("message", String, "Message to log")
            Required("message")
        })
        Return(func() {
            Attribute("logged", Boolean, "Whether the message was logged")
        })
        Passthrough("log_message", "LoggingService", "LogMessage")
    })
})
```

### DisableAgentDocs

`DisableAgentDocs()` disabilita la generazione di `AGENTS_QUICKSTART.md` nella radice del modulo.

**Contesto**: All'interno di `API`

```go
var _ = API("orchestrator", func() {
    DisableAgentDocs()
})
```

---

## Funzioni del set di strumenti

### Set di strumenti

`Toolset(name, dsl)` dichiara un set di strumenti di proprietà del provider al livello più alto. Quando dichiarato al livello più alto, il set di strumenti diventa riutilizzabile a livello globale; gli agenti vi fanno riferimento tramite `Use`.

**Contesto**: Primo livello

```go
var DocsToolset = Toolset("docs.search", func() {
    Description("Tools for searching documentation")
    Tool("search", "Search indexed documentation", func() {
        Args(func() {
            Attribute("query", String, "Search phrase")
            Required("query")
        })
        Return(func() {
            Attribute("documents", ArrayOf(String), "Matched snippets")
            Required("documents")
        })
    })
})
```

I set di strumenti possono includere una descrizione utilizzando la funzione DSL `Description()` standard:

```go
var DataToolset = Toolset("data-tools", func() {
    Description("Tools for data processing and analysis")
    Tool("analyze", "Analyze dataset", func() {
        Args(func() {
            Attribute("dataset_id", String, "Dataset identifier")
            Required("dataset_id")
        })
        Return(func() {
            Attribute("insights", ArrayOf(String), "Analysis insights")
            Required("insights")
        })
    })
})
```

### Attrezzo

`Tool(name, description, dsl)` definisce una funzionalità richiamabile all'interno di un set di strumenti.

**Contesto**: All'interno di `Toolset` o `Method`

La generazione del codice emette:

- Strutture Go payload/risultato in `tool_specs/types.go`
- Codec JSON (`tool_specs/codecs.go`)
- Definizioni dello schema JSON utilizzate dai pianificatori
- Voci del registro degli strumenti con prompt e metadati di supporto

```go
Tool("search", "Search indexed documentation", func() {
    Title("Document Search")
    Args(func() {
        Attribute("query", String, "Search phrase")
        Attribute("limit", Int, "Max results", func() { Default(5) })
        Required("query")
    })
    Return(func() {
        Attribute("documents", ArrayOf(String), "Matched snippets")
        Required("documents")
    })
    CallHintTemplate("Searching for: {{ .Query }}")
    ResultHintTemplate("Found {{ len .Result.Documents }} documents")
    Tags("docs", "search")
})
```

### Argomenti e Invio

`Args(...)` e `Return(...)` definiscono i tipi di payload/risultato utilizzando l'attributo Goa standard DSL.

**Contesto**: All'interno di `Tool`

Puoi usare:

- Una funzione per definire uno schema di oggetti in linea con chiamate `Attribute()`
- Un tipo di utente Goa (Tipo, Risultato, ecc.) per riutilizzare le definizioni di tipo esistenti
- Un tipo primitivo (String, Int, ecc.) per input/output semplici a valore singolo

```go
Tool("search", "Search documentation", func() {
    Args(func() {
        Attribute("query", String, "Search phrase")
        Attribute("limit", Int, "Max results", func() {
            Default(5)
            Minimum(1)
            Maximum(100)
        })
        Required("query")
    })
    Return(func() {
        Attribute("documents", ArrayOf(String), "Matched snippets")
        Attribute("count", Int, "Number of results")
        Required("documents", "count")
    })
})
```

**Tipi di riutilizzo:**

```go
var SearchParams = Type("SearchParams", func() {
    Attribute("query", String)
    Attribute("limit", Int)
    Required("query")
})

Tool("search", "Search documents", func() {
    Args(SearchParams)
    Return(func() {
        Attribute("results", ArrayOf(String))
    })
})
```

### Dati del server

`ServerData(kind, val, args...)` definisce l'output tipizzato solo del server emesso insieme al risultato dello strumento. I dati del server non vengono mai inviati ai fornitori di modelli.
I dati del server della sequenza temporale vengono in genere proiettati in schede dell'interfaccia utente, grafici, tabelle o mappe rivolte all'osservatore, mantenendo il risultato rivolto al modello delimitato ed efficiente in termini di token. Le prove e il pubblico interno consentono ai consumatori a valle di instradare dati relativi alla provenienza o alla sola composizione senza fare affidamento su convenzioni di denominazione.

**Contesto**: All'interno di `Tool`

**Parametri:**

- `kind`: un identificatore di stringa per il tipo di dati del server (ad esempio, `"metrics.time_series"`, `"control.narrative"`, `"audit.evidence"`). Ciò consente ai consumatori di identificare e gestire in modo appropriato le diverse proiezioni dei dati del server.
- `val`: la definizione dello schema, seguendo gli stessi modelli di `Args` e `Return`: una funzione con chiamate `Attribute()`, un tipo di utente Goa o un tipo primitivo.

**Instradamento del pubblico (`Audience`*):**

Ogni voce `ServerData` dichiara un pubblico che i consumatori a valle utilizzano per instradare il carico utile senza fare affidamento su convenzioni di denominazione del tipo:

- `"timeline"`: persistente e idoneo per la proiezione rivolta all'osservatore (ad esempio, schede UI/timeline)
- `"internal"`: accessorio composizione utensili; non persistente o reso
- `"evidence"`: riferimenti di provenienza; persisteva separatamente dalle schede della sequenza temporale

Imposta il pubblico all'interno del blocco DSL `ServerData`:

```go
ServerData("metrics.time_series.chart_points", TimeSeriesServerData, func() {
    AudienceInternal()
    FromMethodResultField("chart_sidecar")
})

ServerData("audit.evidence", ArrayOf(Evidence), func() {
    AudienceEvidence()
    FromMethodResultField("evidence")
})
```

**Quando utilizzare ServerData:**

- Quando i risultati dello strumento devono includere dati completi per le interfacce utente (grafici, grafici, tabelle) mantenendo limitati i carichi utili del modello
- Quando si desidera allegare set di risultati di grandi dimensioni che supererebbero i limiti del contesto del modello
- Quando i consumatori a valle necessitano di dati strutturati che il modello non ha bisogno di vedere

```go
Tool("get_time_series", "Get time series data", func() {
    Args(func() {
        Attribute("device_id", String, "Device identifier")
        Attribute("start_time", String, "Start timestamp (RFC3339)")
        Attribute("end_time", String, "End timestamp (RFC3339)")
        Required("device_id", "start_time", "end_time")
    })
    Return(func() {
        Attribute("summary", String, "Summary for the model")
        Attribute("count", Int, "Number of data points")
        Attribute("min_value", Float64, "Minimum value in range")
        Attribute("max_value", Float64, "Maximum value in range")
        Required("summary", "count")
    })
    ServerData("metrics.time_series", func() {
        Attribute("data_points", ArrayOf(TimeSeriesPoint), "Full time series data")
        Attribute("metadata", MapOf(String, String), "Additional metadata")
        Required("data_points")
    })
})
```

**Utilizzo di un tipo Goa per lo schema server-data:**

```go
var TimeSeriesServerData = Type("TimeSeriesServerData", func() {
    Attribute("data_points", ArrayOf(TimeSeriesPoint), "Full time series data")
    Attribute("unit", String, "Measurement unit")
    Attribute("resolution", String, "Data resolution (e.g., '1m', '5m', '1h')")
    Required("data_points")
})

Tool("get_metrics", "Get device metrics", func() {
    Args(func() {
        Attribute("device_id", String, "Device identifier")
        Required("device_id")
    })
    Return(func() {
        Attribute("summary", String, "Metrics summary for the model")
        Attribute("point_count", Int, "Number of data points")
        Required("summary", "point_count")
    })
    ServerData("metrics.query", TimeSeriesServerData)
})
```

**Accesso in fase di esecuzione:**

In fase di esecuzione, vengono eseguiti i dati del server emessi dagli strumenti
`planner.ToolResult.ServerData`. Decodifica quei byte JSON canonici con il file
codec dati server generati per i tipi dichiarati dello strumento:

```go
// In a stream subscriber or result handler
func handleToolResult(result *planner.ToolResult) {
    if len(result.ServerData) > 0 {
        // Decode with the generated server-data codecs for this tool.
    }
}
```

### Risultato delimitato

`BoundedResult()` contrassegna il risultato dello strumento corrente come una vista limitata su un set di dati potenzialmente più grande.
Dichiara un contratto sui limiti di proprietà del runtime mantenendo il tipo di risultato creato semantico e
specifico del dominio.

**Contesto**: All'interno di `Tool`

Campi visibili nel modello canonico:

- `returned` (richiesto, `Int`)
- `truncated` (richiesto, `Boolean`)
- `total` (opzionale, `Int`)
- `refinement_hint` (opzionale, `String`)
- `next_cursor` (opzionale, `String`) quando `NextCursor(...)` è esposto da un contratto `Cursor` diretto

`BoundedResult` è l'unica fonte di verità per quel contratto:

- codegen lo registra nel `tools.ToolSpec.Bounds` generato
- codegen proietta i campi delimitati canonici nello schema dei risultati JSON generato
- le esecuzioni limitate riuscite devono impostare `planner.ToolResult.Bounds`
- il runtime proietta i bounds di proprietà del provider nel JSON codificato `tool_result`, nei dati del modello di suggerimento dei risultati,
hook ed eventi in streaming
- `ContinueWith` mantiene il cursor fuori dal contratto del modello e offre un'azione senza argomenti solo finché una singola testa di catena attiva può continuare; la corrispondenza esatta del cursor fa avanzare le pagine sequenziali. Le chiamate sorgente parallele restano valide, ma più teste attive rendono indisponibile la continuazione senza argomenti
- `Cursor` diretto espone il cursor opaco del provider in `next_cursor`

```go
Tool("list_devices", "List devices with pagination", func() {
    Args(func() {
        Attribute("site_id", String, "Site identifier")
        Attribute("cursor", String, "Cursor opaco della pagina successiva restituito dalla pagina precedente")
        Required("site_id")
    })
    Return(func() {
        Attribute("devices", ArrayOf(Device), "List of devices")
        Required("devices")
    })
    BoundedResult(func() {
        Cursor("cursor")
        NextCursor("next_cursor")
    })
})
```

I tipi di restituzione fronte utensile non devono dichiarare `returned`, `total`, `truncated`,
`refinement_hint` o `next_cursor` solo in modo che il modello possa vederli. Mantieni focalizzato il risultato semantico
sui dati del dominio. Gli strumenti supportati dal metodo possono comunque utilizzare internamente tipi di risultati del metodo di servizio più avanzati, ma
il contratto dello strumento Goa-AI proviene da `BoundedResult(...)`, campi di restituzione dello strumento non duplicati. Dentro
per i risultati del metodo associato, potrebbero essere richiesti solo `returned` e `truncated`; `total`,
`refinement_hint` e `next_cursor` rimangono parti facoltative del contratto vincolante.

**Responsabilità del servizio:**

I servizi sono responsabili di:

1. Applicare la propria logica di troncamento (impaginazione, limiti, limiti di profondità)
2. Compilazione di `planner.ToolResult.Bounds`
3. Impostazione di `Bounds.NextCursor` con il cursor del provider quando esiste un'altra pagina
4. Facoltativamente fornire `RefinementHint` quando i risultati vengono troncati

Il runtime non calcola i sottoinsiemi o il troncamento stesso. Convalida e proietta solo i limiti
metadati riportati dagli strumenti.

**Quando utilizzare BoundedResult:**

- Strumenti che restituiscono elenchi impaginati (dispositivi, utenti, record)
- Strumenti che interrogano set di dati di grandi dimensioni con limiti di risultati
- Strumenti che applicano limiti di profondità o dimensione alle strutture nidificate
- Qualsiasi strumento in cui il modello deve comprendere che i risultati potrebbero essere incompleti

**Comportamento durante l'esecuzione:**

```go
result := &planner.ToolResult{
    Result: &ListDevicesResult{
        Devices: devices,
    },
    Bounds: &agent.Bounds{
        Returned:       len(devices),
        Total:          ptr(total),
        Truncated:      truncated,
        NextCursor:     nextCursor,
        RefinementHint: refinementHint,
    },
}
```

Quando uno strumento limitato viene eseguito:

1. Il runtime convalida che uno strumento associato con successo ha restituito `planner.ToolResult.Bounds`.
2. Il runtime unisce tali limiti nel JSON emesso utilizzando i nomi dei campi da `BoundedResult(...)`.
3. Con `ContinueWith`, il cursor resta nel runtime e l'azione vuota viene offerta solo per una testa di catena attiva non ambigua.
4. Con `Cursor` diretto, `Bounds.NextCursor` viene emesso in `next_cursor` e il modello fornisce quel valore opaco nella chiamata successiva.

Gli strumenti possono includere un titolo visualizzato utilizzando la funzione DSL `Title()` standard:

```go
Tool("web_search", "Search the web", func() {
    Title("Web Search")
    Args(func() { /* ... */ })
})
```

### Conferma

`Confirmation(dsl)` dichiara che uno strumento deve essere esplicitamente approvato fuori banda prima
esegue. Questo è destinato agli strumenti **sensibili all'operatore** (scritture, eliminazioni, comandi).

**Contesto**: All'interno di `Tool`

Durante la generazione, Goa-AI registra la policy di conferma nella specifica
dello strumento. Durante l'esecuzione il workflow emette una richiesta di
conferma e termina con una sospensione; una risposta tipizzata accettata tramite
`Continue` avvia un nuovo workflow, che esegue lo strumento soltanto dopo
un'approvazione esplicita.

Esempio minimo:

```go
Tool("dangerous_write", "Write a stateful change", func() {
    Args(DangerousWriteArgs)
    Return(DangerousWriteResult)
    Confirmation(func() {
        Title("Confirm change")
        PromptTemplate(`Approve write: set {{ .key }} to {{ json .value }}`)
        DeniedResultTemplate(`{"summary":"Cancelled","key":{{ json .key }}}`)
    })
})
```

Note:

- Il runtime possiede il protocollo di conferma. Il workflow emette una
  sospensione con la richiesta pendente; l'applicazione invia una
  `api.PendingInputResponse` tipizzata tramite `Continue`, che avvia un nuovo
  workflow. Consulta la guida Runtime per payload e flusso di esecuzione.
- I modelli di conferma (`PromptTemplate` e `DeniedResultTemplate`) sono stringhe Go `text/template`
eseguito con `missingkey=error`. Oltre alle funzioni del modello standard (ad esempio `printf`),
Goa-AI fornisce:
  - `json v` → JSON codifica `v` (utile per campi puntatore opzionali o per incorporare valori strutturati).
  - `quote s` → restituisce una stringa tra virgolette con escape Go (come `fmt.Sprintf("%q", s)`).
- La conferma può essere abilitata anche dinamicamente in fase di runtime tramite `runtime.WithToolConfirmation(...)`
(utile per policy basate sull'ambiente o override per distribuzione).

### CallHintTemplate e ResultHintTemplate

`CallHintTemplate(template)` e `ResultHintTemplate(template)` configurano modelli di visualizzazione per le chiamate e i risultati degli strumenti. I modelli sono stringhe di testo/modello Go rese con valori Go digitati per produrre suggerimenti concisi mostrati durante e dopo l'esecuzione.

**Contesto**: All'interno di `Tool`

**Punti chiave:**

- I modelli di chiamata ricevono il payload digitato come root del modello (ad esempio, `.Query`, `.DeviceID`)
- I modelli di risultati ricevono un wrapper esplicito in cui i campi semantici risiedono in `.Result` e i metadati delimitati risiedono in `.Bounds`
- Mantieni i suggerimenti concisi: ≤140 caratteri consigliati per una visualizzazione dell'interfaccia utente pulita
- I modelli sono compilati con `missingkey=error`: tutti i campi a cui si fa riferimento devono esistere
- Utilizza i nomi dei campi Vai, non le chiavi JSON
- Utilizzare i blocchi `{{ if .Field }}` o `{{ with .Field }}` per i campi facoltativi

**Contratto runtime:**

- I costruttori di hook non visualizzano i suggerimenti. Gli eventi pianificati delle chiamate dello strumento sono impostati per impostazione predefinita su `DisplayHint==""`.
- Il runtime arricchisce e rende persistente un suggerimento di chiamata predefinito durevole al momento della pubblicazione a partire dal template tipizzato quando la decodifica del payload riesce.
- La registrazione dei tool richiede un titolo di metadati non vuoto. Quando la decodifica tipizzata non riesce o non è registrato alcun modello, il runtime usa quel titolo come display hint. I payload malformati continuano a fallire al confine del tool; il titolo di metadati serve solo a mantenere renderizzabile il lavoro tentato. I suggerimenti non vengono mai renderizzati rispetto ai byte JSON grezzi.
- Se un produttore imposta esplicitamente `DisplayHint` (non vuoto) prima di pubblicare l'evento hook, il runtime tratta
come autorevole e non lo sovrascrive.
- Per le modifiche alla formulazione per consumatore, configurare `runtime.WithHintOverrides` in fase di runtime. Le sovrascritture richiedono
precedenza sui modelli creati da DSL per gli eventi `tool_start` trasmessi in streaming.

**Esempio di base:**

```go
Tool("search", "Search documents", func() {
    Args(func() {
        Attribute("query", String, "Search phrase")
        Attribute("limit", Int, "Maximum results", func() { Default(10) })
        Required("query")
    })
    Return(func() {
        Attribute("count", Int, "Number of results found")
        Attribute("results", ArrayOf(String), "Matching documents")
        Required("count", "results")
    })
    CallHintTemplate("Searching for: {{ .Query }}")
    ResultHintTemplate("Found {{ .Result.Count }} results")
})
```

**Campi struttura digitati:**

I modelli di chiamata ricevono la struttura del payload Go generata come root del modello.
I modelli di risultati ricevono il wrapper di anteprima di runtime, quindi i campi semantici sono attivi
sotto `.Result` e i metadati delimitati risiedono in `.Bounds`. Seguono i nomi dei campi
Vai alle convenzioni di denominazione (PascalCase), non alle convenzioni JSON (snake_case o camelCase):

```go
// DSL definition
Tool("get_device_status", "Get device status", func() {
    Args(func() {
        Attribute("device_id", String, "Device identifier")      // JSON: device_id
        Attribute("include_metrics", Boolean, "Include metrics") // JSON: include_metrics
        Required("device_id")
    })
    Return(func() {
        Attribute("device_name", String, "Device name")          // JSON: device_name
        Attribute("is_online", Boolean, "Online status")         // JSON: is_online
        Attribute("last_seen", String, "Last seen timestamp")    // JSON: last_seen
        Required("device_name", "is_online")
    })
    // Use Go field names (PascalCase), not JSON keys
    CallHintTemplate("Checking status of {{ .DeviceID }}")
    ResultHintTemplate("{{ .Result.DeviceName }}: {{ if .Result.IsOnline }}online{{ else }}offline{{ end }}")
})
```

**Gestione dei campi facoltativi:**

Utilizza i blocchi condizionali per i campi facoltativi per evitare errori del modello:

```go
Tool("list_items", "List items with optional filter", func() {
    Args(func() {
        Attribute("category", String, "Optional category filter")
        Attribute("limit", Int, "Maximum items", func() { Default(50) })
    })
    Return(func() {
        Attribute("items", ArrayOf(Item), "Matching items")
        Attribute("total", Int, "Total count")
        Attribute("truncated", Boolean, "Results were truncated")
        Required("items", "total")
    })
    CallHintTemplate("Listing items{{ with .Category }} in {{ . }}{{ end }}")
    ResultHintTemplate("{{ .Result.Total }} items{{ if .Result.Truncated }} (truncated){{ end }}")
})
```

**Funzioni modello integrate:**

Il runtime fornisce queste funzioni di supporto per i modelli di suggerimento:


| Funzione | Descrizione | Esempio || ---------- | -------------------------------- | ---------------------------- |
| `join` | Unisci la sezione di stringa con il separatore | `{{ join .Tags ", " }}` || `count`    | Contare gli elementi in una fetta | `{{ count .Results }} items` || `truncate` | Tronca la stringa a N caratteri | `{{ truncate .Query 20 }}` |


**Esempio completo con tutte le funzionalità:**

```go
Tool("analyze_data", "Analyze dataset", func() {
    Args(func() {
        Attribute("dataset_id", String, "Dataset identifier")
        Attribute("analysis_type", String, "Type of analysis", func() {
            Enum("summary", "detailed", "comparison")
        })
        Attribute("filters", ArrayOf(String), "Optional filters")
        Required("dataset_id", "analysis_type")
    })
    Return(func() {
        Attribute("insights", ArrayOf(String), "Analysis insights")
        Attribute("metrics", MapOf(String, Float64), "Computed metrics")
        Attribute("processing_time_ms", Int, "Processing time in milliseconds")
        Required("insights", "processing_time_ms")
    })
    CallHintTemplate("Analyzing {{ .DatasetID }} ({{ .AnalysisType }})")
    ResultHintTemplate("{{ count .Result.Insights }} insights in {{ .Result.ProcessingTimeMs }}ms")
})
```

### Promemoria risultato

`ResultReminder(text)` configura un promemoria di sistema statico che viene inserito nella conversazione dopo la restituzione del risultato dello strumento. Utilizzalo per fornire indicazioni dietro le quinte al modello su come interpretare o presentare il risultato all'utente.

**Contesto**: All'interno di `Tool`

Il testo del promemoria viene automaticamente racchiuso tra i tag `<system-reminder>` dal runtime. Non includere i tag nel testo.

**Promemoria statici e dinamici:**

`ResultReminder` è per promemoria statici in fase di progettazione che si applicano ogni volta che viene chiamato lo strumento. Per i promemoria dinamici che dipendono dallo stato di runtime o dal contenuto dei risultati dello strumento, utilizzare invece `PlannerContext.AddReminder()` nell'implementazione del pianificatore. Supporto per i promemoria dinamici:

- Limitazione della velocità (giri minimi tra le emissioni)
- Tetti per corsa (emissioni massime per corsa)
- Aggiunta/rimozione di runtime in base alle condizioni
- Livelli di priorità (sicurezza vs guida)

**Esempio di base:**

```go
Tool("get_time_series", "Get time series data", func() {
    Args(func() {
        Attribute("device_id", String, "Device identifier")
        Attribute("start_time", String, "Start timestamp")
        Attribute("end_time", String, "End timestamp")
        Required("device_id", "start_time", "end_time")
    })
    Return(func() {
        Attribute("series", ArrayOf(DataPoint), "Time series data points")
        Attribute("summary", String, "Summary for the model")
        Required("series", "summary")
    })
    ResultReminder("The user sees a rendered graph of this data in the UI.")
})
```

**Quando utilizzare il promemoria sui risultati:**

- Quando l'interfaccia utente esegue il rendering dei risultati dello strumento in un modo speciale (grafici, grafici, tabelle) di cui il modello dovrebbe essere a conoscenza
- Quando il modello deve evitare di ripetere informazioni già visibili all'utente
- Quando c'è un contesto importante su come vengono presentati i risultati che influenza il modo in cui il modello dovrebbe rispondere
- Quando si desidera una guida coerente che si applichi a ogni invocazione dello strumento

**Strumenti multipli con promemoria:**

Quando più strumenti in un singolo turno hanno promemoria sui risultati, vengono combinati in un unico messaggio di sistema:

```go
Tool("get_metrics", "Get device metrics", func() {
    Args(func() { /* ... */ })
    Return(func() { /* ... */ })
    ResultReminder("Metrics are displayed as a dashboard widget.")
})

Tool("get_alerts", "Get active alerts", func() {
    Args(func() { /* ... */ })
    Return(func() { /* ... */ })
    ResultReminder("Alerts are shown in a priority-sorted list with severity indicators.")
})
```

**Promemoria dinamici tramite PlannerContext:**

Per i promemoria che dipendono dalle condizioni di runtime, utilizza invece l'API del pianificatore:

```go
// In your planner implementation
func (p *MyPlanner) PlanResume(ctx context.Context, input *planner.PlanResumeInput) (*planner.PlanResult, error) {
    // Add a dynamic reminder based on tool results
    for _, tr := range input.ToolOutputs {
        if tr.Name != "get_time_series" || tr.Failure != nil {
            continue
        }
        result, err := specs.UnmarshalGetTimeSeriesResult(tr.Result)
        if err != nil {
            return nil, err
        }
        if hasAnomalies(result) {
            input.Agent.AddReminder(reminder.Reminder{
                ID:   "anomaly_detected",
                Text: "Anomalies were detected in the time series. Highlight these to the user.",
                Priority: reminder.TierGuidance,
            })
        }
    }
    // ... rest of planner logic
}
```

### Tag

`Tags(values...)` annota strumenti o toolset con etichette piatte per il filtro
generico di policy e interfaccia utente. I tag del toolset vengono ereditati dai
suoi strumenti.

**Contesto**: All'interno di `Tool` o `Toolset`

Modelli di tag comuni:

- Categorie di domini: `"nlp"`, `"database"`, `"api"`, `"filesystem"`
- Tipi di funzionalità: `"read"`, `"write"`, `"search"`, `"transform"`
- Livelli di rischio: `"safe"`, `"destructive"`, `"external"`

```go
Tool("delete_file", "Delete a file", func() {
    Args(func() { /* ... */ })
    Tags("filesystem", "write", "destructive")
})
```

### Meta

Il DSL standard di Goa `Meta(name, values...)` associa un'annotazione denominata
in fase di progettazione allo strumento corrente. La generazione Goa-AI la
conserva in `ToolSpec.Meta` come `map[string][]string`.

```go
Tool("resolve_source", "Resolve a selectable source", func() {
    Args(ResolveSourceArgs)
    Return(ResolveSourceResult)
    Meta("example.chat.supplies_tool_input")
})
```

Usa `Meta` per un contratto stabile di proprietà di uno specifico consumer, non
per una categoria generica di policy. I metadati sono inerti: la sola presenza
di una chiave non cambia scheduling, visibilità, budget, retry o comportamento
terminale. Il planner, la policy o l'interfaccia che interpreta una chiave ne
possiede e documenta la semantica.

Mantieni canonici i contratti integrati:

- usa `Tags` per filtri generici di autorizzazione e capacità;
- usa `Bookkeeping` e `TerminalRun` per contabilità e comportamento terminale;
- usa `ToolFailure` e la relativa azione `Recovery` per gestire l'errore di un singolo risultato;
- usa campi del planner come `SynthesizeAfterTools` per le transizioni del batch.

### Associa a

`BindTo("Method")` o `BindTo("Service", "Method")` associa uno strumento a un metodo di servizio Goa.

**Contesto**: All'interno di `Tool`

Quando uno strumento è associato a un metodo:

- Lo schema `Args` dello strumento può differire dallo schema `Payload` del metodo
- Lo schema `Return` dello strumento può differire dallo schema `Result` del metodo
- Gli adattatori generati si trasformano tra tipi di strumenti e metodi

```go
var _ = Service("orchestrator", func() {
    Method("Search", func() {
        Payload(SearchPayload)
        Result(SearchResult)
    })
    
    Agent("chat", func() {
        Use("docs", func() {
            Tool("search", "Search documentation", func() {
                Args(SearchPayload)
                Return(SearchResult)
                BindTo("Search") // binds to method on same service
            })
        })
    })
})
```

### Iniettare

`Inject(fields...)` contrassegna campi specifici del payload come popolati dal server. I campi iniettati sono:

1. Nascosti al LLM (esclusi dallo schema JSON e dall'elenco dei campi obbligatori visibile al modello)
2. Campi `String` obbligatori sul payload effettivo dello strumento (l'`Args()` esplicito se fornito, altrimenti il payload del metodo associato)
3. Popolati da codice generato, a partire da una di due fonti determinate in fase di generazione: `runtime.ToolCallMeta` oppure le etichette dell'esecuzione

**Contesto**: All'interno di `Tool`

Un nome il cui Goify corrisponde a uno dei cinque campi fissi di `runtime.ToolCallMeta` (`run_id`/`runId`, `session_id`/`sessionId`, `turn_id`/`turnId`, `tool_call_id`/`toolCallId`, `parent_tool_call_id`/`parentToolCallId`) è **basato sui metadati** e si compila come una lettura diretta di tali metadati. Ogni altro nome è **basato su un'etichetta**: si compila come una ricerca nelle etichette dell'esecuzione (la chiave è il nome del design testuale), applicando al valore dell'etichetta la validazione dichiarata dal campo stesso (`Pattern`, `Length`, enum, ...), e il chiamante deve fornirla tramite `runtime.WithLabels(...)` all'avvio dell'esecuzione. Un campo basato su etichetta non può essere dichiarato su uno strumento `BindTo`, perché il protocollo del registro usato dagli strumenti associati e serviti dal registro non trasporta etichette dell'esecuzione.

```go
Tool("get_data", "Get data for current session", func() {
    Args(func() {
        Attribute("session_id", String, "Current session ID")
        Attribute("query", String, "Data query")
        Required("session_id", "query")
    })
    Return(func() {
        Attribute("data", ArrayOf(String))
    })
    BindTo("data_service", "get")
    Inject("session_id") // basato sui metadati: nascosto al LLM, impostato dal runtime
})

Tool("lookup_household", "Lookup scoped to a household", func() {
    Args(func() {
        Attribute("household_id", String, "Household to scope the search to.", func() {
            Pattern("^[a-z0-9-]+$")
        })
        Attribute("query", String, "Search query.")
        Required("household_id", "query")
    })
    Inject("household_id") // basato su etichetta: impostato tramite WithLabels("household_id", ...)
})
```

La generazione del codice emette una funzione `Inject<Tool>` per ogni strumento che inietta, nel file `inject.go` generato del toolset, che entrambe le topologie di esecuzione (gli executor locali in-process e il provider servito dal registro) chiamano in modo identico tra la decodifica e l'esecuzione. Un toolset porta anche un elenco `RequiredLabels` generato; `Runtime.Start`/`StartOneShot` lo validano rispetto alle etichette fornite tramite `WithLabels(...)` prima di pianificare qualsiasi workflow o attività, fallendo immediatamente e indicando in un unico errore tutte le chiavi mancanti.

I `ToolCallExecutor` scritti a mano (per strumenti senza `BindTo`, registrati direttamente presso il runtime) non hanno alcun punto di chiamata generato. Dovrebbero decodificare il payload di questi strumenti con la funzione generata `Decode<Tool>(payload, meta, labels) (*<Tool>Payload, error)` anziché con il `FromJSON` del codec di payload grezzo: `Decode<Tool>` compone il codec con `Inject<Tool>` in un'unica chiamata, così l'iniezione non può mai essere saltata silenziosamente. Decodificare con il solo codec lascerebbe i campi iniettati al loro valore zero di Go senza alcun errore, poiché il loro tag di wire è `json:"-"`.

`WithInterceptors` (vedi [Toolsets](toolsets.md#campi-iniettati)) è un meccanismo separato, ancora supportato, per hook forniti dall'utente che vengono eseguiti dopo `Inject<Tool>` sul payload tipizzato dell'executor di servizio generato; è indipendente dai campi `Inject()` dichiarati da un design.

### TerminalRun

`TerminalRun()` contrassegna lo strumento corrente come terminale per il run.
Quando lo strumento riesce, il runtime completa il run subito dopo aver
pubblicato il risultato, senza un turno `PlanResume`/finalizzazione successivo.
Goa-AI classifica automaticamente ogni strumento terminale come bookkeeping,
quindi `TerminalRun()` è l'unica dichiarazione necessaria.

**Contesto**: All'interno di `Tool`

Utilizzare `TerminalRun()` per gli strumenti il ​​cui risultato è l'output del terminale rivolto all'utente dell'esecuzione, ad esempio un renderer del report finale o uno strumento "commit this run". Il risultato dello strumento è l'artefatto terminale dell'esecuzione; la narrazione del modello extra non è né necessaria né desiderabile.

```go
Tool("commit_task", "Commit the terminal task artifact", func() {
    Args(TaskCompletionArgs)
    Return(TaskCompletionResult)
    TerminalRun()
})
```

**Comportamento in fase di esecuzione:**

- Codegen registra il flag su `tools.ToolSpec.TerminalRun`.
- Dopo una chiamata allo strumento terminale riuscita, il runtime finalizza l'esecuzione senza chiamare `PlanResume`.
- La generazione marca lo strumento anche come bookkeeping. Uno strumento terminale non consuma quindi budget di retrieval o di errori consecutivi e può essere ammesso anche quando il budget di retrieval è esaurito.

### Contabilità

`Bookkeeping()` contrassegna lo strumento corrente come record di controllo il
cui successo non pianifica da solo un altro turno del planner. Non consuma né
il budget di retrieval `MaxToolCalls` né la tolleranza agli errori consecutivi.

**Contesto**: All'interno di `Tool`

Usa `Bookkeeping()` per marker di stato strutturati, dichiarazioni di
transizione, finding e commit terminali. Non usarlo per snapshot o risultati di
lookup il cui successo deve pianificare un ragionamento successivo.

```go
Tool("set_step_status", "Update step status", func() {
    Args(SetStepStatusArgs)
    Return(SetStepStatusResult)
    Bookkeeping()
})
```

**Comportamento in fase di esecuzione:**

- Codegen registra il flag su `tools.ToolSpec.Bookkeeping`.
- Le chiamate di bookkeeping hanno costo zero per `MaxToolCalls` e non modificano il contatore degli errori consecutivi.
- Ogni batch di tool call prodotto dal modello è atomico. Il runtime ammette tutto il batch se tutte le chiamate con budget rientrano nel limite, altrimenti rifiuta tutto il batch. Non rimuove mai singole chiamate dalla risposta del provider.
- Chiamate e risultati restano eventi durevoli nello stream e nel run log, oltre che nella trascrizione del provider. Solo i risultati bookkeeping riusciti vengono omessi dai futuri `ToolOutputs` compatti.
- Un risultato bookkeeping fallito apre un turno dello strumento solo quando `ToolFailure.AllowsToolTurn()` restituisce true.
- Gli strumenti sconosciuti vengono trattati come preventivati; sono esenti solo gli strumenti dichiarati `Bookkeeping()` nel DSL (o contrassegnati in contabilità sul runtime `ToolSpec`).
- Un turno esclusivamente contabile deve risolversi nello stesso turno (`TerminalRun()`, `FinalResponse`, `FinalToolResult` o attendere/pausa).

**Commit terminali:**

Uno strumento di commit terminale richiede solo `TerminalRun()`, perché gli
strumenti terminali implicano bookkeeping:

```go
Tool("commit_task", "Commit the terminal task artifact", func() {
    Args(TaskCompletionArgs)
    Return(TaskCompletionResult)
    TerminalRun()  // nessun costo di retrieval; termina il run quando riesce
})
```

Il commit può essere ammesso senza budget di retrieval residuo. Quando riesce,
il run termina senza un turno successivo del planner.

## Funzioni politiche

### EseguiPolitica

`RunPolicy(dsl)` configura i limiti di esecuzione applicati in fase di esecuzione. Viene dichiarato all'interno di un `Agent` e contiene impostazioni di criteri come limiti, budget temporali, gestione della cronologia e gestione delle interruzioni.

**Contesto**: All'interno di `Agent`

**Funzioni policy disponibili:**

- `DefaultCaps` – limiti delle risorse (chiamate strumento, guasti consecutivi)
- `TimeBudget` – limite semplice dell'orologio a muro per l'intera corsa
- `Timing`: timeout dettagliati per attività di budget, pianificazione e strumenti (avanzato)
- `History` – gestione cronologia conversazioni (finestra scorrevole o compressione)
- `InterruptsAllowed`: abilita la pausa/ripresa per gli operatori umani nel ciclo
- `OnMissingFields` – comportamento di convalida per i campi obbligatori mancanti

```go
Agent("chat", "Conversational runner", func() {
    RunPolicy(func() {
        DefaultCaps(
            MaxToolCalls(8),
            MaxRecoveryTurns(3),
        )
        TimeBudget("2m")
        InterruptsAllowed(true)
        OnMissingFields("await_clarification")

        History(func() {
            KeepRecentTurns(20)
        })
    })
})
```

### DefaultCaps

`DefaultCaps(opts...)` applica limiti di capacità per prevenire cicli incontrollati e imporre limiti di esecuzione.

**Contesto**: All'interno di `RunPolicy`

```go
RunPolicy(func() {
    DefaultCaps(
        MaxToolCalls(8),
        MaxRecoveryTurns(3),
    )
})
```

**MaxToolCalls(n)**: imposta il numero massimo di invocazioni di strumenti a budget consentite per esecuzione. Gli strumenti dichiarati `Bookkeeping()` sono esenti da questo limite e non contano ai fini di `n`. Quando il budget è esaurito, il runtime interrompe la pianificazione delle chiamate preventivate e finalizza l'esecuzione del pianificatore con motivo di terminazione `tool_cap`.

**MaxRecoveryTurns(n)**: imposta il numero massimo di nuove chiamate al pianificatore dopo il rifiuto del risultato di uno strumento o di una risposta del modello. Il lavoro riuscito di uno strumento con budget reimposta questo limite. La chiamata finale dopo l'esaurimento non conta in `n`.

### Budget temporale

`TimeBudget(duration)` applica un limite temporale all'esecuzione dell'agente. La durata è specificata come stringa (ad esempio, `"2m"`, `"30s"`).

**Contesto**: All'interno di `RunPolicy`

```go
RunPolicy(func() {
    TimeBudget("2m") // 2 minutes
})
```

Per un controllo dettagliato sui timeout delle singole attività, utilizzare invece `Timing`.

### Tempistica

`Timing(dsl)` fornisce una configurazione di timeout dettagliata come alternativa a `TimeBudget`. Mentre `TimeBudget` imposta un unico limite complessivo, `Timing` consente di controllare i timeout su tre livelli: il budget di esecuzione complessivo, le attività del pianificatore (inferenza LLM) e le attività di esecuzione dello strumento.

**Contesto**: All'interno di `RunPolicy`

**Quando utilizzare Timing rispetto a TimeBudget:**

- Utilizzare `TimeBudget` per casi semplici in cui è sufficiente un unico limite di orologio da parete
- Utilizza `Timing` quando hai bisogno di timeout diversi per la pianificazione rispetto all'esecuzione dello strumento, ad esempio quando gli strumenti effettuano chiamate API esterne lente ma desideri risposte LLM veloci

```go
RunPolicy(func() {
    Timing(func() {
        Budget("10m")   // overall wall-clock budget for the entire run
        Plan("45s")     // timeout for Plan/Resume activities (LLM inference)
        Tools("2m")     // default timeout for ExecuteTool activities
    })
})
```

`Timing` rimane al livello di runtime semantico. `Plan(...)` e `Tools(...)`
limitato per quanto tempo un tentativo di pianificazione o strumento sano può essere eseguito una volta avviato.
Non configurano i meccanismi del motore del flusso di lavoro come i timeout di attesa della coda o
vivacità del battito cardiaco. Se usi l'adattatore temporale, configura questi meccanismi
con `temporal.Options.ActivityDefaults`.

**Funzioni di cronometraggio:**


| Funzione | Descrizione | Colpisce || ------------------ | ------------------------------------------ | -------------------------------------------------- |
| `Budget(duration)` | Budget totale dell'orologio da parete per la corsa | Intero ciclo di vita della corsa || `Plan(duration)` | Timeout per pianificare e riprendere le attività | Chiamate in inferenza LLM tramite pianificatore || `Tools(duration)` | Timeout predefinito per le attività di ExecuteTool | Esecuzione di strumenti (chiamate di servizio, MCP, agente come strumento) |


**In che modo la temporizzazione influisce sul comportamento di runtime:**

Il runtime traduce questi valori DSL in budget di tentativi indipendenti dal motore:

- `Budget` imposta il budget semantico dell'orologio da parete per l'esecuzione. Il runtime impone
quel budget per il lavoro del pianificatore/strumento e ricava il timeout di funzionamento del motore come
`Budget + FinalizerGrace + engine headroom` quindi il pianificatore finale riprenderà il turno
e la pulizia del terminale hanno ancora spazio per finire.
- `Plan` diventa il budget dei tentativi per `PlanStart` e `PlanResume`
- `Tools` diventa il budget di tentativo predefinito per `ExecuteTool`

Il comportamento di attesa della coda e di attività specifico temporale viene stratificato separatamente da
l'adattatore temporale.

**Esempio completo:**

```go
Agent("data-processor", "Processes large datasets", func() {
    Use(DataToolset)
    RunPolicy(func() {
        DefaultCaps(MaxToolCalls(20))
        Timing(func() {
            Budget("30m")   // long-running data jobs
            Plan("1m")      // LLM decisions should be quick
            Tools("5m")     // data operations may take time
        })
    })
})
```

### Conserva

`Cache(dsl)` configura il comportamento di memorizzazione nella cache dei prompt per l'agente. Specifica dove il runtime deve posizionare i checkpoint della cache rispetto ai prompt di sistema e alle definizioni degli strumenti per i provider che supportano la memorizzazione nella cache.

**Contesto**: All'interno di `RunPolicy`

La memorizzazione nella cache tempestiva può ridurre significativamente i costi di inferenza e la latenza consentendo ai provider di riutilizzare i contenuti elaborati in precedenza. La funzione Cache consente di definire i limiti del checkpoint utilizzati dai provider per determinare quale contenuto può essere memorizzato nella cache.

```go
RunPolicy(func() {
    Cache(func() {
        AfterSystem()  // checkpoint after system messages
        AfterTools()   // checkpoint after tool definitions
    })
})
```

**Funzioni checkpoint cache:**


| Funzione | Descrizione || --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AfterSystem()` | Inserisce un checkpoint della cache dopo tutti i messaggi di sistema. I provider lo interpretano come un limite della cache immediatamente successivo al preambolo del sistema.         || `AfterTools()` | Inserisce un checkpoint della cache dopo le definizioni degli strumenti. I provider lo interpretano come un limite della cache immediatamente successivo alla sezione di configurazione dello strumento. |


**Supporto del fornitore:**

Non tutti i provider supportano la memorizzazione nella cache dei prompt e il supporto varia in base al tipo di checkpoint:


| Fornitore | DopoSistema | AfterTools || ----------------------- | ----------- | ---------- |
| Bedrock (modelli Claude) | ✓ | ✓ || Bedrock (modelli Nova) | ✓ | ✗|


I provider che non supportano la memorizzazione nella cache ignorano queste opzioni. Il runtime convalida i vincoli specifici del provider, ad esempio la richiesta di `AfterTools` con un modello Nova restituisce un errore.

**Quando utilizzare la cache:**

- Utilizza `AfterSystem()` quando il prompt del tuo sistema è stabile tra i turni e vuoi evitare di rielaborarlo
- Utilizzare `AfterTools()` quando le definizioni dello strumento sono stabili e si desidera memorizzare nella cache la configurazione dello strumento
- Combina entrambi per il massimo vantaggio della memorizzazione nella cache con i provider supportati

**Esempio completo:**

```go
Agent("assistant", "Conversational assistant", func() {
    Use(DocsToolset)
    Use(SearchToolset)
    RunPolicy(func() {
        DefaultCaps(MaxToolCalls(10))
        TimeBudget("5m")
        Cache(func() {
            AfterSystem()  // cache the system prompt
            AfterTools()   // cache tool definitions (Claude only)
        })
    })
})
```

### Storia

`History(dsl)` definisce la preparazione della cronologia alla prima chiamata a
`PrepareMessages` in un'invocazione del pianificatore. Una decisione che non
legge i messaggi non esegue questa preparazione. Vedi il
[contratto di preparazione](../runtime/#preparing-conversation-messages).
Le policy della cronologia preservano:

- Il sistema richiede all'inizio della conversazione
- Confini logici del turno (utente + assistente + chiamate/risultati dello strumento come unità atomiche)

È possibile configurare al massimo una policy della cronologia per agente.

**Contesto**: All'interno di `RunPolicy`

Sono disponibili due policy standard:

**Mantieni giri recenti (finestra scorrevole):**

`KeepRecentTurns(n)` conserva solo gli N turni utente/assistente più recenti preservando i suggerimenti del sistema e gli scambi di strumenti. Questo è l'approccio più semplice per delimitare la dimensione del contesto.

```go
RunPolicy(func() {
    History(func() {
        KeepRecentTurns(20) // Keep the last 20 user/assistant turns
    })
})
```

**Parametri:**

- `n`: Numero di turni recenti da conservare (deve essere > 0)

**Compressione (riepilogo assistito da modello):**

La compressione riassume i turni più vecchi con un modello mantenendo una coda esatta e limitata di turni recenti completi. Separa due decisioni:

- `CompressAtTurns(n)` e `CompressAtMaxInputTokens(n)` decidono quando eseguire il riepilogo. Se entrambi sono configurati, uno dei due trigger può avviare la compressione.
- `KeepMaxTurns(n)` e `KeepMaxInputTokens(n)` decidono quali turni completi più recenti restano esatti dopo il riepilogo. Se entrambi sono configurati, si applicano entrambi i limiti.

I budget di token vengono contati a runtime dal modello di cronologia configurato, perché la tokenizzazione dipende dal modello. `KeepMaxInputTokens` non tronca mai un turno: il runtime procede all'indietro dal turno più recente e conserva solo turni completi che rientrano nel budget.

```go
RunPolicy(func() {
    History(func() {
        CompressAtMaxInputTokens(120_000)
        KeepMaxInputTokens(40_000)
        KeepMaxTurns(12)
    })
})
```

**Funzioni di compressione:**

- `CompressAtTurns(n)`: attiva la compressione quando sono presenti almeno `n` turni logici.
- `CompressAtMaxInputTokens(n)`: attiva la compressione quando il transcript visibile al provider supera `n` token di input.
- `KeepMaxTurns(n)`: conserva esatti al massimo `n` turni completi più recenti.
- `KeepMaxInputTokens(n)`: conserva turni completi recenti il cui conteggio di token di input rientra in `n`.

La compressione richiede almeno un trigger `CompressAt...` e almeno un budget di mantenimento `KeepMax...`.

**Requisito del modello storico:**

Quando si utilizza la compressione, è necessario fornire un `model.Client` tramite il campo `HistoryModel` generato nella configurazione dell'agente. Il runtime utilizza questo client con `ModelClassSmall` per riepilogare i turni precedenti e, quando è configurato un budget di token, contare la richiesta visibile al provider. La compressione basata sui token richiede che il modello di cronologia implementi `model.TokenCounter` con conteggi esatti; l'adapter Bedrock lo fa con l'API nativa `CountTokens` di Bedrock.

```go
cfg := chat.ChatAgentConfig{
    Planner:      &ChatPlanner{},
    HistoryModel: smallModelClient,
}
if err := chat.RegisterChatAgent(ctx, rt, cfg); err != nil {
    log.Fatal(err)
}
```

I valori DSL sono predefiniti generati. Un deployment può sostituirli quando il modello scelto ha una finestra di contesto o un budget operativo diverso:

```go
cfg := chat.ChatAgentConfig{
    Planner:      &ChatPlanner{},
    HistoryModel: smallModelClient,
    HistoryCompression: &runtime.HistoryCompressionConfig{
        CompressAtMaxInputTokens: 180_000,
        KeepMaxInputTokens:       60_000,
        KeepMaxTurns:             16,
    },
}
```

Se `HistoryModel` non viene fornito quando è configurata la compressione, la registrazione avrà esito negativo.

**Preservazione dei confini della svolta:**

Entrambe le politiche preservano i confini logici dei turni come unità atomiche. Un "turno" è composto da:

1. Un messaggio utente
2. La risposta dell'assistente (chiamate di testo e/o strumenti)
3. Qualsiasi strumento risulta da quella risposta

Ciò garantisce che il modello veda sempre sequenze di interazione complete, mai svolte parziali che potrebbero confondere il contesto.

### Interruzioni consentite

`InterruptsAllowed(bool)` segnala che le interruzioni human-in-the-loop dovrebbero essere rispettate. Se abilitato, il runtime supporta le operazioni di pausa/ripresa, essenziali per i cicli di chiarimento e gli stati di attesa durevoli.

**Contesto**: All'interno di `RunPolicy`

**Vantaggi principali:**

- Consente all'agente di **mettere in pausa** l'esecuzione quando mancano le informazioni richieste (vedere `OnMissingFields`).
- Consente al pianificatore di **attendere** l'input dell'utente tramite strumenti di chiarimento.
- Garantisce che lo stato dell'agente venga preservato esclusivamente durante la pausa, senza consumare risorse di elaborazione fino alla ripresa.

```go
RunPolicy(func() {
    // Enable pause/resume capability
    InterruptsAllowed(true)
    
    // Automatically pause when required tool arguments are missing
    OnMissingFields("await_clarification")
})
```

### Su campi mancanti

`OnMissingFields(action)` configura il modo in cui l'agente risponde quando la convalida dell'invocazione dello strumento rileva campi obbligatori mancanti.

**Contesto**: All'interno di `RunPolicy`

Valori validi:

- `"finalize"`: interrompe l'esecuzione quando mancano i campi obbligatori
- `"await_clarification"`: mette in pausa e attende che l'utente fornisca le informazioni mancanti
- `"resume"`: continua l'esecuzione nonostante i campi mancanti
- `""` (vuoto): lascia che sia il pianificatore a decidere in base al contesto

```go
RunPolicy(func() {
    OnMissingFields("await_clarification")
})
```

### Esempio di policy completa

```go
Agent("chat", "Conversational runner", func() {
    RunPolicy(func() {
        DefaultCaps(
            MaxToolCalls(8),
            MaxRecoveryTurns(3),
        )
        Timing(func() {
            Budget("5m")
            Plan("30s")
            Tools("1m")
        })
        InterruptsAllowed(true)
        OnMissingFields("await_clarification")
        History(func() {
            CompressAtMaxInputTokens(120_000)
            KeepMaxInputTokens(40_000)
            KeepMaxTurns(12)
        })
    })
})
```

---

## Funzioni MCP

Goa-AI fornisce funzioni DSL per dichiarare i server MCP (Model Context Protocol) all'interno dei servizi Goa.

###MCP

`MCP(name, version, opts...)` abilita il supporto MCP per il servizio corrente. Configura il servizio per esporre strumenti, risorse e prompt tramite il protocollo MCP.

**Contesto**: All'interno di `Service`

```go
Service("calculator", func() {
    Description("Calculator MCP server")
    
    MCP("calc", "1.0.0")
    JSONRPC(func() {
        POST("/mcp")
    })
    
    Method("add", func() {
        Payload(func() {
            Attribute("a", Int, "First number")
            Attribute("b", Int, "Second number")
            Required("a", "b")
        })
        Result(func() {
            Attribute("sum", Int, "Result of addition")
            Required("sum")
        })
        Tool("add", "Add two numbers")
    })
})
```

###Versioneprotocollo

`ProtocolVersion(version)` configura la versione del protocollo MCP supportata dal server. Restituisce una funzione di configurazione da utilizzare con `MCP`.

**Contesto**: argomento opzionale per `MCP`

```go
Service("calculator", func() {
    // Use the default protocol supported by Goa-AI.
    MCP("calc", "1.0.0")
    JSONRPC(func() {
        POST("/mcp")
    })
})
```

### Strumento (nel contesto del metodo)

All'interno di un `Method` in un servizio abilitato per MCP, `Tool(name, description)` contrassegna il metodo corrente come strumento MCP. Il carico utile del metodo diventa lo schema di input dello strumento e il risultato diventa lo schema di output.

**Contesto**: All'interno di `Method` (il servizio deve avere MCP abilitato)

```go
Method("search", func() {
    Payload(func() {
        Attribute("query", String, "Search query")
        Attribute("limit", Int, "Maximum results", func() { Default(10) })
        Required("query")
    })
    Result(func() {
        Attribute("results", ArrayOf(String), "Search results")
        Required("results")
    })
    Tool("search", "Search documents by query")
})
```

### Set di strumenti con `FromMCP` / `FromExternalMCP`

Utilizzare `Toolset(FromMCP(service, toolset))` per server MCP definiti da Goa nella stessa progettazione oppure `Toolset("name", FromExternalMCP(service, toolset), func() { ... })` per server MCP esterni con schemi in linea.

**Contesto**: Primo livello

**Server MCP supportato da Goa:**

```go
var AssistantSuite = Toolset(FromMCP("assistant", "assistant-mcp"))

var _ = Service("orchestrator", func() {
    Agent("chat", func() {
        Use(AssistantSuite)
    })
})
```

`FromMCP` deve puntare a un servizio Goa con lo stesso design che dichiara `MCP(...)`.
Il generatore estrae gli schemi degli strumenti dai metodi MCP di quel servizio.

**Server MCP esterno con schemi in linea:**

```go
var RemoteSearch = Toolset("remote-search", FromExternalMCP("remote", "search"), func() {
    Tool("web_search", "Search the web", func() {
        Args(func() { Attribute("query", String) })
        Return(func() { Attribute("results", ArrayOf(String)) })
    })
})

Agent("helper", "", func() {
    Use(RemoteSearch)
})
```

`FromExternalMCP` richiede dichiarazioni `Tool(...)` in linea perché le dichiarazioni esterne
gli schemi del server non provengono dal progetto Goa locale.

### Risorsa

`Resource(name, uri, mimeType)` contrassegna un metodo come provider di risorse MCP.

**Contesto**: All'interno di `Method` (il servizio deve avere MCP abilitato)

```go
Method("readme", func() {
    Result(String)
    Resource("readme", "file:///docs/README.md", "text/markdown")
})
```

### StaticPrompt

`StaticPrompt(name, description, messages...)` aggiunge un modello di prompt statico.

**Contesto**: All'interno di `Service`

```go
Service("assistant", func() {
    MCP("assistant-mcp", "1.0")
    JSONRPC(func() {
        POST("/mcp")
    })
    
    StaticPrompt("greeting", "Friendly greeting",
        "system", "You are a helpful assistant",
        "user", "Hello!")
})
```

### Esempio completo del server MCP

```go
var _ = Service("assistant", func() {
    Description("MCP server example")
    
    MCP("assistant-mcp", "1.0.0")
    JSONRPC(func() {
        POST("/mcp")
    })
    
    StaticPrompt("greeting", "Friendly greeting",
        "system", "You are a helpful assistant",
        "user", "Hello!")
    
    Method("search", func() {
        Description("Search documents")
        Payload(func() {
            Attribute("query", String, "Search query")
            Required("query")
        })
        Result(func() {
            Attribute("results", ArrayOf(String), "Search results")
            Required("results")
        })
        Tool("search", "Search documents by query")
    })
    
    Method("get_readme", func() {
        Result(String)
        Resource("readme", "file:///README.md", "text/markdown")
    })
    
})
```

---

## Funzioni del registro

Goa-AI fornisce funzioni DSL per dichiarare e utilizzare registri di strumenti: cataloghi centralizzati di server MCP, set di strumenti e agenti che possono essere rilevati e utilizzati dagli agenti.

### Registro

`Registry(name, dsl)` dichiara un'origine del registro per il rilevamento degli strumenti. I registri sono cataloghi centralizzati che possono essere scoperti e utilizzati dagli agenti goa-ai.

**Contesto**: Primo livello

All'interno della funzione DSL, utilizzare:

- `URL`: imposta l'URL dell'endpoint del registro (richiesto)
- `Description`: imposta una descrizione leggibile dall'uomo
- `APIVersion`: imposta la versione dell'API del registro (il valore predefinito è "v1")
- `Security`: fa riferimento agli schemi di sicurezza di Goa per l'autenticazione
- `Timeout`: imposta il timeout della richiesta HTTP
- `Retry`: configura la politica di ripetizione per le richieste non riuscite
- `SyncInterval`: imposta la frequenza con cui aggiornare il catalogo
- `CacheTTL`: imposta la durata della cache locale
- `Federation`: configura le impostazioni di importazione del registro esterno

```go
var CorpRegistry = Registry("corp-registry", func() {
    Description("Corporate tool registry")
    URL("https://registry.corp.internal")
    APIVersion("v1")
    Security(CorpAPIKey)
    Timeout("30s")
    Retry(3, "1s")
    SyncInterval("5m")
    CacheTTL("1h")
})
```

**Opzioni di configurazione:**


| Funzione | Descrizione | Esempio || ---------------------------- | -------------------------------- | --------------------------------------- |
| `URL(endpoint)` | URL dell'endpoint del registro (obbligatorio) | `URL("https://registry.corp.internal")` || `APIVersion(version)` | Segmento del percorso della versione API | `APIVersion("v1")` || `Timeout(duration)` | Timeout della richiesta HTTP | `Timeout("30s")` || `Retry(maxRetries, backoff)` | Riprova la policy per le richieste non riuscite | `Retry(3, "1s")` || `SyncInterval(duration)` | Intervallo di aggiornamento del catalogo | `SyncInterval("5m")` || `CacheTTL(duration)` | Durata della cache locale | `CacheTTL("1h")` |


### Federazione

`Federation(dsl)` configura le impostazioni di importazione del registro esterno. Utilizza la federazione all'interno di una dichiarazione del registro per specificare quali spazi dei nomi importare da un'origine federata.

**Contesto**: All'interno di `Registry`

All'interno della funzione Federation DSL, utilizzare:

- `Include`: specifica i modelli glob per gli spazi dei nomi da importare
- `Exclude`: specifica i modelli glob per gli spazi dei nomi da ignorare

```go
var AnthropicRegistry = Registry("anthropic", func() {
    Description("Anthropic MCP Registry")
    URL("https://registry.anthropic.com/v1")
    Security(AnthropicOAuth)
    Federation(func() {
        Include("web-search", "code-execution", "data-*")
        Exclude("experimental/*", "deprecated/*")
    })
    SyncInterval("1h")
    CacheTTL("24h")
})
```

**Includi ed escludi:**

- `Include(patterns...)`: specifica i modelli glob per gli spazi dei nomi da importare. Se non viene specificato alcun modello di inclusione, tutti gli spazi dei nomi vengono inclusi per impostazione predefinita.
- `Exclude(patterns...)`: specifica i modelli glob per gli spazi dei nomi da ignorare. I modelli di esclusione vengono applicati dopo i modelli di inclusione.

### Dal registro

`FromRegistry(registry, toolset)` configura un set di strumenti in modo che provenga da un registro. Utilizzare FromRegistry come opzione del provider quando si dichiara un set di strumenti.

**Contesto**: argomento per `Toolset`

```go
var CorpRegistry = Registry("corp", func() {
    URL("https://registry.corp.internal")
})

// Basic usage - toolset name derived from registry toolset name
var RegistryTools = Toolset(FromRegistry(CorpRegistry, "data-tools"))

// With explicit name
var MyTools = Toolset("my-tools", FromRegistry(CorpRegistry, "data-tools"))

// With additional configuration
var ConfiguredTools = Toolset(FromRegistry(CorpRegistry, "data-tools"), func() {
    Version("1.2.3")
})
```

I set di strumenti supportati dal registro possono essere aggiunti a una versione specifica utilizzando la funzione DSL `Version()` standard:

```go
var CorpRegistry = Registry("corp", func() {
    URL("https://registry.corp.internal")
})

var PinnedTools = Toolset("stable-tools", FromRegistry(CorpRegistry, "data-tools"), func() {
    Version("1.2.3")
})
```

Consuma un `Toolset(FromRegistry(...))` nominato con `Use`, oppure direttamente un intero `Registry`. Aggiungi `Deferred()` in `Use` per la ricerca nativa. L’agente generato risolve i contratti attuali una volta per attività di pianificazione. Collega client del registro distribuito e Pulse già costruiti con `rt.RegisterRegistry`; `Definition()` e `NewClient(rt)` non ricevono cataloghi.

I provider pubblicano `ToolSchemas()` con conferma, paginazione, metadati e dati server. Gli strumenti dinamici di servizio usano quei contratti; agenti e controllo restano compilati. Le fonti nominate devono esistere e rispettare la versione fissata; un registro completo può essere vuoto. Consumi duplicati o sovrapposti e strumenti inline o esportati su riferimenti al registro sono rifiutati.

Vedi [Ricerca degli strumenti e cataloghi dinamici](../tool-search/) per risoluzione attuale, contratti generati, provider e migrazione.

### Pubblica su

`PublishTo(registry)` configura la pubblicazione del registro per un set di strumenti esportato. Utilizzare PublishTo all'interno di un Export DSL per specificare in quali registri deve essere pubblicato il set di strumenti.

**Contesto**: All'interno di `Toolset` (durante l'esportazione)

```go
var CorpRegistry = Registry("corp", func() {
    URL("https://registry.corp.internal")
})

var LocalTools = Toolset("utils", func() {
    Tool("summarize", "Summarize text", func() {
        Args(func() { Attribute("text", String) })
        Return(func() { Attribute("summary", String) })
    })
})

Agent("data-agent", "Data processing agent", func() {
    Use(LocalTools)
    Export(LocalTools, func() {
        PublishTo(CorpRegistry)
        Tags("data", "etl")
    })
})
```

### Esempio di registro completo

```go
package design

import (
    . "goa.design/goa/v3/dsl"
    . "goa.design/goa-ai/dsl"
)

// Define registries
var CorpRegistry = Registry("corp-registry", func() {
    Description("Corporate tool registry")
    URL("https://registry.corp.internal")
    APIVersion("v1")
    Security(CorpAPIKey)
    Timeout("30s")
    Retry(3, "1s")
    SyncInterval("5m")
    CacheTTL("1h")
})

var AnthropicRegistry = Registry("anthropic", func() {
    Description("Anthropic MCP Registry")
    URL("https://registry.anthropic.com/v1")
    Federation(func() {
        Include("web-search", "code-execution")
        Exclude("experimental/*")
    })
    SyncInterval("1h")
    CacheTTL("24h")
})

// Consume toolsets from registries
var DataTools = Toolset(FromRegistry(CorpRegistry, "data-tools"), func() {
    Version("2.1.0")
})

var SearchTools = Toolset(FromRegistry(AnthropicRegistry, "web-search"))

// Local toolset to publish
var AnalyticsTools = Toolset("analytics", func() {
    Tool("analyze", "Analyze dataset", func() {
        Args(func() {
            Attribute("dataset_id", String, "Dataset identifier")
            Required("dataset_id")
        })
        Return(func() {
            Attribute("insights", ArrayOf(String), "Analysis insights")
            Required("insights")
        })
    })
})

var _ = Service("orchestrator", func() {
    Agent("analyst", "Data analysis agent", func() {
        Use(DataTools)
        Use(SearchTools)
        Use(AnalyticsTools)
        
        // Export and publish to registry
        Export(AnalyticsTools, func() {
            PublishTo(CorpRegistry)
            Tags("analytics", "data")
        })
        
        RunPolicy(func() {
            DefaultCaps(MaxToolCalls(10))
            TimeBudget("5m")
        })
    })
})
```

---

## Passaggi successivi

- **[Runtime](./runtime.md)** - Comprendere come i progetti si traducono in comportamento in fase di esecuzione
- **[Toolsets](../toolsets/)** - Approfondimento sui modelli di esecuzione del set di strumenti
- **[MCP Integration](./mcp-integration.md)** - Cablaggio runtime per server MCP

