Una sessione lunga muore in due modi: l’informazione decisiva — il vincolo posto al terzo turno, la decisione già presa — esce dalla finestra mentre l’agente continua come se ci fosse ancora, oppure l’agente incontra un’ambiguità e decide da solo. Sono lo stesso problema da due lati: che cosa deve sopravvivere, e a chi si passa la mano quando non basta.

Il contesto è un budget di attenzione, non un serbatoio

Anthropic definisce il context engineering come «the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference», e nomina il fenomeno che la rende necessaria, il context rot: «as the number of tokens in the context window increases, the model’s ability to accurately recall information from that context decreases». Non è un limite di capienza ma un degrado progressivo: riempire la finestra peggiora il richiamo molto prima di produrre un errore.

Tre leve, tre proprietari diversi

context editing   lato client   clear_tool_uses_20250919   cancella i tool result vecchi
compaction        lato server   compact_20260112           riassume e scarta il prima
memory tool       lato client   memory_20250818            file persistenti in /memories

Il context editing cancella selettivamente pezzi di storia mentre cresce: di default scatta a 100.000 token di input, conserva le ultime tre coppie di chiamata e risultato e cancella dalle più vecchie, sostituendo ognuna con un segnaposto che avvisa il modello della rimozione. Due parametri contano in produzione: exclude_tools, che protegge dalla cancellazione i risultati portanti, e clear_at_least, che esiste perché ogni cancellazione invalida il prefisso in cache e serve a stabilire «if context clearing is worth breaking your prompt cache».

La compaction lavora dall’altra parte del filo. Alla soglia configurata (150.000 token di default, mai sotto 50.000) il servizio genera un riassunto, e «the API automatically drops all content blocks prior to the compaction block». Su alcuni modelli i blocchi di thinking precedenti non vengono portati avanti, «so the summary is all the model has of that earlier work»: la doc aggiunge che se scrivi tu il campo instructions devi dire al modello che cosa il riassunto deve conservare. È l’unico punto in cui puoi difendere un’informazione critica, e va scritto prima che serva.

Il memory tool è la leva che sopravvive alla sessione: Claude crea, legge e aggiorna file sotto /memories, ma le operazioni le esegue la tua applicazione, quindi lo storage e la validazione dei percorsi sono tuoi (una richiesta con .. nel path deve essere respinta). Attivandolo, l’API inietta da sola un protocollo che vale la pena leggere: «ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory».

Scegliere prima che cosa deve sopravvivere

La combinazione consigliata è esplicita: «compaction keeps the active context small without client-side bookkeeping, and memory preserves the information that must survive summarization». Tradotto: la compaction gestisce il volume, la memoria gli invarianti, e gli invarianti si scrivono quando nascono, non a fine sessione.

Il pattern multisessione documentato lo formalizza: una sessione inizializzatrice scrive registro di avanzamento e checklist prima di qualunque lavoro, e ogni sessione successiva apre leggendoli e chiude aggiornandoli. La regola che tiene onesto il registro è una sola: una funzionalità si marca completata dopo una verifica end-to-end, non quando il codice è scritto.

Chiedere invece di indovinare

L’ambiguità non si risolve con un prompt più severo ma con un’azione. Nell’Agent SDK Claude chiama AskUserQuestion davanti a un compito con «multiple valid approaches», e la chiamata arriva alla tua callback canUseTool esattamente come una richiesta di permesso.

{
  "questions": [
    {
      "question": "How should I format the output?",
      "header": "Format",
      "options": [
        { "label": "Summary", "description": "Brief overview" },
        { "label": "Detailed", "description": "Full explanation" }
      ],
      "multiSelect": false
    }
  ]
}

I vincoli sono stretti: da una a quattro domande per chiamata, da due a quattro opzioni ciascuna, header di massimo dodici caratteri, e il tool «is not currently available in subagents spawned via the Agent tool» — se il ramo ambiguo vive dentro un subagent, la domanda deve risalire. Le risposte tornano indicizzate per testo della domanda; per l’opzione libera si passa il testo dell’utente, non la parola «Other».

Il vincolo architetturale più caro è la durata: «The callback can stay pending indefinitely. Execution remains paused until your callback returns». Accettabile in una CLI, non in un processo che aspetta un revisore umano. La via documentata è un hook PreToolUse che restituisce la decisione defer, «so the process can exit and resume later from the persisted session».

Escalare con un numero, non con una sensazione

L’escalation è una decisione di routing e si misura come tale. La guida al support agent traccia «the percentage of correctly escalated conversations versus those that should have been escalated but weren’t», con obiettivo del 95% o più, accanto a un tasso di deflection tipico del 70-80%. Senza il secondo termine — quelle che andavano escalate e non lo sono state — misuri solo quanto l’agente è prudente.

Il presupposto è il permesso di non sapere: dare all’agente la possibilità esplicita di dichiarare l’incertezza «can drastically reduce false information». E qui i due lati si chiudono: quello che l’umano riceve al passaggio di mano è esattamente ciò che la compaction ha riassunto e la memoria ha conservato. Un’escalation su un contesto già eroso non è un passaggio di mano, è una ripartenza.