---
title: Compattazione su richiesta
url: https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand
description: Chiedi a Claude di riassumere una conversazione quando lo decide la tua applicazione, poi prosegui dal riepilogo.
featureMetadata:
  status: beta
  betaHeader: compact-2026-09-04
  supportedModels:
    - claude-fable-5-1
    - claude-mythos-5-1
    - claude-fable-5
    - claude-mythos-5
    - claude-mythos-preview
    - claude-opus-5-5
    - claude-opus-5
    - claude-opus-4-8
    - claude-opus-4-7
    - claude-opus-4-6
    - claude-sonnet-5-5
    - claude-sonnet-5
    - claude-sonnet-4-6
    - claude-haiku-5-5
  supportedPlatforms:
    Claude API: beta
    Claude Platform on AWS: beta
    Google Cloud: beta
    Microsoft Foundry: beta
---

Con la "on-demand compaction" (compattazione su richiesta), è la tua applicazione a decidere quando una conversazione viene riassunta: invii una richiesta con il parametro `compaction` e Claude restituisce un riepilogo al posto di una risposta.

## Come funziona la compattazione su richiesta

Una richiesta di compattazione è separata dai turni della tua conversazione. Invii la conversazione così com'è con il parametro `compaction`, e la risposta contiene un singolo blocco `compaction`. Il blocco contiene il riepilogo sotto forma di testo leggibile e una firma. Invialo nelle richieste successive esattamente come è arrivato.

Da quel momento in poi il blocco prende il posto dei messaggi che riassume. Va per primo in `messages`, i messaggi riassunti vengono rimossi e il tuo turno successivo lo segue. Claude vede il riepilogo dove si trovavano quei messaggi.

<Frame>
  ![On-demand compaction (compattazione su richiesta): una richiesta che contiene quattro messaggi e il parametro compaction restituisce un blocco compaction e nessuna risposta; nella richiesta successiva il blocco viene per primo in messages al posto di quei quattro messaggi, seguito dal turno successivo dell'utente](https://platform.claude.com/docs/it/images/compaction-on-demand-swap.svg)
</Frame>

## Richiedi un riepilogo

Invia l'header beta `compact-2026-09-04` nella richiesta che chiede il riepilogo e in ogni richiesta successiva che contiene il blocco firmato. Per verificare se un modello supporta la compattazione su richiesta, chiama la [Models API](https://platform.claude.com/docs/it/api/beta/models/list) con l'header beta e leggi `capabilities.compaction` di ciascun modello. Non puoi combinare `compaction` con `context_management` in una stessa richiesta.

Invia la conversazione così com'è con `"compaction": {"type": "summarize"}`. L'API riassume una sola volta tutti i messaggi della richiesta, non genera alcuna risposta dopo di essi e restituisce solo il blocco con `stop_reason` `"compaction"`. Invia lo stesso prompt `system` e gli stessi `tools` che usi per il resto della conversazione. Il processo di riepilogo li legge e, se mantieni dei turni dopo il blocco su un modello con ["preserved thinking" (ragionamento preservato)](https://platform.claude.com/docs/it/build-with-claude/preserved-thinking), il ragionamento in quei turni resta valido solo se `system` e `tools` corrispondono. La conversazione in questo esempio non ha né un prompt `system` né strumenti, quindi la richiesta non invia nessuno dei due:

<CodeGroup>
  ```bash cURL
  # max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
  curl https://api.anthropic.com/v1/messages \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "anthropic-beta: compact-2026-09-04" \
    -H "content-type: application/json" \
    -d '{
      "model": "claude-opus-5-5",
      "max_tokens": 4096,
      "messages": [
        {"role": "user", "content": "I am building a recipe app. Help me name the main entities in the data model."},
        {"role": "assistant", "content": "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe."},
        {"role": "user", "content": "Good. Now suggest field names for Recipe."}
      ],
      "compaction": {"type": "summarize"}
    }'
  ```

  ```bash CLI
  ant beta:messages create --beta compact-2026-09-04 <<'YAML'
  model: claude-opus-5-5
  # max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
  max_tokens: 4096
  messages:
    - role: user
      content: I am building a recipe app. Help me name the main entities in the data model.
    - role: assistant
      content: Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.
    - role: user
      content: Good. Now suggest field names for Recipe.
  compaction:
    type: summarize
  YAML
  ```

  ```python Python
  from anthropic.types.beta import BetaMessageParam

  client = anthropic.Anthropic()

  history: list[BetaMessageParam] = [
      {
          "role": "user",
          "content": "I am building a recipe app. Help me name the main entities in the data model.",
      },
      {
          "role": "assistant",
          "content": "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.",
      },
      {"role": "user", "content": "Good. Now suggest field names for Recipe."},
  ]

  response = client.beta.messages.create(
      model="claude-opus-5-5",
      # max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
      max_tokens=4096,
      betas=["compact-2026-09-04"],
      messages=history,
      compaction={"type": "summarize"},
  )
  print(f"Stop reason: {response.stop_reason}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  const history: Anthropic.Beta.Messages.BetaMessageParam[] = [
    {
      role: "user",
      content: "I am building a recipe app. Help me name the main entities in the data model."
    },
    {
      role: "assistant",
      content:
        "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe."
    },
    { role: "user", content: "Good. Now suggest field names for Recipe." }
  ];

  const response = await client.beta.messages.create({
    model: "claude-opus-5-5",
    // max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
    max_tokens: 4096,
    betas: ["compact-2026-09-04"],
    messages: history,
    compaction: { type: "summarize" }
  });
  console.log(`Stop reason: ${response.stop_reason}`);
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Model = Anthropic.Models.Messages.Model;

  AnthropicClient client = new();

  List<BetaMessageParam> history =
  [
      new()
      {
          Role = Role.User,
          Content = "I am building a recipe app. Help me name the main entities in the data model.",
      },
      new()
      {
          Role = Role.Assistant,
          Content = "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.",
      },
      new() { Role = Role.User, Content = "Good. Now suggest field names for Recipe." },
  ];

  var response = await client.Beta.Messages.Create(new MessageCreateParams
  {
      Model = Model.ClaudeOpus5_5,
      // max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
      MaxTokens = 4096,
      Betas = [AnthropicBeta.Compact2026_09_04],
      Messages = history,
      Compaction = new BetaCompactionConfig(), // type defaults to "summarize"
  });

  Console.WriteLine($"Stop reason: {response.StopReason?.Raw()}");
  ```

  ```go Go
  client := anthropic.NewClient()

  history := []anthropic.BetaMessageParam{
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("I am building a recipe app. Help me name the main entities in the data model.")),
  	{
  		Role:    anthropic.BetaMessageParamRoleAssistant,
  		Content: []anthropic.BetaContentBlockParamUnion{anthropic.NewBetaTextBlock("Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.")},
  	},
  	anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("Good. Now suggest field names for Recipe.")),
  }

  response, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
  	Model: anthropic.ModelClaudeOpus5_5,
  	// max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
  	MaxTokens: 4096,
  	Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  	Messages:  history,
  	Compaction: anthropic.BetaCompactionConfigUnionParam{
  		OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  	},
  })
  if err != nil {
  	log.Fatal(err)
  }
  fmt.Println("Stop reason:", response.StopReason)
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaCompactionConfig;
  import com.anthropic.models.beta.messages.MessageCreateParams;

  void main() {
      var client = AnthropicOkHttpClient.fromEnv();

      var params = MessageCreateParams.builder()
          .model(Model.CLAUDE_OPUS_5_5)
          // max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
          .maxTokens(4096)
          .addBeta(AnthropicBeta.COMPACT_2026_09_04)
          .addUserMessage("I am building a recipe app. Help me name the main entities in the data model.")
          .addAssistantMessage("Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.")
          .addUserMessage("Good. Now suggest field names for Recipe.")
          .compaction(BetaCompactionConfig.builder().build()) // type defaults to "summarize"
          .build();

      var response = client.beta().messages().create(params);
      response.stopReason().ifPresent(reason -> IO.println("Stop reason: " + reason));
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaCompactionConfig;
  use Anthropic\Beta\Messages\BetaMessageParam;
  use Anthropic\Beta\Messages\BetaMessageParam\Role;

  $client = new Client();

  $history = [
      BetaMessageParam::with(
          role: Role::USER,
          content: 'I am building a recipe app. Help me name the main entities in the data model.',
      ),
      BetaMessageParam::with(
          role: Role::ASSISTANT,
          content: 'Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe.',
      ),
      BetaMessageParam::with(role: Role::USER, content: 'Good. Now suggest field names for Recipe.'),
  ];

  $response = $client->beta->messages->create(
      model: Model::CLAUDE_OPUS_5_5,
      // max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
      maxTokens: 4096,
      betas: [AnthropicBeta::COMPACT_2026_09_04],
      messages: $history,
      compaction: BetaCompactionConfig::with(), // type defaults to 'summarize'
  );

  echo "Stop reason: {$response->stopReason}", PHP_EOL;
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  history = [
    {
      role: "user",
      content: "I am building a recipe app. Help me name the main entities in the data model."
    },
    {
      role: "assistant",
      content: "Start with Recipe, Ingredient, and Step. Add a RecipeIngredient entry that holds the quantity and unit for each ingredient in a recipe."
    },
    { role: "user", content: "Good. Now suggest field names for Recipe." }
  ]

  response = client.beta.messages.create(
    model: Anthropic::Model::CLAUDE_OPUS_5_5,
    # max_tokens limita l'intera chiamata, incluso l'eventuale ragionamento, quindi prevedi diverse migliaia di token.
    max_tokens: 4096,
    betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
    messages: history,
    compaction: { type: "summarize" }
  )
  puts "Stop reason: #{response.stop_reason}"
  ```
</CodeGroup>

```json Response
{
  "id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
  "type": "message",
  "role": "assistant",
  "model": "claude-opus-5-5",
  "content": [
    {
      "type": "compaction",
      "content": "Summary of the conversation: the user is designing the data model for a recipe app. The entities agreed so far are Recipe, Ingredient, Step, and RecipeIngredient, which holds the quantity and unit. The user then asked for field names for Recipe.",
      "signature": "EuYBCkQY..."
    }
  ],
  "stop_reason": "compaction",
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0,
    "iterations": [{ "type": "compaction", "input_tokens": 144, "output_tokens": 276 }]
  }
}
```

La chiamata di riepilogo usa il modello, `system`, `tools`, le impostazioni di ragionamento e `max_tokens` della richiesta. Il processo di riepilogo legge le definizioni degli strumenti ma non esegue mai uno strumento, e la risposta non contiene alcun ragionamento. `max_tokens` limita l'intera chiamata, incluso qualsiasi ragionamento che il modello svolge prima di scrivere il riepilogo, quindi prevedi diverse migliaia di token. [Conteggia l'utilizzo della compattazione](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#understanding-usage) mostra come viene fatturata la chiamata.

Se l'ultimo turno `assistant` termina con una chiamata a uno strumento ancora priva di risultato, l'API rifiuta la richiesta. Invia prima i risultati degli strumenti di quel turno. Ometti inoltre `stop_sequences`, `output_config.format` per l'output strutturato e un `tool_choice` di tipo `any` o `tool`. Non avrebbero alcun effetto in una chiamata di riepilogo, e l'API li rifiuta. La conversazione deve comunque rientrare nella "context window" (finestra di contesto) del modello, quindi compatta prima di superarla, non dopo.

Quando esegui lo streaming della risposta, il blocco arriva intero. Ricevi un evento `content_block_start` che contiene il blocco completo, poi `content_block_stop`, senza eventi `content_block_delta`. Gli eventi `ping` possono arrivare prima o tra di essi.

## Continua dal riepilogo

Nella tua cronologia, sostituisci i messaggi che hai inviato con il messaggio assistant restituito. Mantieni il blocco `compaction` esattamente come l'API lo ha restituito, inclusa la sua `signature`. Eventuali turni svolti dopo l'invio della richiesta di compattazione seguono il blocco invariati, ed è su questo che si basa [Compattazione in background](https://platform.claude.com/docs/it/build-with-claude/compaction-background). Invia il blocco per primo in ogni richiesta successiva, con l'header beta:

```json
{
  "model": "claude-opus-5-5",
  "max_tokens": 2048,
  "messages": [
    {
      "role": "assistant",
      "content": [
        {
          "type": "compaction",
          "content": "Summary of the conversation: the user is designing the data model for a recipe app. The entities agreed so far are Recipe, Ingredient, Step, and RecipeIngredient, which holds the quantity and unit. The user then asked for field names for Recipe.",
          "signature": "EuYBCkQY..."
        }
      ]
    },
    {
      "role": "assistant",
      "content": "For Recipe, use title, description, servings, prep_minutes, and cook_minutes. Add created_at and updated_at timestamps."
    },
    { "role": "user", "content": "Now do the same for Ingredient." }
  ]
}
```

Questo esempio prosegue l'esempio di richiesta, che terminava con un turno `user`; il diagramma mostra il caso più semplice, in cui nessun turno viene svolto mentre il riepilogo viene scritto. Qui il secondo messaggio `assistant` è la risposta all'ultimo turno `user` riassunto. È arrivato mentre il riepilogo veniva scritto, quindi non era tra i messaggi riassunti. Due messaggi `assistant` consecutivi vanno bene in questo caso, perché il blocco viene comunque per primo.

L'API colloca il riepilogo dove si trova il blocco e passa a Claude invariati tutti i messaggi successivi. Segui queste regole:

* Metti il blocco per primo in `messages`, come messaggio `assistant` a sé stante oppure come primo blocco di contenuto del primo messaggio, che si tratti di un messaggio `user` o `assistant`.
* Rimuovi i messaggi riassunti. Se ne rimane qualcuno davanti al blocco, la richiesta restituisce un errore 400 (`compaction_block_misplaced`).
* Invia esattamente un blocco `compaction` per richiesta, in ogni richiesta successiva.

<Warning>
  Due errori nella sostituzione non generano alcun errore. Se dei messaggi riassunti rimangono dopo il blocco, l'API li invia di nuovo a Claude. Se una richiesta successiva omette il blocco, Claude non riceve alcun riepilogo.
</Warning>

La "threshold compaction" (compattazione a soglia) funziona al contrario: il suo blocco segue i messaggi che riassume, e l'API li elimina per te. Consulta [Restituire i blocchi di compattazione](https://platform.claude.com/docs/it/build-with-claude/compaction-threshold#passing-compaction-blocks-back).

In Python, usa `client.beta.messages`, come fanno gli esempi in questa pagina. Se chiami `client.messages` e serializzi i blocchi da solo, usa `to_dict()` o `model_dump(exclude_none=True)`: un semplice `model_dump()` aggiunge `citations: null` e `text: null` al blocco, e l'API lo rifiuta.

Se mantieni dei turni dopo il blocco e rinvii i relativi blocchi di ragionamento, le condizioni che mantengono valido quel ragionamento sono descritte in [Compattazione e ragionamento preservato](https://platform.claude.com/docs/it/build-with-claude/compaction-thinking-blocks).

### Compatta di nuovo

Per compattare una conversazione che inizia già con un blocco, invia di nuovo `compaction`. Il nuovo blocco riassume il vecchio riepilogo e tutto ciò che lo segue. Da quel momento in poi, invia solo il blocco più recente.

## Compatta in un ciclo

Dopo ogni turno, il ciclo somma i token di input e di output dell'ultima risposta, perché la richiesta successiva invia anche la risposta. Quando quel totale supera un limite e deve ancora seguire un altro turno, il ciclo invia una richiesta di compattazione con lo stesso modello e lo stesso prompt `system`, controlla `stop_reason`, sostituisce la propria cronologia con il messaggio restituito e stampa il turno prima del quale ha compattato. Il limite di 2.500 token dell'esempio è volutamente basso, in modo che anche una conversazione breve venga compattata. Imposta il tuo limite vicino al tuo budget di input reale.

<CodeGroup exclude="shell">
  ```python Python
  from anthropic.types.beta import BetaMessageParam

  client = anthropic.Anthropic()

  # Imposta questo valore vicino al tuo budget reale di input. Qui è basso così una breve conversazione viene compattata.
  COMPACT_AT_TOKENS = 2500
  SYSTEM = "You help design a recipe app's data model. Keep answers short."

  QUESTIONS = [
      "What are the main entities in the data model?",
      "Which fields should Recipe have?",
      "Which fields should Ingredient have?",
      "Which fields should RecipeIngredient have?",
      "Which fields should Step have?",
      "Which indexes should these tables have?",
      "Which fields should be required?",
      "Which fields should have default values?",
  ]

  history: list[BetaMessageParam] = []
  for turn, question in enumerate(QUESTIONS, start=1):
      history.append({"role": "user", "content": question})
      response = client.beta.messages.create(
          model="claude-opus-5-5",
          max_tokens=8192,
          system=SYSTEM,
          betas=["compact-2026-09-04"],
          messages=history,
      )
      history.append({"role": "assistant", "content": response.content})

      # Anche la richiesta successiva invia questa risposta, quindi conteggiala.
      conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
      if conversation_tokens > COMPACT_AT_TOKENS and turn < len(QUESTIONS):
          summary = client.beta.messages.create(
              model="claude-opus-5-5",
              max_tokens=4096,
              system=SYSTEM,
              betas=["compact-2026-09-04"],
              messages=history,
              compaction={"type": "summarize"},
          )
          if summary.stop_reason == "compaction":
              history = [{"role": "assistant", "content": summary.content}]
              print(f"Compacted before turn {turn + 1}")
  ```

  ```typescript TypeScript
  const client = new Anthropic();

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una breve conversazione viene compattata.
  const compactAtTokens = 2500;
  const systemPrompt = "You help design a recipe app's data model. Keep answers short.";

  const questions = [
    "What are the main entities in the data model?",
    "Which fields should Recipe have?",
    "Which fields should Ingredient have?",
    "Which fields should RecipeIngredient have?",
    "Which fields should Step have?",
    "Which indexes should these tables have?",
    "Which fields should be required?",
    "Which fields should have default values?"
  ];

  let history: Anthropic.Beta.Messages.BetaMessageParam[] = [];
  for (const [index, question] of questions.entries()) {
    const turn = index + 1;
    history.push({ role: "user", content: question });
    const response = await client.beta.messages.create({
      model: "claude-opus-5-5",
      max_tokens: 8192,
      system: systemPrompt,
      betas: ["compact-2026-09-04"],
      messages: history
    });
    history.push({ role: "assistant", content: response.content });

    // Anche questa risposta viene inviata con la richiesta successiva, quindi contala.
    const conversationTokens = response.usage.input_tokens + response.usage.output_tokens;
    if (conversationTokens > compactAtTokens && turn < questions.length) {
      const summary = await client.beta.messages.create({
        model: "claude-opus-5-5",
        max_tokens: 4096,
        system: systemPrompt,
        betas: ["compact-2026-09-04"],
        messages: history,
        compaction: { type: "summarize" }
      });
      if (summary.stop_reason === "compaction") {
        history = [{ role: "assistant", content: summary.content }];
        console.log(`Compacted before turn ${turn + 1}`);
      }
    }
  }
  ```

  ```csharp C#
  using Anthropic.Models.Beta;
  using Anthropic.Models.Beta.Messages;
  using Model = Anthropic.Models.Messages.Model;

  AnthropicClient client = new();

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una breve conversazione viene compattata.
  const int CompactAtTokens = 2500;
  const string SystemPrompt = "You help design a recipe app's data model. Keep answers short.";

  string[] questions =
  [
      "What are the main entities in the data model?",
      "Which fields should Recipe have?",
      "Which fields should Ingredient have?",
      "Which fields should RecipeIngredient have?",
      "Which fields should Step have?",
      "Which indexes should these tables have?",
      "Which fields should be required?",
      "Which fields should have default values?",
  ];

  List<BetaMessageParam> history = [];
  foreach (var (index, question) in questions.Index())
  {
      var turn = index + 1;
      history.Add(new() { Role = Role.User, Content = question });
      var response = await client.Beta.Messages.Create(new MessageCreateParams
      {
          Model = Model.ClaudeOpus5_5,
          MaxTokens = 8192,
          System = SystemPrompt,
          Betas = [AnthropicBeta.Compact2026_09_04],
          Messages = history,
      });
      history.Add(new()
      {
          Role = Role.Assistant,
          Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
      });

      // Anche la richiesta successiva invia questa risposta, quindi contala.
      var conversationTokens = response.Usage.InputTokens + response.Usage.OutputTokens;
      if (conversationTokens > CompactAtTokens && turn < questions.Length)
      {
          var summary = await client.Beta.Messages.Create(new MessageCreateParams
          {
              Model = Model.ClaudeOpus5_5,
              MaxTokens = 4096,
              System = SystemPrompt,
              Betas = [AnthropicBeta.Compact2026_09_04],
              Messages = history,
              Compaction = new BetaCompactionConfig(), // type defaults to "summarize"
          });
          if (summary.StopReason == BetaStopReason.Compaction)
          {
              history =
              [
                  new()
                  {
                      Role = Role.Assistant,
                      Content = summary.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
                  },
              ];
              Console.WriteLine($"Compacted before turn {turn + 1}");
          }
      }
  }
  ```

  ```go Go
  ctx := context.Background()
  client := anthropic.NewClient()

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una breve conversazione viene compattata.
  const compactAtTokens = 2500
  system := []anthropic.BetaTextBlockParam{{Text: "You help design a recipe app's data model. Keep answers short."}}

  questions := []string{
  	"What are the main entities in the data model?",
  	"Which fields should Recipe have?",
  	"Which fields should Ingredient have?",
  	"Which fields should RecipeIngredient have?",
  	"Which fields should Step have?",
  	"Which indexes should these tables have?",
  	"Which fields should be required?",
  	"Which fields should have default values?",
  }

  var history []anthropic.BetaMessageParam
  for i, question := range questions {
  	turn := i + 1
  	history = append(history, anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock(question)))
  	response, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  		Model:     anthropic.ModelClaudeOpus5_5,
  		MaxTokens: 8192,
  		System:    system,
  		Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  		Messages:  history,
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	history = append(history, response.ToParam())

  	// Anche questa risposta viene inviata con la richiesta successiva, quindi contala.
  	conversationTokens := response.Usage.InputTokens + response.Usage.OutputTokens
  	if conversationTokens > compactAtTokens && turn < len(questions) {
  		summary, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{
  			Model:     anthropic.ModelClaudeOpus5_5,
  			MaxTokens: 4096,
  			System:    system,
  			Betas:     []anthropic.AnthropicBeta{anthropic.AnthropicBetaCompact2026_09_04},
  			Messages:  history,
  			Compaction: anthropic.BetaCompactionConfigUnionParam{
  				OfSummarize: &anthropic.BetaSummarizeCompactionParam{},
  			},
  		})
  		if err != nil {
  			log.Fatal(err)
  		}
  		if summary.StopReason == anthropic.BetaStopReasonCompaction {
  			history = []anthropic.BetaMessageParam{summary.ToParam()}
  			fmt.Printf("Compacted before turn %d\n", turn+1)
  		}
  	}
  }
  ```

  ```java Java
  import com.anthropic.models.beta.AnthropicBeta;
  import com.anthropic.models.beta.messages.BetaCompactionConfig;
  import com.anthropic.models.beta.messages.BetaMessageParam;
  import com.anthropic.models.beta.messages.BetaStopReason;
  import com.anthropic.models.beta.messages.MessageCreateParams;

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso perché una breve conversazione venga compattata.
  static final long COMPACT_AT_TOKENS = 2500;
  static final String SYSTEM = "You help design a recipe app's data model. Keep answers short.";

  void main() {
      var client = AnthropicOkHttpClient.fromEnv();

      var questions = List.of(
          "What are the main entities in the data model?",
          "Which fields should Recipe have?",
          "Which fields should Ingredient have?",
          "Which fields should RecipeIngredient have?",
          "Which fields should Step have?",
          "Which indexes should these tables have?",
          "Which fields should be required?",
          "Which fields should have default values?"
      );

      var history = new ArrayList<BetaMessageParam>();
      for (int turn = 1; turn <= questions.size(); turn++) {
          history.add(BetaMessageParam.builder()
              .role(BetaMessageParam.Role.USER)
              .content(questions.get(turn - 1))
              .build());
          var params = MessageCreateParams.builder()
              .model(Model.CLAUDE_OPUS_5_5)
              .maxTokens(8192)
              .system(SYSTEM)
              .addBeta(AnthropicBeta.COMPACT_2026_09_04)
              .messages(history)
              .build();
          var response = client.beta().messages().create(params);
          history.add(response.toParam());

          // Anche questa risposta viene inviata con la richiesta successiva, quindi conteggiala.
          long conversationTokens = response.usage().inputTokens() + response.usage().outputTokens();
          if (conversationTokens > COMPACT_AT_TOKENS && turn < questions.size()) {
              var summaryParams = MessageCreateParams.builder()
                  .model(Model.CLAUDE_OPUS_5_5)
                  .maxTokens(4096)
                  .system(SYSTEM)
                  .addBeta(AnthropicBeta.COMPACT_2026_09_04)
                  .messages(history)
                  .compaction(BetaCompactionConfig.builder().build()) // type defaults to "summarize"
                  .build();
              var summary = client.beta().messages().create(summaryParams);
              if (summary.stopReason().map(BetaStopReason.COMPACTION::equals).orElse(false)) {
                  history.clear();
                  history.add(summary.toParam());
                  IO.println("Compacted before turn " + (turn + 1));
              }
          }
      }
  }
  ```

  ```php PHP
  use Anthropic\Beta\AnthropicBeta;
  use Anthropic\Beta\Messages\BetaCompactionConfig;
  use Anthropic\Beta\Messages\BetaMessageParam;
  use Anthropic\Beta\Messages\BetaMessageParam\Role;
  use Anthropic\Beta\Messages\BetaStopReason;

  $client = new Client();

  // Imposta questo valore vicino al tuo budget di input reale. Qui è basso così una breve conversazione viene compattata.
  const COMPACT_AT_TOKENS = 2500;
  const SYSTEM = "You help design a recipe app's data model. Keep answers short.";

  $questions = [
      'What are the main entities in the data model?',
      'Which fields should Recipe have?',
      'Which fields should Ingredient have?',
      'Which fields should RecipeIngredient have?',
      'Which fields should Step have?',
      'Which indexes should these tables have?',
      'Which fields should be required?',
      'Which fields should have default values?',
  ];

  $history = [];
  foreach ($questions as $index => $question) {
      $turn = $index + 1;
      $history[] = BetaMessageParam::with(role: Role::USER, content: $question);
      $response = $client->beta->messages->create(
          model: Model::CLAUDE_OPUS_5_5,
          maxTokens: 8192,
          system: SYSTEM,
          betas: [AnthropicBeta::COMPACT_2026_09_04],
          messages: $history,
      );
      $history[] = BetaMessageParam::with(role: Role::ASSISTANT, content: $response->content);

      // Anche la richiesta successiva invia questa risposta, quindi conteggiala.
      $conversationTokens = $response->usage->inputTokens + $response->usage->outputTokens;
      if ($conversationTokens > COMPACT_AT_TOKENS && $turn < count($questions)) {
          $summary = $client->beta->messages->create(
              model: Model::CLAUDE_OPUS_5_5,
              maxTokens: 4096,
              system: SYSTEM,
              betas: [AnthropicBeta::COMPACT_2026_09_04],
              messages: $history,
              compaction: new BetaCompactionConfig(), // type defaults to 'summarize'
          );
          if ($summary->stopReason === BetaStopReason::COMPACTION->value) {
              $history = [BetaMessageParam::with(role: Role::ASSISTANT, content: $summary->content)];
              printf("Compacted before turn %d\n", $turn + 1);
          }
      }
  }
  ```

  ```ruby Ruby
  client = Anthropic::Client.new

  # Imposta questo valore vicino al tuo budget reale di input. Qui è basso così una breve conversazione viene compattata.
  COMPACT_AT_TOKENS = 2500
  SYSTEM = "You help design a recipe app's data model. Keep answers short."

  questions = [
    "What are the main entities in the data model?",
    "Which fields should Recipe have?",
    "Which fields should Ingredient have?",
    "Which fields should RecipeIngredient have?",
    "Which fields should Step have?",
    "Which indexes should these tables have?",
    "Which fields should be required?",
    "Which fields should have default values?"
  ]

  history = []
  questions.each.with_index(1) do |question, turn|
    history << { role: "user", content: question }
    response = client.beta.messages.create(
      model: Anthropic::Model::CLAUDE_OPUS_5_5,
      max_tokens: 8192,
      system_: SYSTEM,
      betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
      messages: history
    )
    history << { role: "assistant", content: response.content }

    # Anche la richiesta successiva invia questa risposta, quindi conteggiala.
    conversation_tokens = response.usage.input_tokens + response.usage.output_tokens
    if conversation_tokens > COMPACT_AT_TOKENS && turn < questions.length
      summary = client.beta.messages.create(
        model: Anthropic::Model::CLAUDE_OPUS_5_5,
        max_tokens: 4096,
        system_: SYSTEM,
        betas: [Anthropic::AnthropicBeta::COMPACT_2026_09_04],
        messages: history,
        compaction: { type: "summarize" }
      )
      if summary.stop_reason == :compaction
        history = [{ role: "assistant", content: summary.content }]
        puts "Compacted before turn #{turn + 1}"
      end
    end
  end
  ```
</CodeGroup>

Il controllo su `stop_reason` avviene prima che il codice cerchi il blocco; [Gestisci un riepilogo mancante o un errore](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#when-no-summary-comes-back) spiega perché. La cronologia viene sostituita, non estesa: il messaggio restituito sostituisce tutti i messaggi contenuti nella richiesta, secondo le regole descritte in [Continua dal riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#continue-from-the-summary). Quando non viene restituito alcun riepilogo, il ciclo mantiene la propria cronologia e riprova dopo il turno successivo.

Il [tool runner](https://platform.claude.com/docs/it/agents-and-tools/tool-use/tool-runner) (esecutore di strumenti) dell'SDK in Python, TypeScript, C#, Go, Java, PHP e Ruby può inviare la richiesta di compattazione per te. Quando decidi di compattare, chiama `compact_before_next_turn()` (typescript, java, php: `compactBeforeNextTurn()`; csharp, go: `CompactBeforeNextTurn()`) sul runner. Una volta terminati il turno corrente e le relative chiamate agli strumenti, il runner invia la richiesta di compattazione e sostituisce la propria cronologia con il messaggio restituito. Crea il runner con la beta `compact-2026-09-04`, perché il runner non la aggiunge.

Il runner costruisce la richiesta di compattazione a partire dai propri parametri e omette `context_management`. Omette anche `stop_sequences`, un `tool_choice` di tipo `any` o `tool` e un `output_config.format` per l'output strutturato, che l'API rifiuta in una richiesta di compattazione. [Richiedi un riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#request-a-summary) spiega perché. Il runner li invia di nuovo nelle richieste successive. Le versioni dell'SDK precedenti a Python 1.8.0, TypeScript 0.128.0, C# 12.50.0, Go 1.75.0 e Java 2.65.0 li inviano anche nella richiesta di compattazione. Con quelle versioni, un runner che imposta uno qualsiasi di questi parametri riceve un errore 400. Il runner invia un ["task budget" (budget di attività)](https://platform.claude.com/docs/it/build-with-claude/task-budgets) invariato. Se `output_config.task_budget` imposta `remaining`, la richiesta di compattazione restituisce un errore 400, quindi lascia `remaining` non impostato, come indicato in [Limiti e interazioni con altre funzionalità](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#how-it-fits-with-the-rest-of-the-api). Il runner si rifiuta di compattare finché il suo `context_management` contiene una modifica di compattazione, quindi usa un solo tipo di compattazione per runner.

### Quando compattare

Puoi inviare una richiesta di compattazione dopo qualsiasi turno completato, quindi è il tuo codice a decidere quando.

Per stimare quanto sarà grande la richiesta successiva, somma `input_tokens` e `output_tokens` dall'`usage` dell'ultima risposta, come fa il ciclo. Con la ["prompt caching" (cache dei prompt)](https://platform.claude.com/docs/it/build-with-claude/prompt-caching#tracking-cache-performance), `input_tokens` conta solo i token successivi all'ultimo breakpoint della cache, quindi aggiungi anche `cache_read_input_tokens` e `cache_creation_input_tokens`. Puoi anche inviare gli stessi messaggi all'endpoint di ["token counting" (conteggio dei token)](https://platform.claude.com/docs/it/build-with-claude/token-counting).

Confronta quel numero con un limite a tua scelta, inferiore alla [finestra di contesto](https://platform.claude.com/docs/it/build-with-claude/context-windows) del modello.

## Scrivi il tuo prompt di riepilogo

Senza `instructions`, l'API usa il proprio prompt di riepilogo. Una stringa `instructions` non vuota (fino a 16.384 caratteri) sostituisce completamente quel prompt. Ad esempio:

```json
{
  "compaction": {
    "type": "summarize",
    "instructions": "Summarize this recipe app design conversation. Preserve every entity and field name agreed so far, and the user's latest open request. Do not call tools; respond with the summary text only."
  }
}
```

Il processo di riepilogo legge l'intera conversazione, incluso il ragionamento precedente, con o senza `instructions`. Nelle tue `instructions`, indica cosa deve conservare il riepilogo e di' al modello di non chiamare strumenti. La chiamata di riepilogo viene eseguita con le stesse misure di sicurezza di qualsiasi altra richiesta.

## Gestisci un riepilogo mancante o un errore

Un riepilogo viene prodotto solo quando la chiamata di riepilogo termina normalmente con del testo e senza chiamate a strumenti. Altrimenti, la risposta è comunque un 200 con `content` vuoto, quindi controlla `stop_reason` prima di cercare il blocco. La chiamata viene comunque fatturata e riportata in `usage.iterations`, con utilizzo pari a zero quando non è stato possibile effettuare alcuna chiamata. Lo `stop_reason` è quello con cui è terminata la chiamata di riepilogo. In ogni caso puoi continuare senza un riepilogo e compattare in seguito.

| `stop_reason`                     | Causa                                                                 | Cosa fare                                                                          |
| --------------------------------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `"max_tokens"`                    | Il riepilogo è stato troncato.                                        | Invia di nuovo con un `max_tokens` più grande.                                     |
| `"model_context_window_exceeded"` | Non c'era spazio per il prompt di riepilogo.                          | Invia di nuovo con `instructions` più brevi o con meno messaggi.                   |
| `"tool_use"`                      | Il modello ha chiamato uno strumento invece di scrivere il riepilogo. | Invia di nuovo con `instructions` che dicano al modello di non chiamare strumenti. |
| `"refusal"`                       | La richiesta è stata rifiutata.                                       | Continua senza un riepilogo.                                                       |
| `"end_turn"`                      | La chiamata non ha restituito alcun testo.                            | Continua senza un riepilogo.                                                       |

La chiamata di riepilogo è soggetta alle stesse misure di sicurezza delle tue altre richieste. Dopo un `"refusal"`, [`stop_details`](https://platform.claude.com/docs/it/build-with-claude/handling-stop-reasons#refusal) identifica la categoria di policy che lo ha determinato.

### Errori

Anche una richiesta di compattazione, o una richiesta che contiene un blocco, può fallire del tutto. La maggior parte degli errori 400 ha un messaggio che indica cosa rimuovere o inviare di nuovo. Alcuni contengono anche un `error.details.error_code` che inizia con `compaction_`. Gli errori sui parametri, come un campo che non può essere combinato con `compaction`, contengono solo il messaggio.

| Errore                                                                                                                                                                                              | Causa                                                                                                                     | Cosa fare                                                                                                                                                                                       |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 529 `overloaded_error`, `error.details.error_code` `compaction_unavailable`                                                                                                                         | Un problema temporaneo del server durante la produzione di un blocco, o durante la lettura di un blocco che hai rinviato. | Riprova la richiesta.                                                                                                                                                                           |
| 400 `compaction_block_misplaced`                                                                                                                                                                    | Dei messaggi riassunti rimangono davanti al blocco.                                                                       | Rimuovili, in modo che il blocco venga per primo in `messages`.                                                                                                                                 |
| 400 `compaction_signature_invalid` o `compaction_content_mismatch`                                                                                                                                  | La `signature` o il `content` del blocco sono stati modificati dopo che l'API lo ha restituito.                           | Invia il blocco esattamente come è stato restituito, inclusa la sua `signature`.                                                                                                                |
| 400                                                                                                                                                                                                 | La richiesta contiene più di un blocco `compaction`.                                                                      | Inviane esattamente uno, il più recente.                                                                                                                                                        |
| 400                                                                                                                                                                                                 | L'ultimo turno `assistant` termina con una chiamata a uno strumento ancora priva di risultato.                            | Invia i risultati degli strumenti di quel turno, poi compatta.                                                                                                                                  |
| 400 `compaction_nothing_to_summarize`                                                                                                                                                               | `messages` non ha contenuto `user` o `assistant`, ad esempio una lista vuota.                                             | Invia almeno un messaggio `user` o `assistant`.                                                                                                                                                 |
| 400 sulla richiesta di compattazione, con un messaggio che indica che il parametro `compaction` `requires anthropic-beta: compact-2026-09-04`                                                       | La richiesta di compattazione ha omesso l'header beta.                                                                    | Aggiungi l'header beta; consulta [Richiedi un riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#request-a-summary).                                         |
| 400 su una richiesta successiva che contiene il blocco: un errore di validazione che indica che `compaction` non è uno dei tipi di blocco di contenuto previsti. Il messaggio non menziona l'header | Quella richiesta ha omesso l'header beta.                                                                                 | Aggiungi l'header beta a ogni richiesta che contiene il blocco; consulta [Richiedi un riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#request-a-summary). |
| Errore di validazione 400, come `messages.0.content.0.compaction.citations: Extra inputs are not permitted`                                                                                         | Un blocco è stato rinviato con campi che l'API non aveva restituito, come `citations: null`.                              | Invia il blocco esattamente come è stato restituito; consulta [Continua dal riepilogo](https://platform.claude.com/docs/it/build-with-claude/compaction-on-demand#continue-from-the-summary).   |

## Conteggia l'utilizzo della compattazione

La chiamata di riepilogo viene fatturata ed è soggetta ai "rate limit" (limiti di velocità) come qualsiasi altra richiesta, e `usage.iterations` la riporta come voce `compaction`. I campi di primo livello `input_tokens` e `output_tokens` sono pari a zero perché non è stata generata alcuna risposta. Per conteggiare ciò che una conversazione ha consumato, somma i valori in `usage.iterations`, non i campi di primo livello. Rinviare un blocco nelle richieste successive non aggiunge alcun costo di compattazione.

Ora hai un ciclo funzionante che compatta una conversazione e gestisce un riepilogo mancante. Due pagine cambiano il modo in cui funziona, e puoi combinarle: [Compattazione che mantiene i turni recenti](https://platform.claude.com/docs/it/build-with-claude/compaction-keep-recent-turns) mantiene gli ultimi turni parola per parola, e [Compattazione in background](https://platform.claude.com/docs/it/build-with-claude/compaction-background) consente alla conversazione di proseguire mentre il riepilogo viene scritto. [Compattazione e ragionamento preservato](https://platform.claude.com/docs/it/build-with-claude/compaction-thinking-blocks) si applica se rinvii i blocchi di ragionamento e usi una delle due.

## Limiti e interazioni con altre funzionalità

* **Compattazione a soglia e modifica del contesto.** Non puoi inviare `compaction` e `context_management` nella stessa richiesta. La compattazione a soglia (`compact_20260112`) non può essere eseguita su una richiesta che contiene un blocco firmato.
* **Cache dei prompt.** `cache_control` sul blocco colloca un breakpoint dopo il riepilogo.
* **Messaggi di sistema a metà conversazione e modifiche agli strumenti.** Anche i messaggi `role: "system"` all'interno dell'intervallo riassunto vengono riassunti, quindi le loro istruzioni testuali smettono di applicarsi una volta che il blocco li sostituisce. Nemmeno un livello di [effort per messaggio](https://platform.claude.com/docs/it/build-with-claude/effort#change-effort-mid-conversation-beta) da essi impostato viene trasferito: finché un messaggio successivo non imposta un livello, i turni vengono eseguiti con l'`output_config.effort` di primo livello della richiesta, o con il valore predefinito del modello se non ne imposti uno. Se un'istruzione o un livello di effort è ancora rilevante, ribadiscilo in un messaggio `role: "system"`. Invia quel messaggio subito dopo il tuo prossimo nuovo turno `user` e lascialo nella tua cronologia da quel momento in poi. Per le [modifiche agli strumenti](https://platform.claude.com/docs/it/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes), e per sapere dove va quel messaggio quando mantieni dei turni dopo il blocco, consulta [Modificare il prompt di sistema o gli strumenti](https://platform.claude.com/docs/it/build-with-claude/compaction-thinking-blocks#change-the-system-prompt-or-tools).
* **Budget di attività.** Non inviare il valore `remaining` di un ["task budget" (budget di attività)](https://platform.claude.com/docs/it/build-with-claude/task-budgets) (`output_config.task_budget.remaining`) insieme a `compaction` o nelle richieste che contengono il blocco. In tal caso viene restituito un errore 400.
* **Conteggio dei token.** L'endpoint di [conteggio dei token](https://platform.claude.com/docs/it/build-with-claude/token-counting) ignora il parametro `compaction`.
* **Contenuti che il riepilogo non può trasportare.** Immagini, documenti, blocchi `container_upload` e URL recuperati all'interno dei messaggi riassunti vanno persi una volta che il blocco li sostituisce. Riformula o carica di nuovo tutto ciò di cui un turno successivo ha ancora bisogno.
