---
title: Compactación bajo demanda
url: https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand
description: Pide a Claude que resuma una conversación cuando tu aplicación lo decida y luego continúa a partir del resumen.
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" (compactación bajo demanda), tu aplicación decide cuándo se resume una conversación: envías una solicitud con el parámetro `compaction` y Claude devuelve un resumen en lugar de una respuesta.

## Cómo funciona la compactación bajo demanda

Una solicitud de compactación es independiente de los turnos de tu conversación. Envías la conversación tal como está con el parámetro `compaction`, y la respuesta contiene un único bloque `compaction`. El bloque contiene el resumen como texto que puedes leer, y una firma. Envíalo en solicitudes futuras exactamente como llegó.

A partir de entonces, el bloque ocupa el lugar de los mensajes que resume. Va primero en `messages`, los mensajes resumidos se eliminan y tu siguiente turno va después de él. Claude ve el resumen donde estaban esos mensajes.

<Frame>
  ![On-demand compaction (compactación bajo demanda): una solicitud que lleva cuatro mensajes y el parámetro compaction devuelve un bloque compaction y ninguna respuesta; en la siguiente solicitud, el bloque va primero en messages en lugar de esos cuatro mensajes, seguido del siguiente turno del usuario](https://platform.claude.com/docs/es/images/compaction-on-demand-swap.svg)
</Frame>

## Solicitar un resumen

Envía el encabezado beta `compact-2026-09-04` en la solicitud que pide el resumen y en cada solicitud posterior que lleve el bloque firmado. Para comprobar si un modelo admite la compactación bajo demanda, llama a la [API de Models](https://platform.claude.com/docs/es/api/beta/models/list) con el encabezado beta y lee el `capabilities.compaction` de cada modelo. No puedes combinar `compaction` con `context_management` en una misma solicitud.

Envía la conversación tal como está con `"compaction": {"type": "summarize"}`. La API resume todos los mensajes de la solicitud una sola vez, no genera ninguna respuesta después y devuelve solo el bloque con `stop_reason` `"compaction"`. Envía el mismo "system prompt" (indicación del sistema) en `system` y las mismas `tools` que usas para el resto de la conversación. El resumidor los lee, y si conservas turnos después del bloque en un modelo con ["preserved thinking" (pensamiento preservado)](https://platform.claude.com/docs/es/build-with-claude/preserved-thinking), el pensamiento de esos turnos sigue siendo válido solo si `system` y `tools` coinciden. La conversación de este ejemplo no tiene indicación del sistema en `system` ni herramientas, así que la solicitud no envía ninguna de las dos:

<CodeGroup>
  ```bash cURL
  # max_tokens limita toda la llamada, incluido cualquier pensamiento, así que permite varios miles 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 limita toda la llamada, incluido cualquier pensamiento, así que permite varios miles 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 limita toda la llamada, incluido cualquier pensamiento, así que permite varios miles 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 limita toda la llamada, incluido el pensamiento, así que permite varios miles 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 limita toda la llamada, incluido cualquier pensamiento, así que permite varios miles 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 limita toda la llamada, incluido el pensamiento, así que permite varios miles 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 limita toda la llamada, incluido el pensamiento, así que permite varios miles 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 limita toda la llamada, incluido el pensamiento, así que permite varios miles 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 limita toda la llamada, incluido cualquier pensamiento, así que permite varios miles 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 }]
  }
}
```

La llamada de resumen usa el modelo, `system`, `tools`, la configuración de pensamiento y `max_tokens` de la solicitud. El resumidor lee las definiciones de herramientas pero nunca ejecuta una herramienta, y la respuesta no incluye pensamiento. `max_tokens` limita toda la llamada, incluido cualquier pensamiento que el modelo realice antes de escribir el resumen, así que permite varios miles de tokens. [Contar el uso de la compactación](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#understanding-usage) muestra cómo se factura la llamada.

Si el último turno de `assistant` termina en una llamada a herramienta que aún no tiene resultado, la API rechaza la solicitud. Envía primero los resultados de herramientas de ese turno. Omite también `stop_sequences`, el `output_config.format` de salida estructurada y un `tool_choice` de tipo `any` o `tool`. No tendrían ningún efecto en una llamada de resumen, y la API los rechaza. La conversación aún debe caber en la "context window" (ventana de contexto) del modelo, así que compacta antes de superarla, no después.

Cuando haces streaming de la respuesta, el bloque llega completo. Recibes un evento `content_block_start` que lleva el bloque completo, luego `content_block_stop`, sin eventos `content_block_delta`. Los eventos `ping` pueden llegar antes o entre ellos.

## Continuar a partir del resumen

En tu historial, reemplaza los mensajes que enviaste con el mensaje de asistente devuelto. Conserva el bloque `compaction` exactamente como lo devolvió la API, incluida su `signature`. Cualquier turno realizado después de que enviaste la solicitud de compactación va después del bloque sin cambios, que es en lo que se basa [Compactación en segundo plano](https://platform.claude.com/docs/es/build-with-claude/compaction-background). Envía el bloque primero en cada solicitud posterior, con el encabezado 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." }
  ]
}
```

Este ejemplo continúa el ejemplo de solicitud, que terminó en un turno de `user`; el diagrama muestra el caso más simple, en el que no se realiza ningún turno mientras se escribe el resumen. Aquí el segundo mensaje de `assistant` es la respuesta al último turno de `user` resumido. Llegó mientras se escribía el resumen, por lo que no estaba entre los mensajes resumidos. Dos mensajes de `assistant` seguidos no son un problema aquí, porque el bloque sigue yendo primero.

La API coloca el resumen donde está el bloque y pasa cada mensaje posterior a Claude sin cambios. Sigue estas reglas:

* Coloca el bloque primero en `messages`, ya sea como un mensaje de `assistant` independiente o como el primer bloque de contenido del primer mensaje, ya sea este un mensaje de `user` o de `assistant`.
* Elimina los mensajes resumidos. Si alguno permanece delante del bloque, la solicitud devuelve un error 400 (`compaction_block_misplaced`).
* Envía exactamente un bloque `compaction` por solicitud, en cada solicitud posterior.

<Warning>
  Dos fallos al hacer el intercambio no generan ningún error. Si quedan mensajes resumidos después del bloque, la API los envía a Claude de nuevo. Si una solicitud posterior omite el bloque, Claude no recibe ningún resumen.
</Warning>

La "threshold compaction" (compactación por umbral) funciona al revés: su bloque va después de los mensajes que resume, y la API los descarta por ti. Consulta [Devolver los bloques de compactación](https://platform.claude.com/docs/es/build-with-claude/compaction-threshold#passing-compaction-blocks-back).

En Python, usa `client.beta.messages`, como hacen los ejemplos de esta página. Si llamas a `client.messages` y serializas los bloques tú mismo, usa `to_dict()` o `model_dump(exclude_none=True)`: un `model_dump()` simple añade `citations: null` y `text: null` al bloque, y la API lo rechaza.

Si conservas turnos después del bloque y devuelves sus bloques de pensamiento, las condiciones que mantienen válido ese pensamiento se describen en [Compactación y pensamiento preservado](https://platform.claude.com/docs/es/build-with-claude/compaction-thinking-blocks).

### Compactar de nuevo

Para compactar una conversación que ya comienza con un bloque, envía `compaction` de nuevo. El nuevo bloque resume el resumen anterior y todo lo que viene después. A partir de entonces, envía solo el bloque más reciente.

## Compactar en un bucle

Después de cada turno, el bucle suma los tokens de entrada y de salida de la última respuesta, porque la siguiente solicitud también envía la respuesta. Cuando ese total supera un límite y aún queda otro turno por delante, envía una solicitud de compactación con el mismo modelo y la misma indicación del sistema en `system`, comprueba `stop_reason`, reemplaza su historial con el mensaje devuelto e imprime el turno antes del cual compactó. El límite de 2,500 tokens del ejemplo es deliberadamente bajo, para que una conversación corta se compacte. Establece el tuyo cerca de tu presupuesto real de entrada.

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

  client = anthropic.Anthropic()

  # Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
      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();

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
    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();

  // Configura esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
      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()

  // Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
  	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;

  // Configura esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
          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();

  // Configura esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
      $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

  # Ajusta esto cerca de tu presupuesto real de entrada. Aquí es bajo para que una conversación corta se compacte.
  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 siguiente solicitud también envía esta respuesta, así que cuéntala.
    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 comprobación de `stop_reason` va antes de que el código busque el bloque; [Manejar un resumen faltante o un error](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#when-no-summary-comes-back) explica por qué. El historial se reemplaza, no se amplía: el mensaje devuelto reemplaza todos los mensajes que llevaba la solicitud, según las reglas de [Continuar a partir del resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#continue-from-the-summary). Cuando no se devuelve ningún resumen, el bucle conserva su historial y vuelve a pedirlo después del siguiente turno.

El [tool runner](https://platform.claude.com/docs/es/agents-and-tools/tool-use/tool-runner) (ejecutor de herramientas) del SDK en Python, TypeScript, C#, Go, Java, PHP y Ruby puede enviar la solicitud de compactación por ti. Cuando decidas compactar, llama a `compact_before_next_turn()` (typescript, java, php: `compactBeforeNextTurn()`; csharp, go: `CompactBeforeNextTurn()`) en el ejecutor. Una vez que terminan el turno actual y sus llamadas a herramientas, el ejecutor envía la solicitud de compactación y reemplaza su historial por el mensaje devuelto. Crea el ejecutor con la beta `compact-2026-09-04`, porque el ejecutor no la añade.

El ejecutor construye la solicitud de compactación a partir de sus propios parámetros y omite `context_management`. También omite `stop_sequences`, un `tool_choice` de tipo `any` o `tool` y un `output_config.format` de salida estructurada, que la API rechaza en una solicitud de compactación. [Solicitar un resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#request-a-summary) explica por qué. El ejecutor los vuelve a enviar en sus solicitudes posteriores. Las versiones del SDK anteriores a Python 1.8.0, TypeScript 0.128.0, C# 12.50.0, Go 1.75.0 y Java 2.65.0 también los envían en la solicitud de compactación. En esas versiones, un ejecutor que establece cualquiera de estos parámetros recibe un error 400. El ejecutor envía un [presupuesto de tarea](https://platform.claude.com/docs/es/build-with-claude/task-budgets) sin cambios. Si `output_config.task_budget` establece `remaining`, la solicitud de compactación devuelve un error 400, así que deja `remaining` sin establecer, como indica [Límites e interacciones con otras funciones](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#how-it-fits-with-the-rest-of-the-api). El ejecutor se niega a compactar mientras su `context_management` tenga una edición de compactación, así que usa un solo tipo de compactación en cada ejecutor.

### Cuándo compactar

Puedes enviar una solicitud de compactación después de cualquier turno completado, así que tu código decide cuándo hacerlo.

Para estimar qué tan grande será la siguiente solicitud, suma `input_tokens` y `output_tokens` del `usage` de la última respuesta, como hace el bucle. Con el ["prompt caching" (almacenamiento en caché de prompts)](https://platform.claude.com/docs/es/build-with-claude/prompt-caching#tracking-cache-performance), `input_tokens` cuenta solo los tokens posteriores al último punto de interrupción de caché, así que suma también `cache_read_input_tokens` y `cache_creation_input_tokens`. También puedes enviar los mismos mensajes al endpoint de [conteo de tokens](https://platform.claude.com/docs/es/build-with-claude/token-counting).

Compara ese número con un límite que elijas, por debajo de la [ventana de contexto](https://platform.claude.com/docs/es/build-with-claude/context-windows) del modelo.

## Escribir tu propio prompt de resumen

Sin `instructions`, la API usa su propio prompt de resumen. Una cadena `instructions` no vacía (de hasta 16,384 caracteres) reemplaza ese prompt por completo. Por ejemplo:

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

El resumidor lee toda la conversación, incluido el pensamiento anterior, con o sin `instructions`. En tus `instructions`, indica lo que el resumen debe conservar y dile al modelo que no llame a herramientas. La llamada de resumen se ejecuta bajo las mismas salvaguardas que cualquier otra solicitud.

## Manejar un resumen faltante o un error

Solo se produce un resumen cuando la llamada de resumen termina normalmente con texto y sin ninguna llamada a herramienta. De lo contrario, la respuesta sigue siendo un 200 con `content` vacío, así que comprueba `stop_reason` antes de buscar el bloque. La llamada se factura de todos modos y se informa en `usage.iterations`, con uso cero cuando no se pudo realizar ninguna llamada. El `stop_reason` es aquel con el que terminó la llamada de resumen. En todos los casos puedes continuar sin un resumen y compactar más tarde.

| `stop_reason`                     | Causa                                                              | Qué hacer                                                                                 |
| --------------------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
| `"max_tokens"`                    | El resumen quedó cortado.                                          | Vuelve a enviar con un `max_tokens` mayor.                                                |
| `"model_context_window_exceeded"` | No había espacio para el prompt de resumen.                        | Vuelve a enviar con `instructions` más cortas o menos mensajes.                           |
| `"tool_use"`                      | El modelo llamó a una herramienta en lugar de escribir el resumen. | Vuelve a enviar con `instructions` que le indiquen al modelo que no llame a herramientas. |
| `"refusal"`                       | La solicitud fue rechazada.                                        | Continúa sin un resumen.                                                                  |
| `"end_turn"`                      | La llamada no devolvió texto.                                      | Continúa sin un resumen.                                                                  |

La llamada de resumen está sujeta a las mismas salvaguardas que tus otras solicitudes. Después de un `"refusal"`, [`stop_details`](https://platform.claude.com/docs/es/build-with-claude/handling-stop-reasons#refusal) identifica la categoría de política que lo motivó.

### Errores

Una solicitud de compactación, o una solicitud que lleva un bloque, también puede fallar directamente. La mayoría de los errores 400 tienen un mensaje que indica qué eliminar o volver a enviar. Algunos también llevan un `error.details.error_code` que comienza con `compaction_`. Los errores de parámetros, como un campo que no se puede combinar con `compaction`, llevan solo el mensaje.

| Error                                                                                                                                                                                              | Causa                                                                                           | Qué hacer                                                                                                                                                                                      |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 529 `overloaded_error`, `error.details.error_code` `compaction_unavailable`                                                                                                                        | Un problema transitorio del servidor al producir un bloque, o al leer uno que devolviste.       | Reintenta la solicitud.                                                                                                                                                                        |
| 400 `compaction_block_misplaced`                                                                                                                                                                   | Quedan mensajes resumidos delante del bloque.                                                   | Elimínalos, para que el bloque vaya primero en `messages`.                                                                                                                                     |
| 400 `compaction_signature_invalid` o `compaction_content_mismatch`                                                                                                                                 | La `signature` o el `content` del bloque se modificó después de que la API lo devolviera.       | Envía el bloque exactamente como se devolvió, incluida su `signature`.                                                                                                                         |
| 400                                                                                                                                                                                                | La solicitud lleva más de un bloque `compaction`.                                               | Envía exactamente uno, el más reciente.                                                                                                                                                        |
| 400                                                                                                                                                                                                | El último turno de `assistant` termina en una llamada a herramienta que aún no tiene resultado. | Envía los resultados de herramientas de ese turno y luego compacta.                                                                                                                            |
| 400 `compaction_nothing_to_summarize`                                                                                                                                                              | `messages` no tiene contenido de `user` ni de `assistant`, por ejemplo, una lista vacía.        | Envía al menos un mensaje de `user` o de `assistant`.                                                                                                                                          |
| 400 en la solicitud de compactación, con un mensaje que dice que el parámetro `compaction` `requires anthropic-beta: compact-2026-09-04`                                                           | La solicitud de compactación omitió el encabezado beta.                                         | Añade el encabezado beta; consulta [Solicitar un resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#request-a-summary).                                       |
| 400 en una solicitud posterior que lleva el bloque: un error de validación que dice que `compaction` no es uno de los tipos de bloque de contenido esperados. El mensaje no menciona el encabezado | Esa solicitud omitió el encabezado beta.                                                        | Añade el encabezado beta a cada solicitud que lleve el bloque; consulta [Solicitar un resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#request-a-summary).  |
| Error de validación 400, como `messages.0.content.0.compaction.citations: Extra inputs are not permitted`                                                                                          | Se envió de vuelta un bloque con campos que la API no había devuelto, como `citations: null`.   | Envía el bloque exactamente como se devolvió; consulta [Continuar a partir del resumen](https://platform.claude.com/docs/es/build-with-claude/compaction-on-demand#continue-from-the-summary). |

## Contar el uso de la compactación

La llamada de resumen se factura y está sujeta a "rate limits" (límites de velocidad) como cualquier otra solicitud, y `usage.iterations` la informa como la entrada `compaction`. Los `input_tokens` y `output_tokens` de nivel superior son cero porque no se generó ninguna respuesta. Para contar lo que consumió una conversación, suma los valores de `usage.iterations`, no los campos de nivel superior. Devolver un bloque en solicitudes posteriores no añade ningún costo de compactación.

Ya tienes un bucle funcional que compacta una conversación y maneja un resumen faltante. Dos páginas cambian su funcionamiento, y puedes combinarlas: [Compactación que conserva los turnos recientes](https://platform.claude.com/docs/es/build-with-claude/compaction-keep-recent-turns) conserva los últimos turnos palabra por palabra, y [Compactación en segundo plano](https://platform.claude.com/docs/es/build-with-claude/compaction-background) permite que la conversación continúe mientras se escribe el resumen. [Compactación y pensamiento preservado](https://platform.claude.com/docs/es/build-with-claude/compaction-thinking-blocks) aplica si devuelves bloques de pensamiento y haces cualquiera de las dos cosas.

## Límites e interacciones con otras funciones

* **Compactación por umbral y edición de contexto.** No puedes enviar `compaction` y `context_management` en la misma solicitud. La compactación por umbral (`compact_20260112`) no puede ejecutarse en una solicitud que lleve un bloque firmado.
* **Almacenamiento en caché de prompts.** `cache_control` en el bloque coloca un punto de interrupción después del resumen.
* **Mensajes del sistema a mitad de la conversación y cambios de herramientas.** Los mensajes `role: "system"` dentro del rango resumido también se resumen, así que sus instrucciones de texto dejan de aplicarse una vez que el bloque los reemplaza. Tampoco se conserva un nivel de [esfuerzo por mensaje](https://platform.claude.com/docs/es/build-with-claude/effort#change-effort-mid-conversation-beta) que hayan establecido: hasta que un mensaje posterior establezca un nivel, los turnos se ejecutan con el `output_config.effort` de nivel superior de la solicitud, o con el valor predeterminado del modelo si no estableces uno. Si una instrucción o un nivel de esfuerzo sigue siendo importante, vuelve a indicarlo en un mensaje `role: "system"`. Envía ese mensaje justo después de tu siguiente turno nuevo de `user` y déjalo en tu historial a partir de entonces. Para los [cambios de herramientas](https://platform.claude.com/docs/es/build-with-claude/mid-conversation-system-messages#mid-conversation-tool-changes), y para saber dónde va ese mensaje cuando conservas turnos después del bloque, consulta [Cambiar la indicación del sistema o las herramientas](https://platform.claude.com/docs/es/build-with-claude/compaction-thinking-blocks#change-the-system-prompt-or-tools).
* **Presupuestos de tarea.** No envíes el valor `remaining` de un [presupuesto de tarea](https://platform.claude.com/docs/es/build-with-claude/task-budgets) (`output_config.task_budget.remaining`) con `compaction` ni en solicitudes que lleven el bloque. Hacerlo devuelve un error 400.
* **Conteo de tokens.** El endpoint de [conteo de tokens](https://platform.claude.com/docs/es/build-with-claude/token-counting) ignora el parámetro `compaction`.
* **Contenido que el resumen no puede conservar.** Las imágenes, los documentos, los bloques `container_upload` y las URL obtenidas dentro de los mensajes resumidos desaparecen una vez que el bloque los reemplaza. Vuelve a indicar o a subir cualquier cosa que un turno posterior todavía necesite.
