Prerrequisitos

  • Node.js 18+

Instalación

Instala @anthropic-ai/claude-code desde NPM:

npm install -g @anthropic-ai/claude-code

Para ver el código fuente del SDK de TypeScript, visita la página de @anthropic-ai/claude-code en NPM.

Uso básico

La interfaz principal a través del SDK de TypeScript es la función query, que devuelve un iterador asíncrono que transmite mensajes a medida que llegan:

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Analizar el rendimiento del sistema",
  options: {
    maxTurns: 5,
    appendSystemPrompt: "Eres un ingeniero de rendimiento",
    allowedTools: ["Bash", "Read", "WebSearch"],
    abortController: new AbortController(),
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Opciones de configuración

ArgumentoTipoDescripciónPor defecto
abortControllerAbortControllerControlador de aborto para cancelar operacionesnew AbortController()
additionalDirectoriesstring[]Directorios adicionales para incluir en la sesiónundefined
allowedToolsstring[]Lista de herramientas que Claude puede usarTodas las herramientas habilitadas por defecto
appendSystemPromptstringTexto para agregar al prompt del sistema por defectoundefined
canUseTool(toolName: string, input: any) => Promise<ToolPermissionResult>Función de permisos personalizada para el uso de herramientasundefined
continuebooleanContinuar la sesión más recientefalse
customSystemPromptstringReemplazar completamente el prompt del sistema por defectoundefined
cwdstringDirectorio de trabajo actualprocess.cwd()
disallowedToolsstring[]Lista de herramientas que Claude no puede usarundefined
envDict<string>Variables de entorno para establecerundefined
executable'bun' | 'deno' | 'node'Qué runtime de JavaScript usarnode cuando se ejecuta con Node.js, bun cuando se ejecuta con Bun
executableArgsstring[]Argumentos para pasar al ejecutable[]
fallbackModelstringModelo a usar si el modelo principal fallaundefined
hooksPartial<Record<HookEvent, HookCallbackMatcher[]>>Hooks del ciclo de vida para personalizaciónundefined
includePartialMessagesbooleanIncluir eventos de transmisión parcial en el flujo de mensajesfalse
maxThinkingTokensnumberTokens máximos para el proceso de pensamiento de Claudeundefined
maxTurnsnumberNúmero máximo de turnos de conversaciónundefined
mcpServersRecord<string, McpServerConfig>Configuraciones del servidor MCPundefined
modelstringModelo de Claude a usarUsa el predeterminado de la configuración CLI
pathToClaudeCodeExecutablestringRuta al ejecutable de Claude CodeEjecutable que viene con @anthropic-ai/claude-code
permissionModePermissionModeModo de permisos para la sesión"default" (opciones: "default", "acceptEdits", "bypassPermissions", "plan")
resumestringID de sesión para reanudarundefined
stderr(data: string) => voidCallback para la salida stderrundefined
strictMcpConfigbooleanAplicar validación estricta de configuración MCPundefined

Transmisión de mensajes parciales

Cuando includePartialMessages está habilitado, el SDK emitirá mensajes stream_event que contienen eventos de transmisión en bruto de la API de Claude. Esto te permite acceder al contenido parcial mientras se está generando, útil para implementar actualizaciones de UI en tiempo real o indicadores de progreso.

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Escribe un ensayo largo sobre inteligencia artificial",
  options: {
    includePartialMessages: true,
    maxTurns: 1
  }
})) {
  // Manejar eventos de transmisión parcial
  if (message.type === "stream_event") {
    const event = message.event;
    
    // Acceder al texto parcial mientras se transmite
    if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
      process.stdout.write(event.delta.text);
    }
    
    // Rastrear el progreso del pensamiento
    if (event.type === "content_block_start" && event.content_block.type === "thinking") {
      console.log("\n[Claude está pensando...]");
    }
  }
  
  // Aún obtener el resultado final
  if (message.type === "result" && message.subtype === "success") {
    console.log("\nResultado final:", message.result);
  }
}

Cada mensaje stream_event incluye:

  • event: El evento de transmisión en bruto de la API
  • session_id: El identificador de sesión actual
  • parent_tool_use_id: El ID de la herramienta que se está ejecutando (si aplica)
  • uuid: Un identificador único para este evento

La transmisión de mensajes parciales es principalmente útil para casos de uso avanzados donde necesitas control granular sobre la respuesta de transmisión. Para la mayoría de aplicaciones, el comportamiento predeterminado (esperar mensajes completos) es suficiente.

Conversaciones de múltiples turnos

Para conversaciones de múltiples turnos, tienes dos opciones.

Puedes generar respuestas y reanudarlas, o puedes usar el modo de entrada de transmisión que acepta un async/generador para un array de mensajes. Por ahora, el modo de entrada de transmisión es la única forma de adjuntar imágenes a través de mensajes.

Reanudar con gestión de sesiones

import { query } from "@anthropic-ai/claude-code";

// Continuar la conversación más reciente
for await (const message of query({
  prompt: "Ahora refactoriza esto para mejor rendimiento",
  options: { continue: true }
})) { 
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Reanudar sesión específica
for await (const message of query({
  prompt: "Actualizar las pruebas",
  options: {
    resume: "550e8400-e29b-41d4-a716-446655440000",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Modo de entrada de transmisión

El modo de entrada de transmisión te permite proporcionar mensajes como un iterable asíncrono en lugar de una sola cadena. Esto habilita conversaciones de múltiples turnos, adjuntos de imágenes y generación dinámica de mensajes:

import { query } from "@anthropic-ai/claude-code";

// Crear un generador asíncrono para transmitir mensajes
async function* generateMessages() {
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Comenzar a analizar esta base de código"
    }
  };
  
  // Esperar alguna condición o entrada del usuario
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Ahora enfócate en el módulo de autenticación"
    }
  };
}

// Usar entrada de transmisión
for await (const message of query({
  prompt: generateMessages(),
  options: {
    maxTurns: 5,
    allowedTools: ["Read", "Grep", "Bash"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Entrada de transmisión con imágenes

El modo de entrada de transmisión es la única forma de adjuntar imágenes a través de mensajes:

import { query } from "@anthropic-ai/claude-code";
import { readFileSync } from "fs";

async function* messagesWithImage() {
  // Enviar una imagen con texto
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: [
        {
          type: "text",
          text: "Analiza esta captura de pantalla y sugiere mejoras"
        },
        {
          type: "image",
          source: {
            type: "base64",
            media_type: "image/png",
            data: readFileSync("screenshot.png", "base64")
          }
        }
      ]
    }
  };
}

for await (const message of query({
  prompt: messagesWithImage()
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Prompts del sistema personalizados

Los prompts del sistema definen el rol, experiencia y comportamiento de tu agente:

import { query } from "@anthropic-ai/claude-code";

// Agente de respuesta a incidentes SRE
for await (const message of query({
  prompt: "La API está caída, investigar",
  options: {
    customSystemPrompt: "Eres un experto en SRE. Diagnostica problemas sistemáticamente y proporciona soluciones accionables.",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Agregar al prompt del sistema por defecto
for await (const message of query({
  prompt: "Refactorizar esta función",
  options: {
    appendSystemPrompt: "Siempre incluye manejo de errores integral y pruebas unitarias.",
    maxTurns: 2
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Integración de servidor MCP

El Protocolo de Contexto de Modelo (MCP) te permite dar a tus agentes herramientas y capacidades personalizadas:

import { query } from "@anthropic-ai/claude-code";

// Agente SRE con herramientas de monitoreo
for await (const message of query({
  prompt: "Investigar la interrupción del servicio de pagos",
  options: {
    mcpConfig: "sre-tools.json",
    allowedTools: ["mcp__datadog", "mcp__pagerduty", "mcp__kubernetes"],
    appendSystemPrompt: "Eres un SRE. Usa datos de monitoreo para diagnosticar problemas.",
    maxTurns: 4
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Herramientas personalizadas con servidores MCP en proceso

Los servidores MCP del SDK te permiten crear herramientas personalizadas que se ejecutan directamente en el proceso de tu aplicación, proporcionando ejecución de herramientas con seguridad de tipos sin la sobrecarga de procesos separados o comunicación de red.

Creando herramientas personalizadas

Usa las funciones auxiliares createSdkMcpServer y tool para definir herramientas personalizadas con seguridad de tipos:

import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-code";
import { z } from "zod";

// Crear un servidor MCP del SDK con herramientas personalizadas
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "calculate_compound_interest",
      "Calcular interés compuesto para una inversión",
      {
        principal: z.number().describe("Monto de inversión inicial"),
        rate: z.number().describe("Tasa de interés anual (como decimal, ej., 0.05 para 5%)"),
        time: z.number().describe("Período de inversión en años"),
        n: z.number().default(12).describe("Frecuencia de capitalización por año")
      },
      async (args) => {
        const amount = args.principal * Math.pow(1 + args.rate / args.n, args.n * args.time);
        const interest = amount - args.principal;
        
        return {
          content: [{
            type: "text",
            text: `Monto final: $${amount.toFixed(2)}\nInterés ganado: $${interest.toFixed(2)}`
          }]
        };
      }
    ),
    tool(
      "fetch_user_data",
      "Obtener datos de usuario de la base de datos de tu aplicación",
      {
        userId: z.string().describe("El ID de usuario a obtener"),
        fields: z.array(z.string()).optional().describe("Campos específicos a devolver")
      },
      async (args) => {
        // Acceso directo a la capa de datos de tu aplicación
        const userData = await myDatabase.getUser(args.userId, args.fields);
        
        return {
          content: [{
            type: "text",
            text: JSON.stringify(userData, null, 2)
          }]
        };
      }
    )
  ]
});

// Usar las herramientas personalizadas en tu consulta
for await (const message of query({
  prompt: "Calcular interés compuesto para $10,000 al 5% por 10 años",
  options: {
    mcpServers: {
      "my-custom-tools": customServer
    },
    maxTurns: 3
  }
})) {
  if (message.type === "result") {
    console.log(message.result);
  }
}

Seguridad de tipos con Zod

El auxiliar tool proporciona inferencia completa de tipos de TypeScript desde tus esquemas Zod:

tool(
  "process_data",
  "Procesar datos estructurados con seguridad de tipos",
  {
    // El esquema Zod define tanto validación en tiempo de ejecución como tipos de TypeScript
    data: z.object({
      name: z.string(),
      age: z.number().min(0).max(150),
      email: z.string().email(),
      preferences: z.array(z.string()).optional()
    }),
    format: z.enum(["json", "csv", "xml"]).default("json")
  },
  async (args) => {
    // args está completamente tipado basado en el esquema
    // TypeScript sabe: args.data.name es string, args.data.age es number, etc.
    console.log(`Procesando datos de ${args.data.name} como ${args.format}`);
    
    // Tu lógica de procesamiento aquí
    return {
      content: [{
        type: "text",
        text: `Datos procesados para ${args.data.name}`
      }]
    };
  }
)

Hooks

Los hooks te permiten personalizar y extender el comportamiento de Claude Code ejecutando callbacks personalizados en varios puntos del ciclo de vida del agente. A diferencia de los hooks de CLI que ejecutan comandos bash, los hooks del SDK son funciones JavaScript/TypeScript que se ejecutan en proceso.

Definiendo hooks

Los hooks están organizados por tipo de evento, con matchers opcionales para filtrar cuándo se ejecutan:

import { query } from "@anthropic-ai/claude-code";

for await (const message of query({
  prompt: "Analizar la base de código",
  options: {
    hooks: {
      PreToolUse: [
        {
          matcher: "Write",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`A punto de escribir archivo: ${input.tool_input.file_path}`);
              
              // Validar la operación
              if (input.tool_input.file_path.includes('.env')) {
                return {
                  decision: 'block',
                  stopReason: 'No se puede escribir en archivos de entorno'
                };
              }
              
              // Permitir la operación
              return { continue: true };
            }
          ]
        }
      ],
      PostToolUse: [
        {
          matcher: "Write|Edit",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`Archivo modificado: ${input.tool_response.filePath}`);
              // Ejecutar tu formateo o validación personalizada
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Eventos de hook disponibles

  • PreToolUse: Se ejecuta antes de la ejecución de herramientas. Puede bloquear herramientas o proporcionar retroalimentación.
  • PostToolUse: Se ejecuta después de la ejecución exitosa de herramientas.
  • UserPromptSubmit: Se ejecuta cuando el usuario envía un prompt.
  • SessionStart: Se ejecuta cuando una sesión comienza.
  • SessionEnd: Se ejecuta cuando una sesión termina.
  • Stop: Se ejecuta cuando Claude está a punto de dejar de responder.
  • SubagentStop: Se ejecuta cuando un subagente está a punto de detenerse.
  • PreCompact: Se ejecuta antes de la compactación de conversación.
  • Notification: Se ejecuta cuando se envían notificaciones.

Tipos de entrada de hook

Cada hook recibe entrada tipada basada en el evento:

// Entrada PreToolUse
type PreToolUseHookInput = {
  hook_event_name: 'PreToolUse';
  session_id: string;
  transcript_path: string;
  cwd: string;
  permission_mode?: string;
  tool_name: string;
  tool_input: unknown;
}

// Entrada PostToolUse
type PostToolUseHookInput = {
  hook_event_name: 'PostToolUse';
  session_id: string;
  transcript_path: string;
  cwd: string;
  permission_mode?: string;
  tool_name: string;
  tool_input: unknown;
  tool_response: unknown;
}

Salida de hook

Los hooks devuelven salida que controla el flujo de ejecución:

interface HookJSONOutput {
  // Continuar ejecución (por defecto: true)
  continue?: boolean;
  
  // Suprimir salida al usuario
  suppressOutput?: boolean;
  
  // Razón de parada (mostrada al modelo)
  stopReason?: string;
  
  // Decisión para hooks PreToolUse
  decision?: 'approve' | 'block';
  
  // Mensaje del sistema a mostrar
  systemMessage?: string;
  
  // Salida específica del hook
  hookSpecificOutput?: {
    // Para PreToolUse
    permissionDecision?: 'allow' | 'deny' | 'ask';
    permissionDecisionReason?: string;
    
    // Para UserPromptSubmit o PostToolUse
    additionalContext?: string;
  };
}

Ejemplos prácticos

Registro y monitoreo

const hooks = {
  PreToolUse: [
    {
      hooks: [
        async (input) => {
          // Registrar todo el uso de herramientas
          await logToMonitoring({
            event: 'tool_use',
            tool: input.tool_name,
            input: input.tool_input,
            session: input.session_id
          });
          
          return { continue: true };
        }
      ]
    }
  ]
};

Validación de operaciones de archivo

const hooks = {
  PreToolUse: [
    {
      matcher: "Write|Edit",
      hooks: [
        async (input) => {
          const filePath = input.tool_input.file_path;
          
          // Bloquear archivos sensibles
          const sensitivePatterns = ['.env', '.git/', 'secrets/', '*.key'];
          
          for (const pattern of sensitivePatterns) {
            if (filePath.includes(pattern)) {
              return {
                decision: 'block',
                stopReason: `No se puede modificar archivo sensible que coincide con ${pattern}`
              };
            }
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Auto-formateo de código

import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

const hooks = {
  PostToolUse: [
    {
      matcher: "Write|Edit|MultiEdit",
      hooks: [
        async (input) => {
          const filePath = input.tool_response.filePath;
          
          //Auto-formatear basado en el tipo de archivo
          if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
            await execAsync(`prettier --write "${filePath}"`);
          } else if (filePath.endsWith('.py')) {
            await execAsync(`black "${filePath}"`);
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Mejora de prompts

const hooks = {
  UserPromptSubmit: [
    {
      hooks: [
        async (input) => {
          // Agregar contexto a los prompts
          const projectContext = await loadProjectContext();
          
          return {
            continue: true,
            hookSpecificOutput: {
              hookEventName: 'UserPromptSubmit',
              additionalContext: `Contexto del proyecto: ${projectContext}`
            }
          };
        }
      ]
    }
  ]
};

Instrucciones de compactación personalizadas

const hooks = {
  PreCompact: [
    {
      hooks: [
        async (input) => {
          const trigger = input.trigger; // 'manual' o 'auto'
          
          return {
            continue: true,
            systemMessage: 'Enfócate en preservar detalles de implementación y resoluciones de errores'
          };
        }
      ]
    }
  ]
};

Comportamiento de ejecución de hooks

  • Paralelización: Todos los hooks coincidentes se ejecutan en paralelo
  • Timeout: Los hooks respetan la señal de aborto de las opciones
  • Manejo de errores: Los errores de hooks se registran pero no detienen la ejecución
  • Matchers: Soportan patrones regex (ej., "Write|Edit")

Combinando hooks con canUseTool

Mientras que canUseTool proporciona control de permisos, los hooks ofrecen integración más amplia del ciclo de vida:

for await (const message of query({
  prompt: "Construir la funcionalidad",
  options: {
    // Control de permisos de grano fino
    canUseTool: async (toolName, input) => {
      // Modificar entradas o denegar basado en condiciones de tiempo de ejecución
      return { behavior: "allow", updatedInput: input };
    },
    
    // Hooks del ciclo de vida para monitoreo y automatización
    hooks: {
      PreToolUse: [
        {
          hooks: [
            async (input) => {
              // Registrar, validar o preparar
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  // Procesar mensajes
}

Control de permisos con canUseTool

El callback canUseTool proporciona control de grano fino sobre la ejecución de herramientas. Se llama antes de cada uso de herramienta y puede permitir, denegar o modificar las entradas de herramientas:

type ToolPermissionResult = 
  | { behavior: "allow"; updatedInput?: any }
  | { behavior: "deny"; message?: string };

for await (const message of query({
  prompt: "Analizar comportamiento del usuario y calcular métricas",
  options: {
    mcpServers: {
      "analytics": analyticsServer
    },
    canUseTool: async (toolName: string, input: any) => {
      // Controlar qué herramientas se pueden usar
      if (toolName.startsWith("mcp__analytics__")) {
        // Verificar permisos para herramientas de análisis
        const hasPermission = await checkUserPermissions(toolName);
        
        return hasPermission
          ? { behavior: "allow", updatedInput: input }
          : { behavior: "deny", message: "Permisos insuficientes" };
      }
      
      // Modificar entradas para ciertas herramientas
      if (toolName === "Bash") {
        // Agregar verificaciones de seguridad o modificar comandos
        const safeInput = sanitizeBashCommand(input);
        return { behavior: "allow", updatedInput: safeInput };
      }
      
      // Permitir otras herramientas por defecto
      return { behavior: "allow", updatedInput: input };
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Casos de uso para canUseTool

  • Gestión de permisos: Verificar permisos de usuario antes de permitir la ejecución de herramientas
  • Validación de entrada: Validar o sanear entradas de herramientas antes de la ejecución
  • Limitación de tasa: Implementar límites de tasa para operaciones costosas
  • Registro de auditoría: Registrar el uso de herramientas para cumplimiento o depuración
  • Permisos dinámicos: Habilitar/deshabilitar herramientas basado en condiciones de tiempo de ejecución
// Ejemplo: Limitador de tasa para web scraping
const rateLimits = new Map<string, { count: number; resetTime: number }>();

const canUseTool = async (toolName: string, input: any) => {
  // Limitar tasa de web scraping para prevenir prohibiciones de IP y problemas de cuota de API
  if (toolName === "WebFetch" || toolName === "WebSearch") {
    const now = Date.now();
    const limit = rateLimits.get(toolName) || { count: 0, resetTime: now + 60000 };
    
    // Reiniciar contador cada minuto
    if (now > limit.resetTime) {
      limit.count = 0;
      limit.resetTime = now + 60000;
    }
    
    // Permitir máximo 10 solicitudes por minuto
    if (limit.count >= 10) {
      return { 
        behavior: "deny", 
        message: `Límite de tasa excedido: máximo 10 solicitudes ${toolName} por minuto. Se reinicia en ${Math.ceil((limit.resetTime - now) / 1000)}s` 
      };
    }
    
    limit.count++;
    rateLimits.set(toolName, limit);
    
    // Registrar actividad de scraping para monitoreo
    console.log(`Solicitud ${toolName} ${limit.count}/10 a: ${input.url || input.query}`);
  }
  
  // Prevenir bucles infinitos accidentales en scripts bash
  if (toolName === "Bash" && input.command?.includes("while true")) {
    return { 
      behavior: "deny", 
      message: "Los bucles infinitos no están permitidos" 
    };
  }
  
  return { behavior: "allow", updatedInput: input };
};

Formatos de salida

Salida de texto (por defecto)

// Salida de texto por defecto
for await (const message of query({
  prompt: "Explicar archivo src/components/Header.tsx"
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
    // Salida: Este es un componente React que muestra...
  }
}

Salida JSON

// Recopilar todos los mensajes para acceso tipo JSON
const messages = [];
for await (const message of query({
  prompt: "¿Cómo funciona la capa de datos?"
})) {
  messages.push(message);
}

// Acceder al mensaje de resultado con metadatos
const result = messages.find(m => m.type === "result" && message.subtype === "success");
console.log({
  result: result.result,
  cost: result.total_cost_usd,
  duration: result.duration_ms
});

Formatos de entrada

// Prompt directo
for await (const message of query({
  prompt: "Explicar este código"
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Desde variable
const userInput = "Explicar este código";
for await (const message of query({ prompt: userInput })) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Ejemplos de integración de agentes

Agente de respuesta a incidentes SRE

import { query } from "@anthropic-ai/claude-code";

// Agente automatizado de respuesta a incidentes
async function investigateIncident(
  incidentDescription: string,
  severity = "medium"
) {
  const messages = [];

  for await (const message of query({
    prompt: `Incidente: ${incidentDescription} (Severidad: ${severity})`,
    options: {
      appendSystemPrompt: "Eres un experto en SRE. Diagnostica el problema, evalúa el impacto y proporciona elementos de acción inmediatos.",
      maxTurns: 6,
      allowedTools: ["Bash", "Read", "WebSearch", "mcp__datadog"],
      mcpConfig: "monitoring-tools.json"
    }
  })) {
    messages.push(message);
  }

  return messages.find(m => m.type === "result" && message.subtype === "success");
}

// Uso
const result = await investigateIncident("API de pagos devolviendo errores 500", "high");
console.log(result.result);

Revisión de seguridad automatizada

import { query } from "@anthropic-ai/claude-code";
import { execSync } from "child_process";

async function auditPR(prNumber: number) {
  // Obtener diff del PR
  const prDiff = execSync(`gh pr diff ${prNumber}`, { encoding: 'utf8' });

  const messages = [];
  for await (const message of query({
    prompt: prDiff,
    options: {
      appendSystemPrompt: "Eres un ingeniero de seguridad. Revisa este PR en busca de vulnerabilidades, patrones inseguros y problemas de cumplimiento.",
      maxTurns: 3,
      allowedTools: ["Read", "Grep", "WebSearch"]
    }
  })) {
    messages.push(message);
  }

  return messages.find(m => m.type === "result" && message.subtype === "success");
}

// Uso
const report = await auditPR(123);
console.log(JSON.stringify(report, null, 2));
import { query } from "@anthropic-ai/claude-code";

async function legalReview() {
  // Iniciar sesión de revisión legal
  let sessionId: string;

  for await (const message of query({
    prompt: "Iniciar sesión de revisión legal",
    options: { maxTurns: 1 }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      sessionId = message.session_id;
    }
  }

  // Revisión de múltiples pasos usando la misma sesión
  const steps = [
    "Revisar contract.pdf para cláusulas de responsabilidad",
    "Verificar cumplimiento con requisitos GDPR",
    "Generar resumen ejecutivo de riesgos"
  ];

  for (const step of steps) {
    for await (const message of query({
      prompt: step,
      options: { resume: sessionId, maxTurns: 2 }
    })) {
      if (message.type === "result" && message.subtype === "success") {
        console.log(`Paso: ${step}`);
        console.log(message.result);
      }
    }
  }
}

Esquema de mensajes

Los mensajes devueltos por la API JSON están estrictamente tipados según el siguiente esquema:

type SDKMessage =
  // Un mensaje del asistente
  | {
      type: "assistant";
      uuid: string;
      session_id: string;
      message: Message; // del SDK de Anthropic
      parent_tool_use_id: string | null;
    }

  // Un mensaje del usuario (entrada)
  | {
      type: "user";
      uuid?: string;
      session_id: string;
      message: MessageParam; // del SDK de Anthropic
      parent_tool_use_id: string | null;
    }

  // Un mensaje del usuario (salida/repetición con UUID requerido)
  | {
      type: "user";
      uuid: string;
      session_id: string;
      message: MessageParam; // del SDK de Anthropic
      parent_tool_use_id: string | null;
    }

  // Emitido como el último mensaje en caso de éxito
  | {
      type: "result";
      subtype: "success";
      uuid: UUID;
      session_id: string;
      duration_ms: number;
      duration_api_ms: number;
      is_error: boolean;
      num_turns: number;
      result: string;
      total_cost_usd: number;
      usage: Usage;
      permission_denials: SDKPermissionDenial[];
    }

  // Emitido como el último mensaje en error o máximo de turnos
  | {
      type: "result";
      subtype: "error_max_turns" | "error_during_execution";
      uuid: UUID;
      session_id: string;
      duration_ms: number;
      duration_api_ms: number;
      is_error: boolean;
      num_turns: number;
      total_cost_usd: number;
      usage: Usage;
      permission_denials: SDKPermissionDenial[];
    }

  // Emitido como el primer mensaje al inicio de una conversación
  | {
      type: "system";
      subtype: "init";
      uuid: UUID;
      session_id: string;
      apiKeySource: "user" | "project" | "org" | "temporary";
      cwd: string;
      tools: string[];
      mcp_servers: {
        name: string;
        status: string;
      }[];
      model: string;
      permissionMode: "default" | "acceptEdits" | "bypassPermissions" | "plan";
      slash_commands: string[];
      output_style: string;
    };

  type SDKPermissionDenial = {
    tool_name: string;
    tool_use_id: string;
    tool_input: Record<string, unknown>;
  }

Tipos de soporte adicionales:

Los tipos Message, MessageParam y Usage están disponibles en el SDK de TypeScript de Anthropic.

Recursos relacionados