Предварительные требования

  • Node.js 18+

Установка

Установите @anthropic-ai/claude-code из NPM:

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

Чтобы просмотреть исходный код TypeScript SDK, посетите страницу @anthropic-ai/claude-code на NPM.

Базовое использование

Основным интерфейсом через TypeScript SDK является функция query, которая возвращает асинхронный итератор, передающий сообщения по мере их поступления:

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

for await (const message of query({
  prompt: "Анализировать производительность системы",
  options: {
    maxTurns: 5,
    appendSystemPrompt: "Вы инженер по производительности",
    allowedTools: ["Bash", "Read", "WebSearch"],
    abortController: new AbortController(),
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

Параметры конфигурации

АргументТипОписаниеПо умолчанию
abortControllerAbortControllerКонтроллер прерывания для отмены операцийnew AbortController()
additionalDirectoriesstring[]Дополнительные каталоги для включения в сессиюundefined
allowedToolsstring[]Список инструментов, которые Claude разрешено использоватьВсе инструменты включены по умолчанию
appendSystemPromptstringТекст для добавления к системному промпту по умолчаниюundefined
canUseTool(toolName: string, input: any) => Promise<ToolPermissionResult>Пользовательская функция разрешений для использования инструментовundefined
continuebooleanПродолжить самую последнюю сессиюfalse
customSystemPromptstringПолностью заменить системный промпт по умолчаниюundefined
cwdstringТекущий рабочий каталогprocess.cwd()
disallowedToolsstring[]Список инструментов, которые Claude не разрешено использоватьundefined
envDict<string>Переменные окружения для установкиundefined
executable'bun' | 'deno' | 'node'Какую среду выполнения JavaScript использоватьnode при запуске с Node.js, bun при запуске с Bun
executableArgsstring[]Аргументы для передачи исполняемому файлу[]
fallbackModelstringМодель для использования, если основная модель не работаетundefined
hooksPartial<Record<HookEvent, HookCallbackMatcher[]>>Хуки жизненного цикла для настройкиundefined
includePartialMessagesbooleanВключить частичные события потоковой передачи в поток сообщенийfalse
maxThinkingTokensnumberМаксимальное количество токенов для процесса размышления Claudeundefined
maxTurnsnumberМаксимальное количество ходов разговораundefined
mcpServersRecord<string, McpServerConfig>Конфигурации MCP-серверовundefined
modelstringМодель Claude для использованияИспользует значение по умолчанию из конфигурации CLI
pathToClaudeCodeExecutablestringПуть к исполняемому файлу Claude CodeИсполняемый файл, поставляемый с @anthropic-ai/claude-code
permissionModePermissionModeРежим разрешений для сессии"default" (варианты: "default", "acceptEdits", "bypassPermissions", "plan")
resumestringID сессии для возобновленияundefined
stderr(data: string) => voidОбратный вызов для вывода stderrundefined
strictMcpConfigbooleanПринудительная строгая проверка конфигурации MCPundefined

Частичная потоковая передача сообщений

Когда включен includePartialMessages, SDK будет выдавать сообщения stream_event, содержащие необработанные события потоковой передачи из API Claude. Это позволяет получать доступ к частичному содержимому по мере его генерации, что полезно для реализации обновлений пользовательского интерфейса в реальном времени или индикаторов прогресса.

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

for await (const message of query({
  prompt: "Напишите длинное эссе об искусственном интеллекте",
  options: {
    includePartialMessages: true,
    maxTurns: 1
  }
})) {
  // Обработка частичных событий потоковой передачи
  if (message.type === "stream_event") {
    const event = message.event;
    
    // Доступ к частичному тексту по мере его потоковой передачи
    if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
      process.stdout.write(event.delta.text);
    }
    
    // Отслеживание прогресса размышления
    if (event.type === "content_block_start" && event.content_block.type === "thinking") {
      console.log("\n[Claude размышляет...]");
    }
  }
  
  // Все еще получаем окончательный результат
  if (message.type === "result" && message.subtype === "success") {
    console.log("\nОкончательный результат:", message.result);
  }
}

Каждое сообщение stream_event включает:

  • event: Необработанное событие потоковой передачи из API
  • session_id: Идентификатор текущей сессии
  • parent_tool_use_id: ID выполняемого инструмента (если применимо)
  • uuid: Уникальный идентификатор для этого события

Частичная потоковая передача сообщений в основном полезна для продвинутых случаев использования, где вам нужен детальный контроль над потоковым ответом. Для большинства приложений достаточно поведения по умолчанию (ожидание полных сообщений).

Многоходовые разговоры

Для многоходовых разговоров у вас есть два варианта.

Вы можете генерировать ответы и возобновлять их, или можете использовать режим потокового ввода, который принимает async/generator для массива сообщений. На данный момент режим потокового ввода - единственный способ прикреплять изображения через сообщения.

Возобновление с управлением сессиями

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

// Продолжить самый последний разговор
for await (const message of query({
  prompt: "Теперь рефакторьте это для лучшей производительности",
  options: { continue: true }
})) { 
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Возобновить конкретную сессию
for await (const message of query({
  prompt: "Обновите тесты",
  options: {
    resume: "550e8400-e29b-41d4-a716-446655440000",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Режим потокового ввода

Режим потокового ввода позволяет предоставлять сообщения как асинхронный итерируемый объект вместо одной строки. Это обеспечивает многоходовые разговоры, вложения изображений и динамическую генерацию сообщений:

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

// Создать асинхронный генератор для потоковых сообщений
async function* generateMessages() {
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Начните анализировать эту кодовую базу"
    }
  };
  
  // Ждать какого-то условия или пользовательского ввода
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: "Теперь сосредоточьтесь на модуле аутентификации"
    }
  };
}

// Использовать потоковый ввод
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);
  }
}

Потоковый ввод с изображениями

Режим потокового ввода - единственный способ прикреплять изображения через сообщения:

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

async function* messagesWithImage() {
  // Отправить изображение с текстом
  yield {
    type: "user" as const,
    message: {
      role: "user" as const,
      content: [
        {
          type: "text",
          text: "Проанализируйте этот скриншот и предложите улучшения"
        },
        {
          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);
}

Пользовательские системные промпты

Системные промпты определяют роль, экспертизу и поведение вашего агента:

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

// Агент реагирования на инциденты SRE
for await (const message of query({
  prompt: "API не работает, исследуйте",
  options: {
    customSystemPrompt: "Вы эксперт SRE. Диагностируйте проблемы систематически и предоставляйте практические решения.",
    maxTurns: 3
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Добавить к системному промпту по умолчанию
for await (const message of query({
  prompt: "Рефакторьте эту функцию",
  options: {
    appendSystemPrompt: "Всегда включайте комплексную обработку ошибок и модульные тесты.",
    maxTurns: 2
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Интеграция MCP-серверов

Протокол контекста модели (MCP) позволяет предоставлять вашим агентам пользовательские инструменты и возможности:

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

// SRE-агент с инструментами мониторинга
for await (const message of query({
  prompt: "Исследуйте сбой платежного сервиса",
  options: {
    mcpConfig: "sre-tools.json",
    allowedTools: ["mcp__datadog", "mcp__pagerduty", "mcp__kubernetes"],
    appendSystemPrompt: "Вы SRE. Используйте данные мониторинга для диагностики проблем.",
    maxTurns: 4
  }
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Пользовательские инструменты с внутрипроцессными MCP-серверами

SDK MCP-серверы позволяют создавать пользовательские инструменты, которые работают непосредственно в процессе вашего приложения, обеспечивая типобезопасное выполнение инструментов без накладных расходов отдельных процессов или сетевого взаимодействия.

Создание пользовательских инструментов

Используйте функции-помощники createSdkMcpServer и tool для определения типобезопасных пользовательских инструментов:

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

// Создать SDK MCP-сервер с пользовательскими инструментами
const customServer = createSdkMcpServer({
  name: "my-custom-tools",
  version: "1.0.0",
  tools: [
    tool(
      "calculate_compound_interest",
      "Рассчитать сложные проценты для инвестиции",
      {
        principal: z.number().describe("Начальная сумма инвестиции"),
        rate: z.number().describe("Годовая процентная ставка (в виде десятичной дроби, например, 0.05 для 5%)"),
        time: z.number().describe("Период инвестиции в годах"),
        n: z.number().default(12).describe("Частота начисления процентов в год")
      },
      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: `Итоговая сумма: $${amount.toFixed(2)}\nПолученные проценты: $${interest.toFixed(2)}`
          }]
        };
      }
    ),
    tool(
      "fetch_user_data",
      "Получить пользовательские данные из базы данных вашего приложения",
      {
        userId: z.string().describe("ID пользователя для получения"),
        fields: z.array(z.string()).optional().describe("Конкретные поля для возврата")
      },
      async (args) => {
        // Прямой доступ к уровню данных вашего приложения
        const userData = await myDatabase.getUser(args.userId, args.fields);
        
        return {
          content: [{
            type: "text",
            text: JSON.stringify(userData, null, 2)
          }]
        };
      }
    )
  ]
});

// Использовать пользовательские инструменты в вашем запросе
for await (const message of query({
  prompt: "Рассчитайте сложные проценты для $10,000 под 5% на 10 лет",
  options: {
    mcpServers: {
      "my-custom-tools": customServer
    },
    maxTurns: 3
  }
})) {
  if (message.type === "result") {
    console.log(message.result);
  }
}

Типобезопасность с Zod

Помощник tool обеспечивает полный вывод типов TypeScript из ваших схем Zod:

tool(
  "process_data",
  "Обработать структурированные данные с типобезопасностью",
  {
    // Схема Zod определяет как валидацию времени выполнения, так и типы 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 полностью типизирован на основе схемы
    // TypeScript знает: args.data.name это string, args.data.age это number, и т.д.
    console.log(`Обработка данных ${args.data.name} как ${args.format}`);
    
    // Ваша логика обработки здесь
    return {
      content: [{
        type: "text",
        text: `Обработаны данные для ${args.data.name}`
      }]
    };
  }
)

Хуки

Хуки позволяют настраивать и расширять поведение Claude Code, запуская пользовательские обратные вызовы в различных точках жизненного цикла агента. В отличие от CLI-хуков, которые выполняют bash-команды, SDK-хуки - это JavaScript/TypeScript функции, которые выполняются внутри процесса.

Определение хуков

Хуки организованы по типу события с дополнительными сопоставителями для фильтрации времени их выполнения:

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

for await (const message of query({
  prompt: "Проанализируйте кодовую базу",
  options: {
    hooks: {
      PreToolUse: [
        {
          matcher: "Write",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`Собираюсь записать файл: ${input.tool_input.file_path}`);
              
              // Валидировать операцию
              if (input.tool_input.file_path.includes('.env')) {
                return {
                  decision: 'block',
                  stopReason: 'Нельзя записывать в файлы окружения'
                };
              }
              
              // Разрешить операцию
              return { continue: true };
            }
          ]
        }
      ],
      PostToolUse: [
        {
          matcher: "Write|Edit",
          hooks: [
            async (input, toolUseId, { signal }) => {
              console.log(`Файл изменен: ${input.tool_response.filePath}`);
              // Запустить вашу пользовательскую форматирование или валидацию
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Доступные события хуков

  • PreToolUse: Выполняется перед выполнением инструмента. Может блокировать инструменты или предоставлять обратную связь.
  • PostToolUse: Выполняется после успешного выполнения инструмента.
  • UserPromptSubmit: Выполняется, когда пользователь отправляет промпт.
  • SessionStart: Выполняется при запуске сессии.
  • SessionEnd: Выполняется при завершении сессии.
  • Stop: Выполняется, когда Claude собирается прекратить отвечать.
  • SubagentStop: Выполняется, когда субагент собирается остановиться.
  • PreCompact: Выполняется перед сжатием разговора.
  • Notification: Выполняется при отправке уведомлений.

Типы входных данных хуков

Каждый хук получает типизированные входные данные на основе события:

// Входные данные PreToolUse
type PreToolUseHookInput = {
  hook_event_name: 'PreToolUse';
  session_id: string;
  transcript_path: string;
  cwd: string;
  permission_mode?: string;
  tool_name: string;
  tool_input: unknown;
}

// Входные данные 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;
}

Выходные данные хука

Хуки возвращают выходные данные, которые управляют потоком выполнения:

interface HookJSONOutput {
  // Продолжить выполнение (по умолчанию: true)
  continue?: boolean;
  
  // Подавить вывод пользователю
  suppressOutput?: boolean;
  
  // Причина остановки (показывается модели)
  stopReason?: string;
  
  // Решение для хуков PreToolUse
  decision?: 'approve' | 'block';
  
  // Системное сообщение для показа
  systemMessage?: string;
  
  // Специфичные для хука выходные данные
  hookSpecificOutput?: {
    // Для PreToolUse
    permissionDecision?: 'allow' | 'deny' | 'ask';
    permissionDecisionReason?: string;
    
    // Для UserPromptSubmit или PostToolUse
    additionalContext?: string;
  };
}

Практические примеры

Логирование и мониторинг

const hooks = {
  PreToolUse: [
    {
      hooks: [
        async (input) => {
          // Логировать все использование инструментов
          await logToMonitoring({
            event: 'tool_use',
            tool: input.tool_name,
            input: input.tool_input,
            session: input.session_id
          });
          
          return { continue: true };
        }
      ]
    }
  ]
};

Валидация файловых операций

const hooks = {
  PreToolUse: [
    {
      matcher: "Write|Edit",
      hooks: [
        async (input) => {
          const filePath = input.tool_input.file_path;
          
          // Блокировать чувствительные файлы
          const sensitivePatterns = ['.env', '.git/', 'secrets/', '*.key'];
          
          for (const pattern of sensitivePatterns) {
            if (filePath.includes(pattern)) {
              return {
                decision: 'block',
                stopReason: `Нельзя изменять чувствительный файл, соответствующий ${pattern}`
              };
            }
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Автоформатирование кода

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;
          
          // Автоформатирование на основе типа файла
          if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
            await execAsync(`prettier --write "${filePath}"`);
          } else if (filePath.endsWith('.py')) {
            await execAsync(`black "${filePath}"`);
          }
          
          return { continue: true };
        }
      ]
    }
  ]
};

Улучшение промптов

const hooks = {
  UserPromptSubmit: [
    {
      hooks: [
        async (input) => {
          // Добавить контекст к промптам
          const projectContext = await loadProjectContext();
          
          return {
            continue: true,
            hookSpecificOutput: {
              hookEventName: 'UserPromptSubmit',
              additionalContext: `Контекст проекта: ${projectContext}`
            }
          };
        }
      ]
    }
  ]
};

Пользовательские инструкции сжатия

const hooks = {
  PreCompact: [
    {
      hooks: [
        async (input) => {
          const trigger = input.trigger; // 'manual' или 'auto'
          
          return {
            continue: true,
            systemMessage: 'Сосредоточьтесь на сохранении деталей реализации и разрешений ошибок'
          };
        }
      ]
    }
  ]
};

Поведение выполнения хуков

  • Параллелизация: Все соответствующие хуки выполняются параллельно
  • Тайм-аут: Хуки учитывают сигнал прерывания из опций
  • Обработка ошибок: Ошибки хуков логируются, но не останавливают выполнение
  • Сопоставители: Поддерживают шаблоны regex (например, "Write|Edit")

Комбинирование хуков с canUseTool

Хотя canUseTool обеспечивает контроль разрешений, хуки предлагают более широкую интеграцию жизненного цикла:

for await (const message of query({
  prompt: "Создайте функцию",
  options: {
    // Детальный контроль разрешений
    canUseTool: async (toolName, input) => {
      // Изменить входные данные или отклонить на основе условий времени выполнения
      return { behavior: "allow", updatedInput: input };
    },
    
    // Хуки жизненного цикла для мониторинга и автоматизации
    hooks: {
      PreToolUse: [
        {
          hooks: [
            async (input) => {
              // Логировать, валидировать или подготавливать
              return { continue: true };
            }
          ]
        }
      ]
    }
  }
})) {
  // Обработать сообщения
}

Контроль разрешений с canUseTool

Обратный вызов canUseTool обеспечивает детальный контроль над выполнением инструментов. Он вызывается перед каждым использованием инструмента и может разрешить, отклонить или изменить входные данные инструмента:

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

for await (const message of query({
  prompt: "Проанализируйте поведение пользователей и рассчитайте метрики",
  options: {
    mcpServers: {
      "analytics": analyticsServer
    },
    canUseTool: async (toolName: string, input: any) => {
      // Контролировать, какие инструменты можно использовать
      if (toolName.startsWith("mcp__analytics__")) {
        // Проверить разрешения для инструментов аналитики
        const hasPermission = await checkUserPermissions(toolName);
        
        return hasPermission
          ? { behavior: "allow", updatedInput: input }
          : { behavior: "deny", message: "Недостаточно разрешений" };
      }
      
      // Изменить входные данные для определенных инструментов
      if (toolName === "Bash") {
        // Добавить проверки безопасности или изменить команды
        const safeInput = sanitizeBashCommand(input);
        return { behavior: "allow", updatedInput: safeInput };
      }
      
      // Разрешить другие инструменты по умолчанию
      return { behavior: "allow", updatedInput: input };
    }
  }
})) {
  if (message.type === "result") console.log(message.result);
}

Случаи использования для canUseTool

  • Управление разрешениями: Проверить разрешения пользователя перед разрешением выполнения инструмента
  • Валидация входных данных: Валидировать или санитизировать входные данные инструмента перед выполнением
  • Ограничение скорости: Реализовать ограничения скорости для дорогих операций
  • Аудит логирования: Логировать использование инструментов для соответствия или отладки
  • Динамические разрешения: Включать/отключать инструменты на основе условий времени выполнения
// Пример: Ограничитель скорости веб-скрапинга
const rateLimits = new Map<string, { count: number; resetTime: number }>();

const canUseTool = async (toolName: string, input: any) => {
  // Ограничить скорость веб-скрапинга для предотвращения блокировки IP и проблем с квотой API
  if (toolName === "WebFetch" || toolName === "WebSearch") {
    const now = Date.now();
    const limit = rateLimits.get(toolName) || { count: 0, resetTime: now + 60000 };
    
    // Сбросить счетчик каждую минуту
    if (now > limit.resetTime) {
      limit.count = 0;
      limit.resetTime = now + 60000;
    }
    
    // Разрешить максимум 10 запросов в минуту
    if (limit.count >= 10) {
      return { 
        behavior: "deny", 
        message: `Превышен лимит скорости: максимум 10 ${toolName} запросов в минуту. Сброс через ${Math.ceil((limit.resetTime - now) / 1000)}с` 
      };
    }
    
    limit.count++;
    rateLimits.set(toolName, limit);
    
    // Логировать активность скрапинга для мониторинга
    console.log(`${toolName} запрос ${limit.count}/10 к: ${input.url || input.query}`);
  }
  
  // Предотвратить случайные бесконечные циклы в bash-скриптах
  if (toolName === "Bash" && input.command?.includes("while true")) {
    return { 
      behavior: "deny", 
      message: "Бесконечные циклы не разрешены" 
    };
  }
  
  return { behavior: "allow", updatedInput: input };
};

Форматы вывода

Текстовый вывод (по умолчанию)

// Текстовый вывод по умолчанию
for await (const message of query({
  prompt: "Объясните файл src/components/Header.tsx"
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
    // Вывод: Это React-компонент, показывающий...
  }
}

JSON-вывод

// Собрать все сообщения для JSON-подобного доступа
const messages = [];
for await (const message of query({
  prompt: "Как работает уровень данных?"
})) {
  messages.push(message);
}

// Доступ к результирующему сообщению с метаданными
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
});

Форматы ввода

// Прямой промпт
for await (const message of query({
  prompt: "Объясните этот код"
})) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

// Из переменной
const userInput = "Объясните этот код";
for await (const message of query({ prompt: userInput })) {
  if (message.type === "result" && message.subtype === "success") console.log(message.result);
}

Примеры интеграции агентов

SRE-агент реагирования на инциденты

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

// Автоматизированный агент реагирования на инциденты
async function investigateIncident(
  incidentDescription: string,
  severity = "medium"
) {
  const messages = [];

  for await (const message of query({
    prompt: `Инцидент: ${incidentDescription} (Серьезность: ${severity})`,
    options: {
      appendSystemPrompt: "Вы эксперт SRE. Диагностируйте проблему, оцените влияние и предоставьте немедленные действия.",
      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");
}

// Использование
const result = await investigateIncident("API платежей возвращает ошибки 500", "high");
console.log(result.result);

Автоматизированная проверка безопасности

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

async function auditPR(prNumber: number) {
  // Получить diff PR
  const prDiff = execSync(`gh pr diff ${prNumber}`, { encoding: 'utf8' });

  const messages = [];
  for await (const message of query({
    prompt: prDiff,
    options: {
      appendSystemPrompt: "Вы инженер по безопасности. Проверьте этот PR на уязвимости, небезопасные шаблоны и проблемы соответствия.",
      maxTurns: 3,
      allowedTools: ["Read", "Grep", "WebSearch"]
    }
  })) {
    messages.push(message);
  }

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

// Использование
const report = await auditPR(123);
console.log(JSON.stringify(report, null, 2));

Многоходовой юридический помощник

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

async function legalReview() {
  // Начать сессию юридической проверки
  let sessionId: string;

  for await (const message of query({
    prompt: "Начать сессию юридической проверки",
    options: { maxTurns: 1 }
  })) {
    if (message.type === "system" && message.subtype === "init") {
      sessionId = message.session_id;
    }
  }

  // Многоэтапная проверка с использованием той же сессии
  const steps = [
    "Проверить contract.pdf на пункты об ответственности",
    "Проверить соответствие требованиям GDPR",
    "Создать краткое изложение рисков для руководства"
  ];

  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(`Этап: ${step}`);
        console.log(message.result);
      }
    }
  }
}

Схема сообщений

Сообщения, возвращаемые из JSON API, строго типизированы согласно следующей схеме:

type SDKMessage =
  // Сообщение помощника
  | {
      type: "assistant";
      uuid: string;
      session_id: string;
      message: Message; // из Anthropic SDK
      parent_tool_use_id: string | null;
    }

  // Пользовательское сообщение (ввод)
  | {
      type: "user";
      uuid?: string;
      session_id: string;
      message: MessageParam; // из Anthropic SDK
      parent_tool_use_id: string | null;
    }

  // Пользовательское сообщение (вывод/воспроизведение с обязательным UUID)
  | {
      type: "user";
      uuid: string;
      session_id: string;
      message: MessageParam; // из Anthropic SDK
      parent_tool_use_id: string | null;
    }

  // Выдается как последнее сообщение при успехе
  | {
      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[];
    }

  // Выдается как последнее сообщение при ошибке или максимальном количестве ходов
  | {
      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[];
    }

  // Выдается как первое сообщение в начале разговора
  | {
      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>;
  }

Дополнительные поддерживающие типы:

Типы Message, MessageParam и Usage доступны в Anthropic TypeScript SDK.

Связанные ресурсы