Cap 26: API Fundamentals para Arquitectos

Por: Artiko
claude-apiextended-thinkingprompt-cachingtool-choice

Este tutorial cubre los conceptos de la API de Claude que el examen Claude Certified Architect – Foundations evalúa directamente y que los tutoriales anteriores no han cubierto en detalle.

1. Thinking adaptativo — razonamiento interno

El thinking permite que Claude genere tokens de razonamiento internos antes de producir su respuesta. En la generación vigente de modelos ese razonamiento se activa con thinking: { type: "adaptive" }: el modelo decide cuánto razonar según la dificultad de la tarea, sin que tú dimensiones un presupuesto fijo.

Regla de identificadores de modelo

Desde la generación 4.6 los IDs no llevan sufijo de fecha aunque siguen siendo snapshots pinneados. Nunca escribas fechas en claude-opus-4-8, claude-sonnet-5 ni claude-fable-5. Los alias de la API son opus → Opus 4.8 y sonnet → Sonnet 5.

budget_tokens está eliminado

thinking: { type: "enabled", budget_tokens: N } devuelve 400 en Fable 5, Opus 4.8, Opus 4.7 y Sonnet 5.

ModeloCómo se activa el razonamiento
claude-fable-5Thinking siempre activo; { type: "disabled" } devuelve 400
claude-opus-4-8, claude-opus-4-7{ type: "adaptive" }; aceptan { type: "disabled" } y, si se omite el campo, corren sin thinking
claude-sonnet-5{ type: "adaptive" } (thinking adaptativo por defecto)
claude-haiku-4-5Único de la tabla actual con extended thinking clásico (budget_tokens); no soporta adaptive
claude-opus-4-6, claude-sonnet-4-6budget_tokens sigue funcionando, pero deprecado

Thinking tokens vs Output tokens

TipoVisible al usuarioSe cobra como
thinkingNo por defecto (display: "omitted")Output tokens
text (output)Output tokens

Los thinking tokens se cobran igual que los output tokens. Subir el nivel de razonamiento sin necesidad sube el costo sin beneficio.

Árbol de decisión: razonamiento y esfuerzo

flowchart TD
    A[¿La tarea requiere razonamiento?] -->|No| B["Opus 4.8/4.7: omitir 'thinking'<br/>(corren sin thinking)"]
    A -->|Sí| C["thinking type adaptive"]
    C --> D{"¿Cuánta profundidad?"}
    D -->|"Extracción, clasificación,<br/>respuestas cortas"| E["output_config.effort: 'low' o 'medium'"]
    D -->|"Uso general"| F["output_config.effort: 'high' (default)"]
    D -->|"Coding y agentes"| G["output_config.effort: 'xhigh' (recomendado)"]
    D -->|"Problemas abiertos<br/>de máxima dificultad"| H["output_config.effort: 'max'"]
    C --> I{"¿Necesito ver el razonamiento?"}
    I -->|No| J["display: 'omitted' (default,<br/>bloques vacíos)"]
    I -->|Sí| K["display: 'summarized'"]

Cuándo subir el esfuerzo y cuándo no

Subir: análisis de trade-offs arquitectónicos, debugging de comportamiento inesperado, planificación de sistemas complejos, bucles agénticos de coding.

No subir: extracción de campos de un JSON, clasificación de texto, generación de código repetitivo, cualquier tarea donde la respuesta directa es suficiente.

Implementación

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// Caso de uso: analizar trade-offs de diseño
const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 16000,
  thinking: { type: "adaptive" },
  output_config: { effort: "xhigh" }, // GA, sin cabecera beta
  messages: [
    {
      role: "user",
      content:
        "Analiza los trade-offs entre PostgreSQL y DynamoDB para un sistema " +
        "de e-commerce con 10M usuarios, picos de 50k req/s en Black Friday " +
        "y necesidad de transacciones ACID en pedidos.",
    },
  ],
});

// Los bloques "thinking" llegan VACÍOS salvo que pidas display: "summarized"
for (const block of response.content) {
  if (block.type === "text") {
    console.log(block.text); // Esta es la respuesta final
  }
}

Ver el razonamiento: display

thinking.display vale "omitted" por defecto en Fable 5, Mythos 5, Opus 4.8/4.7 y Sonnet 5: los bloques thinking llegan vacíos. Para obtener razonamiento visible hay que pedirlo explícitamente:

const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 4096,
  thinking: { type: "adaptive", display: "summarized" },
  messages: [{ role: "user", content: "…" }],
});

Nota del examen: summarized devuelve un resumen del razonamiento. La cadena de pensamiento cruda nunca se devuelve por la API.


1b. output_config.effort — la palanca de razonamiento vs costo

El parámetro de esfuerzo es hoy el control principal de profundidad de razonamiento frente a costo, y sustituye funcionalmente tanto a budget_tokens como al viejo ajuste por temperature.

  • Va anidado en output_config, nunca como campo top-level.
  • Es GA: no requiere cabecera beta.
  • Valores: low | medium | high | xhigh | max.
  • Default high en Opus 4.8 (todas las superficies) y en Sonnet 5 (Claude API y Claude Code).
  • xhigh es el nivel recomendado para coding y agentes.
  • Opus 4.6 y Sonnet 4.6 no tienen xhigh.
const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 8192,
  thinking: { type: "adaptive" },
  output_config: { effort: "xhigh" },
  messages: [{ role: "user", content: "Refactoriza este módulo…" }],
});

2. Prompt Caching — reducir latencia y costo

Prompt caching permite que el servidor reutilice el procesamiento de un prefix del prompt entre llamadas consecutivas.

Cómo funciona

sequenceDiagram
    participant App
    participant API as Anthropic API
    participant Cache

    App->>API: Request 1 (system prompt largo + query)
    Note over API: Procesa todo el prefix
    API->>Cache: Guarda prefix en caché (TTL: ~5 min)
    API-->>App: Response 1 (latencia normal)

    App->>API: Request 2 (mismo system prompt + nueva query)
    API->>Cache: ¿Existe el prefix?
    Cache-->>API: HIT — recupera prefix procesado
    Note over API: Solo procesa la nueva query
    API-->>App: Response 2 (~90% menos latencia en prefix)

Marcado con cache_control

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// CLAUDE.md del proyecto (3000+ tokens, se repite en cada llamada de CI)
const projectContext = await Bun.file("CLAUDE.md").text();

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 2048,
  system: [
    {
      type: "text",
      text: projectContext,
      cache_control: { type: "ephemeral" }, // cachear este prefix
    },
  ],
  messages: [
    {
      role: "user",
      content: "¿Qué comando uso para iniciar el servidor de desarrollo?",
    },
  ],
});

Dónde colocar cache_control

Siempre en el último bloque estático antes de la parte dinámica. Si el caché se marca en el medio de una cadena que cambia, se invalida.

Posición correctaResultado
System prompt completo (estático)Cachea todo el system prompt
Documento grande en primer user messageCachea system + documento
Historial de conversación hasta N-1Cachea contexto acumulado

Advertencia: si el texto que marcas con cache_control cambia entre llamadas (aunque sea un carácter), el caché se invalida y vuelve a procesar completo.

Casos de uso ideales

  • CLAUDE.md largo en pipelines de CI que se ejecutan muchas veces
  • Base de conocimiento que se consulta en múltiples queries del mismo usuario
  • Contexto de proyecto estático en agentic loops largos

Impacto en métricas

  • Latencia: ~90% de reducción en el procesamiento del prefix cacheado
  • Costo de input: ~30–50% de reducción (los tokens cacheados tienen precio menor)
  • Costo de output: sin cambio

3. Sampling eliminado y salida estructurada

temperature, top_p y top_k ya no se aceptan

Los tres parámetros de sampling devuelven 400 en Fable 5, Opus 4.8 y Opus 4.7; en Sonnet 5 se rechaza cualquier valor que no sea el default. El comportamiento del modelo se dirige hoy por prompting, no por sampling.

ParámetroQué eraEstado en la generación vigente
temperatureAleatoriedad de la distribución de tokens400 en Fable 5, Opus 4.8 y Opus 4.7; valores no-default rechazados en Sonnet 5
top_pNucleus sampling: tokens hasta probabilidad acumulada pIgual que temperature
top_kSolo los k tokens más probables. Sí era un parámetro de la API de MessagesIgual que temperature

Corrección frecuente: top_k no era un parámetro “no expuesto” en la API de Claude. Existía como parámetro de sampling; lo que ocurre hoy es que fue eliminado en los modelos vigentes.

Nota histórica: en modelos legacy (Opus 4.5, Sonnet 4.5 y anteriores) sí se usaba temperature: 0 para acercarse al determinismo, sin garantía total por el paralelismo de punto flotante en hardware.

Qué se usa en su lugar

flowchart LR
    A1["temperature: 0<br/>para forzar JSON"] --> B1["output_config.format<br/>structured outputs"]
    A2["temperature baja<br/>para menos divagación"] --> B2["output_config.effort<br/>low o medium"]
    A3["budget_tokens alto<br/>para más razonamiento"] --> B3["output_config.effort<br/>xhigh o max"]
    A4["Prefill del turno assistant<br/>para forzar formato"] --> B4["structured outputs o<br/>instrucciones en el system prompt"]

Structured outputs (GA)

La API de structured outputs es GA y es el sustituto oficial tanto del prefill del turno assistant como del uso de temperature: 0 para forzar formato. Se configura con output_config.format:

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 512,
  output_config: {
    format: {
      type: "json_schema",
      schema: {
        type: "object",
        properties: {
          numero_factura: { type: "string" },
          total: { type: "number" },
          moneda: { type: "string" },
        },
        required: ["numero_factura", "total", "moneda"],
        additionalProperties: false,
      },
    },
  },
  messages: [{ role: "user", content: invoiceText }],
});
  • output_format (nombre antiguo) y la cabecera beta structured-outputs-2025-11-13 solo funcionan durante el periodo de transición. Lo vigente es output_config.format.
  • Para tools, el campo complementario es strict: true como campo top-level de la definición de la tool, que exige additionalProperties: false y required en el schema:
const extractInvoiceFieldsTool = {
  name: "extract_invoice_fields",
  description: "Extrae los campos estructurados de una factura",
  strict: true, // top-level, no dentro de input_schema
  input_schema: {
    type: "object",
    properties: {
      numero_factura: { type: "string" },
      total: { type: "number" },
    },
    required: ["numero_factura", "total"],
    additionalProperties: false,
  },
};

Clave para el examen: el prefill del turno assistant final está eliminado (devuelve 400) en Fable 5, Opus 4.6/4.7/4.8 y Sonnet 4.6/5. Si el material de estudio te propone prellenar {" en un mensaje assistant para forzar JSON, esa técnica ya no aplica: usa structured outputs o instrucciones en el system prompt.


4. tool_choice — control completo sobre ejecución de tools

Esta sección es crítica para el examen. El parámetro tool_choice controla si Claude puede, debe o no debe usar tools.

Los 4 modos

flowchart TD
    Q[¿Necesito que Claude use tools?] --> A{¿Cuánta certeza?}
    A -->|"No sé si la query\nnecesita tools"| M1["auto\nClaude decide"]
    A -->|"Debe usar alguna tool\npero no sé cuál"| M2["any\nAl menos una tool"]
    A -->|"Debe usar\nUNA tool específica"| M3["tool + name\nExactamente esa tool"]
    A -->|"No debe usar tools\nen este turno"| M4["none\nSolo texto"]

Tabla comparativa

ModoClaude puede responder sin toolClaude elige la toolError si no hay toolsUso típico
autoNoConversación general
anyNoSí (cualquiera)Forzar extracción
tool + nameNoNo (fija)Sí si no existeSchema específico
noneSí (siempre texto)N/ANoAnálisis sin acción

Modificador disable_parallel_tool_use

Además del modo, tool_choice admite disable_parallel_tool_use: true, que fuerza a Claude a emitir como máximo un bloque tool_use por turno:

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  tool_choice: { type: "any", disable_parallel_tool_use: true },
  tools: [extractContactTool, extractDateTool],
  messages: [{ role: "user", content: emailText }],
});

Restricción de plataforma: en Amazon Bedrock con Sonnet 5, un tool_choice forzado (any o tool) requiere enviar además thinking: { type: "disabled" }.

Implementaciones

// AUTO: Claude decide si usar tools o responder en texto
const autoResponse = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  tool_choice: { type: "auto" }, // default, puede omitirse
  tools: [searchTool, calculatorTool],
  messages: [{ role: "user", content: "¿Cuánto es 2+2?" }],
  // Claude puede responder "4" sin usar ninguna tool
});

// ANY: Claude DEBE usar al menos una tool
const anyResponse = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  tool_choice: { type: "any" },
  tools: [extractContactTool, extractDateTool],
  messages: [{ role: "user", content: emailText }],
  // Claude elegirá al menos una de las tools disponibles
});

// TOOL específica: Claude DEBE usar exactamente esta tool
const toolResponse = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  tool_choice: { type: "tool", name: "extract_invoice_fields" },
  tools: [extractInvoiceFieldsTool],
  messages: [{ role: "user", content: invoiceText }],
  // Claude usará extract_invoice_fields o error
});

// NONE: Deshabilita todos los tools aunque estén definidos
const noneResponse = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 1024,
  tool_choice: { type: "none" },
  tools: [deleteDatabaseTool], // definidas pero inaccesibles
  messages: [{ role: "user", content: "Analiza los riesgos de este plan" }],
  // Claude solo puede responder en texto — modo análisis puro
});

Errores comunes

  • Usar tool_choice: { type: "tool", name: "X" } con una tool que no está en la lista → error 400
  • Usar any sin tools definidas → error 400
  • Asumir que auto siempre llamará tools — puede responder en texto si considera que no necesita tools

5. Múltiples tool calls en un mismo turno

Claude puede emitir varios bloques tool_use en un solo turno. El desarrollador los ejecuta en paralelo y retorna todos los resultados en un único user message.

sequenceDiagram
    participant Dev as Desarrollador
    participant Claude

    Dev->>Claude: User message con query
    Claude-->>Dev: content: [tool_use(id=A), tool_use(id=B)]
    Note over Dev: Ejecuta tool A y tool B en paralelo
    Dev->>Claude: role:user, content: [tool_result(id=A), tool_result(id=B)]
    Claude-->>Dev: Respuesta final con ambos resultados

Código completo

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function runWithParallelTools(userQuery: string) {
  const response = await client.messages.create({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    tools: [weatherTool, stockPriceTool],
    messages: [{ role: "user", content: userQuery }],
  });

  if (response.stop_reason !== "tool_use") {
    return response.content[0];
  }

  // Recopilar todos los tool_use blocks
  const toolUseBlocks = response.content.filter(
    (b): b is Anthropic.ToolUseBlock => b.type === "tool_use"
  );

  // Ejecutar todas en paralelo
  const results = await Promise.all(
    toolUseBlocks.map(async (block) => {
      const output = await dispatchTool(block.name, block.input);
      return {
        type: "tool_result" as const,
        tool_use_id: block.id, // correlación crítica
        content: JSON.stringify(output),
      };
    })
  );

  // Retornar todos los resultados en un único mensaje
  const finalResponse = await client.messages.create({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    tools: [weatherTool, stockPriceTool],
    messages: [
      { role: "user", content: userQuery },
      { role: "assistant", content: response.content },
      { role: "user", content: results }, // todos los resultados juntos
    ],
  });

  return finalResponse.content[0];
}

Clave para el examen: cada tool_result debe tener el tool_use_id exacto del bloque correspondiente. Si los IDs no coinciden, la API retorna error 400.


6. Streaming responses

Cuándo usar streaming vs buffering

SituaciónModo recomendado
Interfaz de usuario en tiempo realStreaming
CLI con feedback visualStreaming
CI/CD, procesamiento batchBuffering
Cuando necesitas el response completo antes de actuarBuffering

Streaming básico con tool_use

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function streamWithTools(query: string) {
  const stream = await client.messages.stream({
    model: "claude-sonnet-5",
    max_tokens: 1024,
    tools: [searchTool],
    messages: [{ role: "user", content: query }],
  });

  let currentToolInput = "";
  let currentToolId = "";
  let currentToolName = "";

  for await (const event of stream) {
    switch (event.type) {
      case "content_block_start":
        if (event.content_block.type === "tool_use") {
          currentToolId = event.content_block.id;
          currentToolName = event.content_block.name;
          currentToolInput = "";
        }
        break;

      case "content_block_delta":
        if (event.delta.type === "text_delta") {
          process.stdout.write(event.delta.text); // mostrar al usuario en tiempo real
        } else if (event.delta.type === "input_json_delta") {
          currentToolInput += event.delta.partial_json; // acumular input de tool
        }
        break;

      case "message_delta":
        if (event.delta.stop_reason === "tool_use") {
          const toolInput = JSON.parse(currentToolInput);
          const result = await dispatchTool(currentToolName, toolInput);
          // continuar el loop con el resultado...
        }
        break;

      case "message_stop":
        // stream completado
        break;
    }
  }

  const finalMessage = await stream.finalMessage();
  return finalMessage;
}

Tipos de eventos clave

EventoCuándo ocurre
content_block_startInicio de un bloque (text o tool_use)
content_block_deltaFragmento de texto o JSON parcial
content_block_stopFin del bloque actual
message_deltaCambio en metadata del mensaje (stop_reason)
message_stopMensaje completado

7. Vision API — inputs multimodales

Claude puede procesar imágenes junto con texto. Esto es útil en arquitecturas donde el input no es solo texto.

Árbol de decisión

flowchart TD
    I[Input del usuario] --> T{¿Contiene imagen?}
    T -->|No| P[Request text-only]
    T -->|Sí| F{¿Tipo de imagen?}
    F -->|"URL pública accesible"| U[image_url]
    F -->|"Archivo local / privado"| B[base64]
    B --> C{¿Tamaño?}
    C -->|"< 5 MB"| OK[Enviar en base64]
    C -->|"> 5 MB"| R[Redimensionar o comprimir primero]

Casos de uso en arquitecturas

  • Screenshot de UI para debugging automatizado
  • PDF o imagen de factura para extracción de campos
  • Diagrama de arquitectura para análisis y documentación
  • Captura de dashboard para generación de reportes

Implementación con base64

import Anthropic from "@anthropic-ai/sdk";
import { readFileSync } from "fs";

const client = new Anthropic();

async function analyzeScreenshot(imagePath: string, question: string) {
  const imageData = readFileSync(imagePath);
  const base64Image = imageData.toString("base64");

  const response = await client.messages.create({
    model: "claude-opus-4-8",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: [
          {
            type: "image",
            source: {
              type: "base64",
              media_type: "image/png", // image/jpeg, image/gif, image/webp
              data: base64Image,
            },
          },
          {
            type: "text",
            text: question,
          },
        ],
      },
    ],
  });

  return response.content[0];
}

// Uso
const result = await analyzeScreenshot(
  "./screenshot.png",
  "¿Qué errores aparecen en la consola?"
);

Implementación con URL

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 512,
  messages: [
    {
      role: "user",
      content: [
        {
          type: "image",
          source: {
            type: "url",
            url: "https://example.com/architecture-diagram.png",
          },
        },
        { type: "text", text: "Identifica los puntos de fallo único en este diagrama." },
      ],
    },
  ],
});

Limitaciones y costo

  • No puede procesar: video, audio nativo, archivos .zip, ejecutables
  • Costo estimado por imagen: 1000–4000 tokens adicionales dependiendo del tamaño y detalle
  • Formatos soportados: PNG, JPEG, GIF, WebP
  • Tamaño máximo recomendado: 5 MB por imagen

8. Token counting y optimización de costos

countTokens antes de enviar

La API expone client.messages.countTokens() para calcular cuántos tokens usará un request antes de enviarlo. Esto es útil para:

  • Verificar que el mensaje cabe en el context window
  • Planificar el espacio disponible para tool results
  • Evitar errores max_tokens inesperados en producción
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function safeRequest(systemPrompt: string, userMessage: string) {
  const MODEL = "claude-sonnet-5";
  // Ventana nativa de 1M tokens en Opus 4.8, Sonnet 5 y Fable 5.
  // Para claude-haiku-4-5 la ventana sigue siendo 200_000.
  const CONTEXT_WINDOW = 1_000_000;
  const OUTPUT_BUDGET = 4096;

  // Contar tokens antes de enviar
  const tokenCount = await client.messages.countTokens({
    model: MODEL,
    system: systemPrompt,
    messages: [{ role: "user", content: userMessage }],
  });

  const availableForOutput = CONTEXT_WINDOW - tokenCount.input_tokens;

  if (availableForOutput < OUTPUT_BUDGET) {
    throw new Error(
      `Contexto insuficiente: ${tokenCount.input_tokens} tokens de input, ` +
        `solo quedan ${availableForOutput} para output`
    );
  }

  return client.messages.create({
    model: MODEL,
    max_tokens: OUTPUT_BUDGET,
    system: systemPrompt,
    messages: [{ role: "user", content: userMessage }],
  });
}

Estimación rápida de tokens

IdiomaRegla aproximada
Inglés~4 caracteres = 1 token
Español~3.5 caracteres = 1 token
Código~3 caracteres = 1 token
JSON estructurado~2.5 caracteres = 1 token

Modelos, context windows y costo (referencia aproximada)

ModeloContext windowMax outputInput (por 1M tokens)Output (por 1M tokens)
claude-opus-4-8 (default recomendado, cutoff enero 2026)1M128K$5$25
claude-fable-5 (GA 9 jun 2026)1M128K$10$50
claude-sonnet-51M128K$3$15
claude-haiku-4-5 (pin claude-haiku-4-5-20251001)200K64K$1$5

claude-sonnet-5 tiene precio introductorio de $2/$10 hasta el 31 de agosto de 2026.

Opus 4.5 y Sonnet 4.5 son legacy; claude-3-5-haiku fue retirado el 19 de febrero de 2026 y devuelve 404. Los precios cambian: consulta anthropic.com/pricing para valores actualizados.

Estrategia para agentic loops

La aritmética manual sigue sirviendo como control de cordura:

tokens_disponibles_para_tool_results =
  context_window
  - system_prompt_tokens
  - historial_tokens
  - output_tokens_estimados
  - margen_de_seguridad (10%)

Pero hoy la API ofrece mecanismos de servidor que cubren exactamente ese problema y que conviene preferir sobre la aritmética a mano.

Task Budgets

Beta task-budgets-2026-03-13, disponible en Fable 5, Sonnet 5, Opus 4.8 y Opus 4.7. Es un presupuesto del que el modelo es consciente para todo el bucle agéntico, a diferencia de max_tokens, que es un tope duro por respuesta e invisible al modelo. Mínimo 20.000 tokens. Conviene usarlo con streaming.

const response = await client.messages.create({
  model: "claude-opus-4-8",
  max_tokens: 8192,
  output_config: {
    effort: "xhigh",
    task_budget: { type: "tokens", total: 200_000 },
  },
  tools: [searchTool, editTool],
  messages: [{ role: "user", content: "Migra el módulo de pagos…" }],
}, { headers: { "anthropic-beta": "task-budgets-2026-03-13" } });

Compaction — resumir el historial en servidor

Beta compact-2026-01-12, en Fable 5, Opus 4.8/4.7/4.6, Sonnet 5 y Sonnet 4.6. El servidor resume el historial automáticamente al acercarse al límite.

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 4096,
  context_management: { edits: [{ type: "compact_20260112" }] },
  messages: conversation,
}, { headers: { "anthropic-beta": "compact-2026-01-12" } });

Hay que reenviar response.content completo al siguiente turno, no solo el texto.

Context editing — borrar en vez de resumir

Beta context-management-2025-06-27, con los tipos clear_tool_uses_20250919 y clear_thinking_20251015. Borra pares tool_use/tool_result antiguos en lugar de resumirlos.

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 4096,
  context_management: {
    edits: [
      {
        type: "clear_tool_uses_20250919",
        trigger: { type: "input_tokens", value: 100_000 }, // default 100.000
        keep: { type: "tool_uses", value: 3 },             // default 3 pares recientes
        exclude_tools: ["memory"],
      },
    ],
  },
  messages: conversation,
}, { headers: { "anthropic-beta": "context-management-2025-06-27" } });

Se recomienda combinarlo con la memory tool (memory_20250818): Claude recibe aviso antes del borrado y guarda lo importante en archivos persistentes.

No confundir ambos mecanismos: usar compact_20260112 bajo la cabecera de context-management da error. Compaction tiene su propia cabecera beta.

Si aun así tokens_disponibles_para_tool_results es negativo, quedan las medidas clásicas:

  1. Comprimir el historial (summarization o compaction)
  2. Reducir el system prompt
  3. Paginar los tool results en lugar de incluirlos todos

Resumen del capítulo

ConceptoClave para el examen
Thinkingthinking: { type: "adaptive" }; budget_tokens devuelve 400 salvo en Haiku 4.5
Bloques thinkingdisplay: "omitted" por defecto (llegan vacíos); pedir display: "summarized" para verlos
Esfuerzooutput_config: { effort: … } — GA, sin beta; low|medium|high|xhigh|max; xhigh para coding y agentes
Samplingtemperature, top_p y top_k eliminados en los modelos vigentes (400); se dirige por prompting
Structured outputsoutput_config.format = { type: "json_schema", schema: {…} }; strict: true top-level en la tool
Prefill assistantEliminado (400) en Fable 5, Opus 4.6/4.7/4.8 y Sonnet 4.6/5
IDs de modeloSin sufijo de fecha desde la generación 4.6, pero siguen siendo snapshots pinneados
Prompt Cachingcache_control: { type: "ephemeral" } en el último bloque estático
tool_choice: autoClaude decide; puede no usar tools
tool_choice: anyClaude DEBE usar al menos una tool
tool_choice: toolClaude DEBE usar exactamente esa tool
tool_choice: noneDeshabilita tools aunque estén definidas
disable_parallel_tool_useModificador de tool_choice: máximo un tool_use por turno
Bedrock + Sonnet 5Un tool_choice forzado exige enviar además thinking: { type: "disabled" }
Parallel tool callsUn user message con todos los tool_result usando el tool_use_id correcto
StreamingAcumular input_json_delta para tool inputs; texto en tiempo real
Visionbase64 o URL; sin video/audio; ~1000–4000 tokens por imagen
Token countingclient.messages.countTokens() antes de enviar; ventana de 1M en Opus 4.8, Sonnet 5 y Fable 5
Presupuesto agénticoTask Budgets (output_config.task_budget, mínimo 20.000 tokens) frente a max_tokens
Gestión de contextoCompaction (compact_20260112) resume; context editing (clear_tool_uses_20250919) borra. Cabeceras beta distintas

Siguiente: Preguntas de Práctica