O Modelo Mental do SDK TypeScript da Anthropic
O pacote @anthropic-ai/sdk é o cliente oficial TypeScript e JavaScript para a API Claude.
A maioria dos desenvolvedores o encontra como npm install @anthropic-ai/sdk, seguido por uma única chamada messages.create, e essa chamada funciona bem como uma primeira impressão.
Mas a forma real do SDK só fica clara quando você entende as poucas decisões de design por trás dele: ele é construído sobre fetch em vez de uma pilha HTTP específica para Node, ele modela uma resposta de streaming como um iterável assíncrono em vez de um stream de callbacks, e ele utiliza as uniões discriminadas do TypeScript para que o compilador, e não sua memória, rastreie qual forma de dado você está segurando em qualquer ponto.
Esta página constrói esse modelo mental antes que você escreva qualquer código de produção contra o SDK.
Resumo
- Ideia Central:
@anthropic-ai/sdké um cliente fino, baseado emfetch, que transforma chamadas HTTP para a API Claude em objetos tipados e iteráveis assíncronos. - Por que Importa: Como depende apenas de
fetch, o mesmo código do cliente roda em Node.js, Vercel Edge Functions, Cloudflare Workers e Deno Deploy sem uma compilação específica para o runtime. - Conceitos Chave: instanciação do cliente, a API Messages, streaming via iteradores assíncronos, blocos de conteúdo de união discriminada, configuração de retentativa e cancelamento, classes de erro tipadas.
- Quando Usar: Utilize este SDK sempre que estiver chamando Claude a partir de TypeScript ou JavaScript, seja um backend Node, uma função serverless ou um middleware edge.
- Limitações / Trade-offs: O SDK é uma camada de transporte e tipagem, não um framework de agente. Ele não gerencia estado de conversa, loops de execução de ferramentas ou memória para você.
- Tópicos Relacionados: a forma de requisição/resposta da API Messages, definições de ferramentas com Zod, configuração de retentativa e timeout, endpoints de chat de streaming no Next.js.
Fundamentos
Em sua essência, o SDK é um wrapper em torno de requisições HTTP para a API Claude.
Você constrói um cliente Anthropic, geralmente uma vez por processo ou por requisição, e cada chamada subsequente é um método nesse cliente.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});O objeto cliente é deliberadamente sem grandes destaques.
Ele contém sua chave de API, sua URL base e suas opções de requisição padrão (timeouts, retentativas, cabeçalhos), e expõe namespaces de recursos como client.messages que agrupam métodos relacionados.
Chamar client.messages.create(...) envia uma única requisição HTTP e resolve com um objeto JavaScript simples assim que a resposta chega.
Esse objeto não é uma instância de classe especial com comportamento oculto. É JSON, tipado.
Uma analogia útil é que o SDK está mais próximo de um wrapper fetch bem tipado do que de um framework com estado.
Ele não abre uma conexão persistente, não se lembra de turnos anteriores de uma conversa para você, e não decide quando chamar uma ferramenta.
Cada uma dessas responsabilidades permanece no código da sua aplicação. O trabalho do SDK é mais restrito: transformar um objeto de requisição em uma chamada HTTP validada, e transformar a resposta de volta em dados TypeScript tipados.
Mecânicas e Interações
Por que a arquitetura baseada em fetch importa
A maioria dos clientes HTTP no ecossistema Node é construída sobre os módulos http e https do próprio Node, que só existem em um processo Node.js.
O SDK TypeScript da Anthropic, em vez disso, constrói sua camada de requisição sobre a API fetch padrão, usando uma implementação fetch compatível com Node quando executando no Node e o fetch nativo do runtime em todos os outros lugares.
Essa única escolha é o que permite que a mesma importação, a mesma construção de cliente e a mesma chamada messages.create rodem sem modificação em uma Vercel Edge Function, um Cloudflare Worker ou um Deno Deploy isolate, nenhum dos quais expõe o módulo http do Node.
Na prática, isso significa que você não escolhe uma "compilação para navegador" versus uma "compilação para servidor" do SDK.
Você escolhe onde executar seu código, e o SDK se adapta porque sua camada mais baixa assume apenas a presença de fetch, ReadableStream e AbortController, todos os quais são padrões em runtimes JavaScript modernos.
Streaming como um iterável assíncrono, não eventos
Uma chamada não-streaming espera pelo corpo completo da resposta antes de resolver.
Uma chamada de streaming é diferente: o servidor envia a resposta como uma sequência de eventos server-sent, um por token ou por mudança estrutural, e o trabalho do SDK é transformar esse stream de eventos brutos em algo que você possa consumir incrementalmente.
Muitas bibliotecas de cliente HTTP expõem streaming como um EventEmitter, onde você registra callbacks on("data", ...) e on("end", ...) e gerencia o estado entre as chamadas você mesmo.
O SDK da Anthropic, em vez disso, retorna um objeto de stream que é ele próprio um iterável assíncrono, então você o consome com um loop for await padrão.
const stream = client.messages.stream({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain async iterators." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta") {
process.stdout.write(event.delta.text ?? "");
}
}A mudança de mentalidade aqui importa mais do que a sintaxe.
Um modelo de listener de eventos força você a construir seu próprio acumulador e sua própria noção de "pronto", geralmente com uma variável mutável que vive fora do callback.
Um modelo de iterável assíncrono permite que o fluxo de controle da sua própria função expresse essa lógica: o corpo do loop executa uma vez por evento, e o loop simplesmente termina quando o stream termina, sem um manipulador "on end" separado para manter em sincronia.
O objeto stream também expõe métodos de conveniência, como esperar pela mensagem final montada, então você não é obrigado a concatenar deltas manualmente quando só se importa com o resultado final.
Uniões discriminadas moldam como você escreve código
Uma resposta Claude não é uma forma fixa.
Uma única mensagem pode conter um bloco de texto, um bloco de uso de ferramenta e (quando o pensamento estendido é habilitado) um bloco de pensamento, em qualquer combinação e ordem.
O SDK modela isso com uma união discriminada: cada tipo de bloco de conteúdo compartilha um campo type, e o valor literal desse campo ("text", "tool_use", "thinking") é o que o TypeScript usa para estreitar o tipo.
for (const block of message.content) {
switch (block.type) {
case "text":
console.log(block.text);
break;
case "tool_use":
console.log(block.name, block.input);
break;
}
}Uma vez que você ramifica em block.type, o compilador já sabe quais outros campos existem em block dentro desse ramo, text dentro do caso "text", name e input dentro do caso "tool_use", sem uma asserção de tipo manual.
É por isso que ler respostas Claude em TypeScript tende a parecer um controle de fluxo em uma tag, em vez de encadeamento opcional através de um blob de tipagem frouxa.
O mesmo padrão de união discriminada se estende a eventos de streaming (content_block_start, content_block_delta, message_stop, e outros), então a forma do código que você escreve para lidar com um stream espelha a forma do código que você escreve para lidar com uma mensagem finalizada.
Considerações Avançadas e Aplicações
Resiliência é configuração, não código que você escreve
Chamadas de rede falham, expiram e ocasionalmente sofrem limitação de taxa, e o SDK trata todos os três como configuração de primeira classe em vez de problemas que você resolve com seu próprio loop de retentativa.
Você pode definir maxRetries e timeout globalmente no cliente ou por chamada, e o SDK aplica backoff exponencial para falhas retryáveis (erros de servidor, erros de conexão, limites de taxa) automaticamente.
Para cancelamento, o SDK aceita um sinal AbortController padrão em qualquer chamada, o que permite vincular a vida útil de uma requisição Claude a algo externo, um usuário fechando um painel de chat, um manipulador de requisição HTTP sendo cancelado, ou um timeout que você controla.
const controller = new AbortController();
setTimeout(() => controller.abort(), 5000);
await client.messages.create(
{ model: "claude-sonnet-5", max_tokens: 256, messages: [...] },
{ signal: controller.signal },
);Como AbortController é um padrão web em vez de uma API Node, esse mecanismo de cancelamento funciona identicamente em um navegador, uma função edge ou um servidor Node, que é a mesma história de portabilidade do transporte baseado em fetch por baixo dele.
Erros tipados em vez de análise de código de status
Quando uma requisição falha, o SDK lança uma classe de erro específica em vez de um erro HTTP genérico com um status numérico anexado.
BadRequestError, RateLimitError, AuthenticationError, e APIConnectionError são classes distintas, então um bloco catch pode ramificar com instanceof em vez de inspecionar um código de status e esperar que a forma do corpo do erro corresponda ao que você espera.
try {
await client.messages.create({ ... });
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
// back off and retry later
} else if (error instanceof Anthropic.APIConnectionError) {
// network-level failure, not an API rejection
}
}Isso importa mais em código de produção que precisa se comportar de maneira diferente para diferentes classes de falha: um limite de taxa geralmente significa "esperar e tentar novamente", um erro de autenticação geralmente significa "parar e alertar", e um erro de conexão geralmente significa "o problema é a rede, não Claude".
Onde a responsabilidade do SDK termina
Um padrão de produção comum é conectar client.messages.stream() a um manipulador de rota Next.js para que o manipulador encaminhe o stream de tokens do Claude diretamente para o navegador como uma resposta de chat token por token.
O SDK torna esse padrão natural porque seu stream já é um iterável assíncrono e o transporte subjacente já é compatível com fetch com runtimes edge, mas o SDK em si não sabe nada sobre Next.js, sua estrutura de rota, ou como você apresenta a saída parcial a um usuário.
Ele também não gerencia o histórico de conversas multi-turno (você reenvia mensagens anteriores), e não executa um loop de chamada de ferramenta para você (você inspeciona blocos tool_use e decide se e como executá-los).
Tratar o SDK como "transporte tipado, não orquestração" evita que você espere comportamento de framework de agente de uma biblioteca cliente.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
messages.create não-streaming | Código mais simples, uma resposta aguardada | O usuário espera pela conclusão inteira antes de ver qualquer coisa | Tarefas em lote, chamadas backend-a-backend sem UI ao vivo |
messages.stream com for await | Tokens aparecem conforme são gerados, fluxo de controle natural | Código um pouco mais complexo para montar estado parcial se você também precisar da mensagem completa | UIs de chat, qualquer lugar onde a latência percebida importa |
| Streaming com o helper de mensagem final embutido | Obtenha atualizações incrementais da UI e a mensagem final de uma única chamada | Mantém a resposta completa em memória até que o stream termine | UIs de chat que também precisam persistir a mensagem concluída |
Conceitos Equivocados Comuns
- "Streaming requer um cliente diferente ou um pacote diferente." Não requer. O mesmo cliente
Anthropice o mesmo namespacemessagesexpõem tantocreate(não-streaming) quantostream(streaming); streaming é uma escolha de método, não uma instalação separada. - "O SDK só funciona no Node.js porque é um pacote npm." Ser distribuído no npm não tem relação com o runtime em que ele pode ser executado. Como seu transporte é baseado em
fetch, ele roda em qualquer ambiente que implemente os padrõesfetch,ReadableStreameAbortController, o que inclui a maioria dos runtimes edge modernos. - "Uniões discriminadas são apenas decoração TypeScript; os dados reais são um objeto solto." O campo
typeno qual a união se estreita é o mesmo campo que a API realmente retorna, então a tipagem não é aspiracional. Estreitar emblock.typereflete uma diferença estrutural real na resposta, não uma camada de conveniência adicionada por cima. - "Você precisa analisar manualmente eventos server-sent para construir um recurso de streaming." O SDK já analisa o formato de comunicação SSE para você e expõe o resultado como um iterável assíncrono de eventos tipados; você nunca toca em texto de evento bruto a menos que deliberadamente desça abaixo da abstração do SDK.
- "Retentativas duplicarão silenciosamente efeitos colaterais se uma requisição falhar parcialmente." O SDK apenas retenta requisições que julga seguras para retentar (falhas de conexão, certos erros de servidor, limites de taxa) antes que uma resposta seja recebida, não depois de um sucesso parcial; ele não retenta uma vez que seu código já começou a consumir um stream.
FAQs
Que problema o @anthropic-ai/sdk realmente resolve?
- Ele transforma chamadas HTTP brutas para a API Claude em objetos TypeScript tipados e iteráveis assíncronos.
- Ele lida com cabeçalhos de autenticação, retentativas, timeouts e classificação de erros para que você não os implemente manualmente.
- Ele fornece tipos verificados pelo compilador para requisições e respostas em vez de JSON de tipagem frouxa.
Por que é importante que o SDK seja construído sobre fetch em vez do módulo http do Node?
Como fetch é um padrão web implementado por Node, navegadores e runtimes edge igualmente, o mesmo código do SDK roda sem modificação em uma Vercel Edge Function, um Cloudflare Worker ou um Deno Deploy isolate, nenhum dos quais tem o módulo http do Node disponível.
Como preparo uma instância de cliente para fazer requisições?
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });Uma instância de cliente é suficiente para muitas requisições; ela apenas armazena sua configuração.
Como o streaming difere de uma chamada normal messages.create?
messages.createresolve uma vez com a resposta completa.messages.streamretorna um objeto sobre o qual você itera, recebendo eventos parciais conforme o Claude os gera.- Ambos vivem no mesmo namespace
client.messages, então alternar entre eles é uma escolha de método, não um cliente diferente.
O que significa que o stream é um "iterável assíncrono"?
Significa que você pode consumi-lo com um loop for await (const event of stream) padrão, permitindo que o corpo do seu próprio loop reaja a cada evento à medida que ele chega, em vez de registrar callbacks separados on("data") e on("end") de listener de eventos e rastrear o estado de conclusão sozinho.
O que é uma união discriminada, no contexto deste SDK?
É um padrão TypeScript onde cada bloco de conteúdo possível compartilha um campo comum type ("text", "tool_use", "thinking"), e verificar o valor desse campo permite que o compilador restrinja quais outros campos estão disponíveis naquele bloco específico, sem uma conversão de tipo manual.
Preciso escrever minha própria lógica de retentativa para requisições instáveis?
Não. O SDK aceita uma opção maxRetries (em todo o cliente ou por chamada) e aplica backoff automaticamente para falhas retryáveis como erros de conexão, certos erros de servidor e limites de taxa.
Como cancelo uma requisição em andamento?
Passe o signal de um AbortController como uma opção de requisição e chame controller.abort() quando quiser cancelar; isso funciona da mesma forma em Node, navegadores e runtimes edge porque AbortController é um padrão web, não uma API específica do Node.
Como devo lidar com erros do SDK?
Capture a chamada e verifique instanceof contra as classes de erro tipadas do SDK (RateLimitError, BadRequestError, AuthenticationError, APIConnectionError, e outras) para que sua lógica de tratamento corresponda ao tipo real de falha em vez de analisar um código de status.
O SDK gerencia o histórico de conversas para mim?
Não. Você é responsável por construir o array messages em cada chamada, incluindo turnos anteriores que você deseja que o Claude veja. O SDK envia exatamente o que você fornece e não persiste o estado entre as chamadas.
O SDK executa loops de chamada de ferramenta automaticamente?
Não. Quando o Claude quer usar uma ferramenta, a resposta inclui um bloco de conteúdo tool_use; seu código é responsável por lê-lo, executar a lógica correspondente e enviar o resultado de volta em uma chamada subsequente.
Quando eu escolheria não-streaming em vez de streaming?
Escolha não-streaming para chamadas backend-a-backend, processamento em lote ou qualquer lugar onde nenhum humano esteja observando a saída chegar ao vivo, pois é um código mais simples sem manipulação de eventos parciais. Escolha streaming sempre que a latência percebida em uma UI importar.
A tipagem do SDK é puramente para conveniência do editor, ou reflete a API real?
Reflete a API real. Os campos de união discriminada (como type em um bloco de conteúdo) são os mesmos campos que a API Claude realmente retorna na rede, então o estreitamento em TypeScript corresponde a uma distinção estrutural real na resposta, não a uma camada cosmética.
Relacionados
- Noções Básicas do SDK TypeScript/JavaScript - instalando o pacote e fazendo sua primeira chamada tipada.
- Iteradores Assíncronos para Streaming no SDK TypeScript - um guia mais aprofundado sobre o consumo de eventos transmitidos.
- Executando o SDK da Anthropic em Runtimes Edge - o que a arquitetura baseada em fetch significa na prática no Vercel Edge e Cloudflare Workers.
- Padrões de Retentativa, Timeout e AbortController no SDK TypeScript - configurando resiliência em profundidade.
- Referência de Tipos do SDK TypeScript para Blocos de Conteúdo - o catálogo completo de uniões discriminadas.
- Referência de Classes de Erro do SDK TypeScript - cada classe de erro tipada e quando ela é lançada.
Versões da Stack: Escrito contra a linha de modelos Claude atual em ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão), e Claude Haiku 4.5 - e o SDK oficial
@anthropic-ai/sdkTypeScript (última versão). Nomes de modelos, versões de SDK e preços mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.