Blog • AI / API

Nouveautés Claude API 2026 : qu’est-ce que Conversation Compaction ? Comment un AI Agent persiste-t-il le long contexte et l’état compacté en JSON ?

Plus un Agent tourne longtemps, plus le tableau Messages s’allonge. Résultats d’outils, blocs de pensée, allers-retours user : tout ça finit par remplir la fenêtre de contexte. En 2026, Messages API en a fait une capacité officielle : Conversation Compaction.

Compaction, ce n’est pas écrire un résumé côté client et le recoller. L’API émet un bloc type: "compaction" en JSON. La requête suivante doit remettre ce bloc tel quel dans messages, pour que la session continue depuis l’état compacté.

Cet article présente :

Retenez ceci : Ce que vous persistez n’est pas « tout le dialogue », mais le dernier bloc compaction, plus les tours derrière le bloc qui n’ont pas encore été absorbés. Dans le bloc, content, signature, encrypted_content sont un contrat, pas un commentaire. Ci-dessous : deux compressions → forme du bloc → liste à persister → règles de permutation.

Quelle tranche Compaction comprime

Le positionnement officiel est net : la compaction côté serveur est la pratique recommandée pour les longs dialogues et les workflows Agent, sans écrire soi-même le code de résumé côté client. Quand la fenêtre se remplit de vieux contenu, la qualité de réponse baisse ; la compaction remplace le plus ancien par un résumé, pour que le contexte utile puisse encore avancer. Voir

Claude API Compaction.

Une fois la compression par seuil ouverte, l’API fait quatre pas : les tokens d’entrée atteignent le seuil ; elle génère un résumé ; elle écrit un bloc compaction ; elle continue la réponse avec le contexte compacté. La fois suivante, vous ajoutez toute la réponse assistant dans messages, et l’API jette le contenu devant ce bloc pour reprendre depuis le résumé.

C’est lossy. Les arguments d’outils précis, les phrases d’origine, le thinking précoce ne restent pas mot à mot. Ce qui reste : les objectifs, les décisions, et les faits encore utiles ensuite. Ce n’est pas la même chose que « stocker tout le tableau messages en base ». Comment le contexte gonfle dans une pile Agent :

Pile AI Agent 2026.

Deux voies : compression par seuil et à la demande

En 2026 il y a deux beta. Ne les mélangez pas dans la même requête. Les docs le disent : le paramètre compaction ne peut pas partir avec context_management.

Voie En-tête beta Ce que vous écrivez dans le JSON Où le bloc apparaît
Compression par seuil compact-2026-01-12 context_management.edits : y ajouter compact_20260112 En tête d’une réponse normale ; text peut suivre
Compression à la demande compact-2026-09-04 Au sommet compaction: {"type":"summarize"} Une réponse à part, stop_reason vaut compaction, sans réponse normale

Le déclenchement de la compression par seuil vaut par défaut input_tokens150000, plancher 50000. Option pause_after_compaction : le résumé s’écrit, puis ça s’arrête, pour que vous réinsériez les derniers tours ou les messages d’instruction derrière le bloc, avant de continuer. Un instructions personnalisé remplace tout le prompt de résumé par défaut, 16384 caractères max.

La compression à la demande est le point de la ligne de septembre. Vous décidez quand compresser ; la requête de résumé peut tourner en arrière-plan, le dialogue continue avec l’historique complet ; vous pouvez aussi laisser les derniers tours en clair derrière le résumé. Le bloc signé doit être tout devant messages ; les messages déjà résumés doivent sortir de devant le bloc, sinon 400, nom d’erreur compaction_block_misplaced. Bedrock et Google Cloud n’ont pas cette voie à la demande.

Le Messages JSON avant et après compaction

D’abord avant compaction : de simples tours user / assistant.

Requête de compression à la demande (extrait des docs officiels)
{
  "model": "claude-opus-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."
    },
    {
      "role": "user",
      "content": "Good. Now suggest field names for Recipe."
    }
  ],
  "compaction": { "type": "summarize" }
}

La réponse n’a qu’un bloc compaction signé, stop_reason vaut compaction. Ensuite, à chaque requête, ce bloc doit être tout devant ; derrière, seulement les tours que ce résumé n’a pas absorbés.

Continuer après compaction : le bloc tout devant, les anciens messages déjà ôtés
{
  "model": "claude-opus-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...",
          "signature": "EuYBCkQY..."
        }
      ]
    },
    {
      "role": "assistant",
      "content": "For Recipe, use title, description, servings..."
    },
    {
      "role": "user",
      "content": "Now do the same for Ingredient."
    }
  ]
}

Le bloc de la compression par seuil est plus « coincé dans la réponse » : le tableau content de l’assistant commence par compaction, puis text. Après plusieurs compressions, c’est le dernier bloc qui compte : il représente l’état final du prompt actuel. Quand l’API voit ce bloc, elle ignore les blocs de contenu devant. Vous pouvez renvoyer le tout, ou jeter vous-même les anciens messages et n’envoyer qu’à partir de ce bloc.

Champ Ce que c’est Peut-on le modifier
type Fixe compaction Non
content Texte du résumé ; en échec, null Ne pas changer les mots ; chaîne vide illégale
signature Signature renvoyée par la compression à la demande À renvoyer tel quel
encrypted_content Métadonnées opaques ; le type SDK exige un aller-retour verbatim S’il est là, stockez-le tel quel, ne le parsez pas
cache_control Optionnel, un point de cache rien que pour le résumé Vous l’ajoutez ; ce n’est pas un champ émis

Le SDK décrit encrypted_content comme « métadonnées opaques laissées par une compaction précédente, à renvoyer verbatim ». Le client ne le démonte pas, et ne l’affiche pas comme corps de résumé. Quand le content d’un bloc en échec vaut null, le serveur le traite comme un no-op ; vous pouvez encore le renvoyer, mais ce n’est pas un résumé valide.

Champs à persister pour restaurer une session

Dès qu’un Agent redémarre, les messages en mémoire disparaissent. Ce que vous restaurez n’est pas « tout le chat d’avant compaction », c’est l’état qui permet encore de continuer les requêtes après compaction.

  1. 1
    Le dernier bloc compaction

    Le JSON du bloc entier, y compris content, signature, encrypted_content. S’il y en a plusieurs, seul le plus récent compte : une nouvelle compaction avale l’ancien résumé et le contenu derrière.

  2. 2
    Les messages derrière le bloc

    Les tours user / assistant que ce résumé n’a pas couverts, dans l’ordre d’origine. Les tours nés pendant une compression arrière-plan sont ici aussi.

  3. 3
    Le system et les tools de ce moment

    En compression à la demande, la requête de résumé doit porter le même system et les mêmes tools que le reste du dialogue. Sur les modèles qui gardent le thinking, que les thinking des tours derrière le bloc restent valides dépend de si ces deux-là ont changé, et si la queue touche encore les messages résumés.

  4. 4
    Quelle beta vous suivez

    La compression par seuil continue avec compact-2026-01-12. Un bloc de compression à la demande exige compact-2026-09-04 à chaque requête suivante. Mauvais en-tête, le bloc peut ne pas être reconnu.

Forme minimale de persistance d’une session (indicatif, pas le schema officiel)
{
  "beta": "compact-2026-09-04",
  "model": "claude-opus-5",
  "system": "You are a coding agent.",
  "tools": [],
  "compaction_block": {
    "type": "compaction",
    "content": "Summary of the conversation: ...",
    "signature": "EuYBCkQY...",
    "encrypted_content": "..."
  },
  "tail": [
    {
      "role": "assistant",
      "content": "For Recipe, use title, description..."
    },
    {
      "role": "user",
      "content": "Now do the same for Ingredient."
    }
  ]
}

Pour reconstruire la requête : messages[0] reçoit l’assistant qui porte ce bloc (ou vous mettez le bloc dans le premier content du premier message), puis vous concaténez tail. Ne remettez pas les anciens messages user d’avant compaction devant le bloc.

Ce n’est pas la même couche que l’évaluation des permissions. Là-bas, on décide si un Tool Call peut tourner ; ici, on décide si l’état existe encore après que la fenêtre a été absorbée. L’article permissions :

Comment Claude Managed Agents juge automatiquement un Tool Call. Comment les Agents collaborent sur un long flux :

Comment Claude participe au workflow de R&D IA.

Comment permuter en compression arrière-plan et keep-tail

Une requête de compression à la demande ne résume que les messages qu’elle a reçus. Vous pouvez donc n’envoyer que les vieux tours à compresser, garder les derniers tours en clair en local, puis insérer le bloc devant ces tours. Les docs appellent ça keep-tail.

La compression arrière-plan (async) va plus loin : pendant que le résumé tourne, le dialogue continue avec l’historique complet. Au retour, on ne remplace pas tout l’historique par un bloc : on ôte en tête de file « les messages envoyés à compresser à ce moment », on y met le message assistant renvoyé, et on laisse tels quels les tours nés derrière.

Permutation en compression arrière-plan (schéma officiel)
if response.stop_reason == "compaction":
    compaction_message = {
        "role": "assistant",
        "content": response.content,
    }
    history = [compaction_message] + history[sent_count:]
# sent_count = number of messages sent in the compaction request

Entre-temps, ne modifiez pas les messages déjà dans l’historique. La permutation doit avoir lieu sur la première requête après l’arrivée du bloc, pour que le thinking né pendant le résumé reste valide. Sans bloc de retour, gardez l’historique complet et réessayez plus tard.

Si la compression par seuil ouvre pause_after_compaction, la réponse n’a souvent que ce bloc, stop_reason vaut aussi compaction. Vous rattachez le texte à garder derrière le bloc, puis vous envoyez la requête suivante. Attention : sur Claude Fable 5.1, si vous réinsérez d’anciens tours assistant derrière le bloc, enlevez-en les thinking / redacted_thinking, ou portez thinking-binding-controls-2026-08-01 et réglez prefix_mismatch_behavior: "drop_block", sinon vous risquez un 400. Ces blocs de pensée ont été générés contre l’historique complet ; ils ne collent plus au dialogue compacté.

Comment ça se superpose au prompt cache

La compaction et le prompt caching peuvent coexister. Vous pouvez ajouter cache_control: {"type":"ephemeral"} sur le bloc compaction, pour que le résumé entre seul en cache. Un autre point de rupture en fin de system prompt : quand la compaction a lieu, le cache du system prompt tient encore, seule la tranche résumé se réécrit.

Pour la facturation, ne regardez pas seulement le usage de premier niveau. Les tokens des itérations de compaction peuvent être dans usage.iterations. Côté persistance, vous ne vous souciez toujours que du bloc et de la queue ; usage n’est pas le contrat pour restaurer la session.

Vérifier le bloc et l’historique dans JSONNote

Le volume JSON change beaucoup avant et après compaction, et l’œil ne suffit pas pour les champs. Au debug, alignez les positions, pas le style.

  1. 1
    D’abord formater le fichier persisté

    Jetez le session JSON dans Formateur JSON, vérifiez que compaction_block.type vaut compaction, et que signature est encore là.

  2. 2
    Puis valider la forme du bloc

    Avec JSON Schema, écrivez un schema minimal : l’enum de type n’a que compaction ; content accepte string ou null ; signature / encrypted_content s’ils sont là, traitez-les en string. Interdire la chaîne vide.

  3. 3
    Comparer messages avant et après compaction

    Avec JSON Diff, voyez quels tours ont disparu en tête de file, et ce qui s’est ajouté derrière le bloc. Après une compression à la demande, aucun message user déjà résumé ne doit réapparaître devant le bloc.

  4. 4
    Masquer la signature pour le retour d’expérience

    Le corps du résumé peut se montrer. Avant Partage Hash, masquez la signature et les champs opaques. Ils relancent la session ; ne les envoyez pas comme du texte ordinaire.

FAQ

Conversation Compaction, est-ce effacer tout le dialogue ?

Non. L’API remplace les anciens messages déjà compactés par un résumé. Le résumé est dans un bloc de contenu dont type est compaction. Vous devez renvoyer ce bloc tel quel, pour que la session continue depuis le résumé.

Quel JSON minimal pour restaurer une session ?

Au moins le dernier bloc compaction (avec content, signature, encrypted_content), tous les messages derrière le bloc, plus le system et les tools de ce moment. Sans la signature ou le champ opaque, la requête suivante ne se reconnecte pas.

Quelle différence entre la compression par seuil et la compression à la demande de septembre ?

La compression par seuil suit compact-2026-01-12 et se déclenche aux tokens dans une requête normale. La compression à la demande suit compact-2026-09-04 : vous envoyez à part compaction: {type: summarize}, recevez un bloc signé, à placer tout devant messages.

Un résumé écrit à la main peut-il remplacer un bloc compaction ?

Pas comme le même contrat. La plateforme reconnaît le bloc qu’elle a émis. Un texte user que vous écrivez n’est qu’un autre message, sans signature, et ne fait pas jeter à l’API le vieux contenu devant le bloc.

Peut-on modifier le content d’un bloc compaction avant de le renvoyer ?

Ne le modifiez pas. Les docs exigent un aller-retour tel quel. content en chaîne vide n’est pas légal ; content à null signifie un échec de compaction, le serveur le traite comme un no-op. Modifier signature ou encrypted_content fera échouer les requêtes suivantes ou perdra le résumé.

Résumé

Conversation Compaction range « la fenêtre va exploser » en un JSON renvoyable. La compression par seuil arrive toute seule dans une requête normale ; la compression à la demande de septembre vous laisse décider quand compresser, si ça peut tourner en arrière-plan, et si les derniers tours restent en clair.

Restaurer une session, c’est le dernier bloc compaction plus le tail derrière, pas le texte intégral d’avant compaction. content, signature, encrypted_content : stockez-les tels quels, renvoyez-les tels quels. Si le bloc est mal placé, l’API ne fera pas semblant que vous portez encore cet historique.

Lisez le bloc et le tail comme deux contrats. Pour une longue tâche qu’un humain doit surveiller, écrivez dans instructions du résumé les entités à garder et les questions ouvertes ; pour un Agent qui doit moins interrompre, permutez le bloc en arrière-plan via la compression à la demande, au lieu de ne garder en mémoire qu’une note que vous avez écrite.

← Retour au blog