---
title: Compaction à la demande
url: https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand
description: Demandez à Claude de résumer une conversation au moment choisi par votre application, puis poursuivez à partir du résumé.
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
---

Avec la « on-demand compaction » (compaction à la demande), votre application décide quand une conversation est résumée : vous envoyez une requête avec le paramètre `compaction`, et Claude renvoie un résumé à la place d'une réponse.

## Fonctionnement de la compaction à la demande

Une requête de compaction est distincte des tours de votre conversation. Vous envoyez la conversation en l'état avec le paramètre `compaction`, et la réponse contient un unique bloc `compaction`. Ce bloc contient le résumé sous forme de texte lisible, ainsi qu'une signature. Renvoyez-le dans les requêtes suivantes exactement tel que vous l'avez reçu.

Dès lors, le bloc remplace les messages qu'il résume. Il est placé en premier dans `messages`, les messages résumés sont supprimés, et votre tour suivant vient après lui. Claude voit le résumé à l'endroit où se trouvaient ces messages.

<Frame>
  ![« On-demand compaction » (compaction à la demande) : une requête qui contient quatre messages et le paramètre compaction renvoie un bloc compaction et aucune réponse ; à la requête suivante, le bloc vient en premier dans messages à la place de ces quatre messages, suivi du tour utilisateur suivant](https://platform.claude.com/docs/fr/images/compaction-on-demand-swap.svg)
</Frame>

## Demander un résumé

Envoyez l'en-tête bêta `compact-2026-09-04` sur la requête qui demande le résumé et sur chaque requête ultérieure qui contient le bloc signé. Pour vérifier si un modèle prend en charge la compaction à la demande, appelez l'[API Models](https://platform.claude.com/docs/fr/api/beta/models/list) avec l'en-tête bêta et lisez le champ `capabilities.compaction` de chaque modèle. Vous ne pouvez pas combiner `compaction` avec `context_management` dans une même requête.

Envoyez la conversation en l'état avec `"compaction": {"type": "summarize"}`. L'API résume une fois chaque message de la requête, ne génère aucune réponse ensuite, et renvoie uniquement le bloc avec `stop_reason` `"compaction"`. Envoyez la même invite `system` et les mêmes `tools` que ceux que vous utilisez pour le reste de la conversation. Le résumeur les lit, et si vous conservez des tours après le bloc sur un modèle avec la [« preserved thinking » (réflexion préservée)](https://platform.claude.com/docs/fr/build-with-claude/preserved-thinking), la réflexion de ces tours ne reste valide que si `system` et `tools` correspondent. La conversation de cet exemple n'a ni invite `system` ni outils, la requête n'envoie donc ni l'un ni l'autre :

<CodeGroup>
  ```bash cURL
  # max_tokens plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
  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 plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
  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 plafonne l'appel entier, réflexion comprise, prévoyez donc plusieurs milliers de tokens.
      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 plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
    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 plafonne l'appel entier, réflexion comprise, prévoyez donc plusieurs milliers de tokens.
      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 plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
  	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 plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
          .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 plafonne l'appel entier, réflexion comprise ; prévoyez donc plusieurs milliers de tokens.
      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 plafonne l'appel entier, réflexion comprise, prévoyez donc plusieurs milliers de tokens.
    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 }]
  }
}
```

L'appel de résumé utilise le modèle, `system`, `tools`, les paramètres de réflexion et `max_tokens` de la requête. Le résumeur lit les définitions d'outils mais n'exécute jamais d'outil, et la réponse ne contient aucune réflexion. `max_tokens` plafonne l'ensemble de l'appel, y compris toute réflexion effectuée par le modèle avant d'écrire le résumé ; prévoyez donc plusieurs milliers de tokens. [Comptabiliser l'utilisation de la compaction](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#understanding-usage) montre comment l'appel est facturé.

Si le dernier tour `assistant` se termine par un appel d'outil qui n'a pas encore de résultat, l'API rejette la requête. Envoyez d'abord les résultats d'outils de ce tour. Omettez également `stop_sequences`, le `output_config.format` des sorties structurées, et un `tool_choice` de type `any` ou `tool`. Ils n'auraient aucun effet sur un appel de résumé, et l'API les rejette. La conversation doit toujours tenir dans la « context window » (fenêtre de contexte) du modèle ; compactez donc avant de la dépasser, et non après.

Lorsque vous recevez la réponse en « streaming » (flux), le bloc arrive en entier. Vous recevez un événement `content_block_start` contenant le bloc complet, puis `content_block_stop`, sans aucun événement `content_block_delta`. Des événements `ping` peuvent arriver avant ou entre eux.

## Poursuivre à partir du résumé

Dans votre historique, remplacez les messages que vous avez envoyés par le message assistant renvoyé. Conservez le bloc `compaction` exactement tel que l'API l'a renvoyé, y compris sa `signature`. Les tours effectués après l'envoi de la requête de compaction suivent le bloc sans modification, ce sur quoi s'appuie la [Compaction en arrière-plan](https://platform.claude.com/docs/fr/build-with-claude/compaction-background). Envoyez le bloc en premier dans chaque requête ultérieure, avec l'en-tête bêta :

```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." }
  ]
}
```

Cet exemple poursuit l'exemple de requête, qui se terminait par un tour `user` ; le diagramme montre le cas plus simple, où aucun tour n'est effectué pendant la rédaction du résumé. Ici, le second message `assistant` est la réponse au dernier tour `user` résumé. Il est arrivé pendant la rédaction du résumé, il ne faisait donc pas partie des messages résumés. Deux messages `assistant` consécutifs ne posent pas de problème ici, car le bloc vient toujours en premier.

L'API place le résumé à l'emplacement du bloc et transmet chaque message ultérieur à Claude sans modification. Respectez ces règles :

* Placez le bloc en premier dans `messages`, soit comme un message `assistant` à part entière, soit comme premier bloc de contenu du premier message, qu'il s'agisse d'un message `user` ou `assistant`.
* Supprimez les messages résumés. S'il en reste devant le bloc, la requête renvoie une erreur 400 (`compaction_block_misplaced`).
* Envoyez exactement un bloc `compaction` par requête, dans chaque requête ultérieure.

<Warning>
  Deux oublis lors du remplacement ne provoquent aucune erreur. Si des messages résumés restent après le bloc, l'API les envoie de nouveau à Claude. Si une requête ultérieure omet le bloc, Claude ne reçoit aucun résumé.
</Warning>

La compaction par seuil fonctionne à l'inverse : son bloc suit les messages qu'il résume, et l'API les supprime pour vous. Consultez [Renvoyer les blocs de compaction](https://platform.claude.com/docs/fr/build-with-claude/compaction-threshold#passing-compaction-blocks-back).

En Python, utilisez `client.beta.messages`, comme le font les exemples de cette page. Si vous appelez `client.messages` et sérialisez vous-même les blocs, utilisez `to_dict()` ou `model_dump(exclude_none=True)` : un simple `model_dump()` ajoute `citations: null` et `text: null` au bloc, et l'API le rejette.

Si vous conservez des tours après le bloc et renvoyez leurs blocs de réflexion, les conditions qui maintiennent la validité de cette réflexion sont décrites dans [Compaction et réflexion préservée](https://platform.claude.com/docs/fr/build-with-claude/compaction-thinking-blocks).

### Compacter à nouveau

Pour compacter une conversation qui commence déjà par un bloc, envoyez de nouveau `compaction`. Le nouveau bloc résume l'ancien résumé et tout ce qui le suit. Dès lors, n'envoyez que le bloc le plus récent.

## Compacter dans une boucle

Après chaque tour, la boucle additionne les tokens d'entrée et de sortie de la dernière réponse, car la requête suivante envoie aussi la réponse. Lorsque ce total dépasse une limite et qu'un autre tour reste à venir, elle envoie une requête de compaction avec le même modèle et la même invite `system`, vérifie `stop_reason`, remplace son historique par le message renvoyé, et affiche le tour avant lequel elle a compacté. La limite de 2 500 tokens de l'exemple est volontairement basse, afin qu'une courte conversation soit compactée. Fixez la vôtre près de votre budget d'entrée réel.

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

  client = anthropic.Anthropic()

  # Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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})

      # La prochaine requête envoie aussi cette réponse, comptez-la donc.
      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();

  // Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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 });

    // La requête suivante envoie aussi cette réponse, comptez-la donc.
    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();

  // Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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(),
      });

      // La requête suivante envoie aussi cette réponse, comptez-la donc.
      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()

  // Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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())

  	// La requête suivante envoie aussi cette réponse, comptez-la donc.
  	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;

  // Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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());

          // La requête suivante envoie aussi cette réponse, comptez-la donc.
          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();

  // Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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);

      // La requête suivante envoie aussi cette réponse, comptez-la donc.
      $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

  # Définissez cette valeur près de votre budget d'entrée réel. Elle est basse ici pour qu'une courte conversation soit compactée.
  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 }

    # La requête suivante envoie aussi cette réponse, comptez-la donc.
    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>

La vérification de `stop_reason` intervient avant que le code ne recherche le bloc ; [Gérer un résumé manquant ou une erreur](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#when-no-summary-comes-back) explique pourquoi. L'historique est remplacé, et non complété : le message renvoyé remplace chaque message que contenait la requête, selon les règles de [Poursuivre à partir du résumé](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#continue-from-the-summary). Lorsqu'aucun résumé n'est renvoyé, la boucle conserve son historique et redemande après le tour suivant.

Le [tool runner](https://platform.claude.com/docs/fr/agents-and-tools/tool-use/tool-runner) (exécuteur d'outils) des SDK en Python, TypeScript, C#, Go, Java, PHP et Ruby peut envoyer la requête de compaction pour vous. Lorsque vous décidez de compacter, appelez `compact_before_next_turn()` (typescript, java, php: `compactBeforeNextTurn()`; csharp, go: `CompactBeforeNextTurn()`) sur l'exécuteur. Une fois le tour en cours et ses appels d'outils terminés, l'exécuteur envoie la requête de compaction et remplace son historique par le message renvoyé. Créez l'exécuteur avec la bêta `compact-2026-09-04`, car l'exécuteur ne l'ajoute pas.

L'exécuteur construit la requête de compaction à partir de ses propres paramètres et omet `context_management`. Il omet également `stop_sequences`, un `tool_choice` de type `any` ou `tool`, et un `output_config.format` de sortie structurée, que l'API rejette sur une requête de compaction. [Demander un résumé](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#request-a-summary) explique pourquoi. L'exécuteur les renvoie dans ses requêtes ultérieures. Les versions du SDK antérieures à Python 1.8.0, TypeScript 0.128.0, C# 12.50.0, Go 1.75.0 et Java 2.65.0 les envoient aussi sur la requête de compaction. Sur ces versions, un exécuteur qui définit l'un de ces paramètres reçoit une erreur 400. L'exécuteur envoie un [budget de tâche](https://platform.claude.com/docs/fr/build-with-claude/task-budgets) sans modification. Si `output_config.task_budget` définit `remaining`, la requête de compaction renvoie une erreur 400 ; laissez donc `remaining` non défini, comme l'indique [Limites et interactions avec d'autres fonctionnalités](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#how-it-fits-with-the-rest-of-the-api). L'exécuteur refuse de compacter tant que son `context_management` contient une édition de compaction ; utilisez donc un seul type de compaction par exécuteur.

### Quand compacter

Vous pouvez envoyer une requête de compaction après n'importe quel tour terminé ; c'est donc votre code qui décide du moment.

Pour estimer la taille de la prochaine requête, additionnez `input_tokens` et `output_tokens` du `usage` de la dernière réponse, comme le fait la boucle. Avec la [« prompt caching » (mise en cache des prompts)](https://platform.claude.com/docs/fr/build-with-claude/prompt-caching#tracking-cache-performance), `input_tokens` ne compte que les tokens situés après le dernier point d'arrêt du cache ; ajoutez donc également `cache_read_input_tokens` et `cache_creation_input_tokens`. Vous pouvez aussi envoyer les mêmes messages au point de terminaison de [« token counting » (comptage de tokens)](https://platform.claude.com/docs/fr/build-with-claude/token-counting).

Comparez ce nombre à une limite de votre choix, inférieure à la [fenêtre de contexte](https://platform.claude.com/docs/fr/build-with-claude/context-windows) du modèle.

## Rédiger votre propre prompt de résumé

Sans `instructions`, l'API utilise son propre prompt de résumé. Une chaîne `instructions` non vide (jusqu'à 16 384 caractères) remplace entièrement ce prompt. Par exemple :

```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."
  }
}
```

Le résumeur lit l'intégralité de la conversation, y compris la réflexion antérieure, avec ou sans `instructions`. Dans vos `instructions`, indiquez ce que le résumé doit conserver et demandez au modèle de ne pas appeler d'outils. L'appel de résumé s'exécute avec les mêmes garde-fous que toute autre requête.

## Gérer un résumé manquant ou une erreur

Un résumé n'est produit que lorsque l'appel de résumé se termine normalement avec du texte et sans appel d'outil. Sinon, la réponse reste un 200 avec un `content` vide ; vérifiez donc `stop_reason` avant de rechercher le bloc. L'appel est tout de même facturé et signalé dans `usage.iterations`, avec une utilisation nulle lorsqu'aucun appel n'a pu être effectué. Le `stop_reason` est celui par lequel l'appel de résumé s'est terminé. Dans tous les cas, vous pouvez continuer sans résumé et compacter plus tard.

| `stop_reason`                     | Cause                                                   | Que faire                                                                                       |
| --------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `"max_tokens"`                    | Le résumé a été tronqué.                                | Renvoyez la requête avec un `max_tokens` plus élevé.                                            |
| `"model_context_window_exceeded"` | Il n'y avait pas de place pour le prompt de résumé.     | Renvoyez la requête avec des `instructions` plus courtes ou moins de messages.                  |
| `"tool_use"`                      | Le modèle a appelé un outil au lieu d'écrire le résumé. | Renvoyez la requête avec des `instructions` qui demandent au modèle de ne pas appeler d'outils. |
| `"refusal"`                       | La requête a été refusée.                               | Continuez sans résumé.                                                                          |
| `"end_turn"`                      | L'appel n'a renvoyé aucun texte.                        | Continuez sans résumé.                                                                          |

L'appel de résumé est soumis aux mêmes garde-fous que vos autres requêtes. Après un `"refusal"`, [`stop_details`](https://platform.claude.com/docs/fr/build-with-claude/handling-stop-reasons#refusal) identifie la catégorie de politique à l'origine du refus.

### Erreurs

Une requête de compaction, ou une requête qui contient un bloc, peut aussi échouer purement et simplement. La plupart des erreurs 400 ont un message qui indique ce qu'il faut supprimer ou renvoyer. Certaines contiennent aussi un `error.details.error_code` qui commence par `compaction_`. Les erreurs de paramètres, comme un champ qui ne peut pas être combiné avec `compaction`, ne contiennent que le message.

| Erreur                                                                                                                                                                                                     | Cause                                                                                                                   | Que faire                                                                                                                                                                                             |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 529 `overloaded_error`, `error.details.error_code` `compaction_unavailable`                                                                                                                                | Un problème serveur transitoire lors de la production d'un bloc, ou lors de la lecture d'un bloc que vous avez renvoyé. | Réessayez la requête.                                                                                                                                                                                 |
| 400 `compaction_block_misplaced`                                                                                                                                                                           | Des messages résumés restent devant le bloc.                                                                            | Supprimez-les, afin que le bloc vienne en premier dans `messages`.                                                                                                                                    |
| 400 `compaction_signature_invalid` ou `compaction_content_mismatch`                                                                                                                                        | La `signature` ou le `content` du bloc a été modifié après que l'API l'a renvoyé.                                       | Envoyez le bloc exactement tel qu'il a été renvoyé, y compris sa `signature`.                                                                                                                         |
| 400                                                                                                                                                                                                        | La requête contient plus d'un bloc `compaction`.                                                                        | Envoyez-en exactement un, le plus récent.                                                                                                                                                             |
| 400                                                                                                                                                                                                        | Le dernier tour `assistant` se termine par un appel d'outil qui n'a pas encore de résultat.                             | Envoyez les résultats d'outils de ce tour, puis compactez.                                                                                                                                            |
| 400 `compaction_nothing_to_summarize`                                                                                                                                                                      | `messages` ne contient aucun contenu `user` ou `assistant`, par exemple une liste vide.                                 | Envoyez au moins un message `user` ou `assistant`.                                                                                                                                                    |
| 400 sur la requête de compaction, avec un message indiquant que le paramètre `compaction` `requires anthropic-beta: compact-2026-09-04`                                                                    | La requête de compaction a omis l'en-tête bêta.                                                                         | Ajoutez l'en-tête bêta ; consultez [Demander un résumé](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#request-a-summary).                                                |
| 400 sur une requête ultérieure qui contient le bloc : une erreur de validation indiquant que `compaction` ne fait pas partie des types de blocs de contenu attendus. Le message ne mentionne pas l'en-tête | Cette requête a omis l'en-tête bêta.                                                                                    | Ajoutez l'en-tête bêta à chaque requête qui contient le bloc ; consultez [Demander un résumé](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#request-a-summary).          |
| 400 erreur de validation, comme `messages.0.content.0.compaction.citations: Extra inputs are not permitted`                                                                                                | Un bloc a été renvoyé avec des champs que l'API n'avait pas renvoyés, comme `citations: null`.                          | Envoyez le bloc exactement tel qu'il a été renvoyé ; consultez [Poursuivre à partir du résumé](https://platform.claude.com/docs/fr/build-with-claude/compaction-on-demand#continue-from-the-summary). |

## Comptabiliser l'utilisation de la compaction

L'appel de résumé est facturé et soumis aux « rate limits » (limites de débit) comme toute autre requête, et `usage.iterations` le signale comme l'entrée `compaction`. Les `input_tokens` et `output_tokens` de premier niveau sont à zéro, car aucune réponse n'a été générée. Pour comptabiliser ce qu'une conversation a consommé, faites la somme sur `usage.iterations`, et non sur les champs de premier niveau. Renvoyer un bloc dans les requêtes ultérieures n'ajoute aucun coût de compaction.

Vous disposez d'une boucle fonctionnelle qui compacte une conversation et gère un résumé manquant. Deux pages modifient son fonctionnement, et vous pouvez les combiner : [Compaction qui conserve les tours récents](https://platform.claude.com/docs/fr/build-with-claude/compaction-keep-recent-turns) conserve les derniers tours mot pour mot, et [Compaction en arrière-plan](https://platform.claude.com/docs/fr/build-with-claude/compaction-background) permet à la conversation de se poursuivre pendant la rédaction du résumé. [Compaction et réflexion préservée](https://platform.claude.com/docs/fr/build-with-claude/compaction-thinking-blocks) s'applique si vous renvoyez des blocs de réflexion et utilisez l'une ou l'autre.

## Limites et interactions avec d'autres fonctionnalités

* **Compaction par seuil et édition du contexte.** Vous ne pouvez pas envoyer `compaction` et `context_management` dans la même requête. La compaction par seuil (`compact_20260112`) ne peut pas s'exécuter sur une requête qui contient un bloc signé.
* **Mise en cache des prompts.** `cache_control` sur le bloc place un point d'arrêt après le résumé.
* **Messages système en cours de conversation et modifications d'outils.** Les messages `role: "system"` situés dans la plage résumée sont également résumés ; leurs instructions textuelles cessent donc de s'appliquer une fois que le bloc les remplace. Un niveau d'[effort par message](https://platform.claude.com/docs/fr/build-with-claude/effort#change-effort-mid-conversation-beta) qu'ils définissent n'est pas non plus conservé : jusqu'à ce qu'un message ultérieur définisse un niveau, les tours s'exécutent avec le `output_config.effort` de premier niveau de la requête, ou avec la valeur par défaut du modèle si vous n'en définissez pas. Si une instruction ou un niveau d'effort reste important, énoncez-le à nouveau dans un message `role: "system"`. Envoyez ce message juste après votre prochain nouveau tour `user`, et conservez-le ensuite dans votre historique. Pour les [modifications d'outils](https://platform.claude.com/docs/fr/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes), et pour savoir où placer ce message lorsque vous conservez des tours après le bloc, consultez [Modifier l'invite système ou les outils](https://platform.claude.com/docs/fr/build-with-claude/compaction-thinking-blocks#change-the-system-prompt-or-tools).
* **Budgets de tâche.** N'envoyez pas la valeur `remaining` d'un [budget de tâche](https://platform.claude.com/docs/fr/build-with-claude/task-budgets) (`output_config.task_budget.remaining`) avec `compaction` ni dans les requêtes qui contiennent le bloc. Cela renvoie une erreur 400.
* **Comptage de tokens.** Le point de terminaison de [comptage de tokens](https://platform.claude.com/docs/fr/build-with-claude/token-counting) ignore le paramètre `compaction`.
* **Contenu que le résumé ne peut pas transporter.** Les images, les documents, les blocs `container_upload` et les URL récupérées dans les messages résumés disparaissent une fois que le bloc les remplace. Reformulez ou téléversez de nouveau tout ce dont un tour ultérieur a encore besoin.
