O SDK de JavaScript da TypeSafe faz uma coisa que o de Python não consegue
fazer do mesmo jeito: ele deriva o tipo da resposta a partir das perguntas
que você escreveu. Se a sua pergunta é um choice com as opções billing,
technical e other, o editor sabe que answers.category.choice só pode ser
uma dessas três strings.
Para quem está chegando agora: o Jev é o modelo da TypeSafe AI que não gera texto. Você manda um conteúdo e um mapa de perguntas tipadas, e recebe decisões com probabilidade. O passo a passo geral está em primeiros passos.
Instalação e chave
npm install @typesafe-ai/sdk
A documentação indica Node.js 20 ou mais novo. Depois, defina
TYPESAFE_API_KEY no ambiente. O cliente lê essa variável sozinho, e a ordem
de precedência é explícita na documentação: opções passadas no construtor vêm
antes das variáveis de ambiente, que vêm antes dos padrões do SDK. Valores de
ambiente vazios ou só com espaço são ignorados.
A primeira chamada
import { choice, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const response = await client.systemOne({
state: { document: "I was charged twice. Please fix this ASAP." },
questions: {
category: choice("What is this ticket about?", {
billing: null,
technical: null,
other: null,
}),
},
});
console.log(response.answers.category.choice);
Duas coisas valem nota. A descrição de cada opção pode ser null quando o nome
já basta — embora, na prática, descrever separe melhor, como discutido em
critérios que separam. E o state aceita
string, objeto ou lista de textos, como no resto da API.
Os três ajudantes
O SDK expõe uma função por primitiva, e as assinaturas documentadas são estas:
| Ajudante | Assinatura | O que exige |
|---|---|---|
choice | choice(instructions, criteria) | rótulos mapeados para descrições, ou null |
score | score(instructions, criteria) | pelo menos duas descrições, indexadas a partir de zero |
noul | noul(instructions?, criteria?) | os dois parâmetros são opcionais |
Em todos eles, instructions aceita texto, objeto JSON, lista ou null — o
mesmo tipo de entrada estruturada descrito em
estrutura avançada.
Um exemplo com as três primitivas na mesma chamada, que é o jeito recomendado:
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
const client = new TypeSafeClient();
const { answers, model, usage } = await client.systemOne({
state: {
mensagem: "Fiz a atualização ontem e o sistema não abre. Preciso disso hoje.",
plano: "Empresarial",
},
questions: {
categoria: choice("Qual o assunto principal deste ticket?", {
duvida_tecnica: "Algo não funciona, dá erro ou o cliente não sabe usar.",
cobranca: "Fatura, valor, estorno ou forma de pagamento.",
outro: "Não se encaixa nas categorias acima.",
}),
urgencia: score("Qual a urgência do pedido?", [
"Nenhuma pressa declarada.",
"Quer resposta nos próximos dias.",
"Cita prazo curto ou impacto no trabalho.",
"Operação parada agora.",
]),
pede_reembolso: noul("O cliente pede estorno ou reembolso?"),
},
});
if (answers.categoria.confidence < 0.6) {
filaHumana();
} else {
encaminhar(answers.categoria.choice, answers.urgencia.score);
}
console.log(model, usage.input_tokens);
As três perguntas viajam juntas de propósito: o state entra uma vez e cada
pergunta soma apenas os próprios tokens. O motivo está em
várias perguntas numa chamada.
O que muda em relação ao Python
Se você já leu a página do SDK Python, estas são as diferenças que importam na prática:
| Python | JavaScript | |
|---|---|---|
| Método | client.system_one(...) | client.systemOne({...}) |
| Perguntas | classes Choice, Score, Noul | funções choice(), score(), noul() |
| Leitura | answers, mais nouls, choices e scores | só response.answers |
| Tipos da resposta | anotados pelo SDK | inferidos das suas perguntas |
| Retentativa | segundos (backoff_initial=0.5) | milissegundos (backoffInitialMs: 500) |
| Tempo limite padrão | 10,0 s por operação HTTP | configurável em timeout, por tentativa |
O modelo padrão é o mesmo nos dois: jev-latest. Sobre fixar a versão em vez
de usar o alias, veja
modelos e aliases.
Configuração do cliente
O cliente expõe, como propriedades somente leitura, a configuração efetiva:
baseURL, defaultHeaders, defaultModel, fetch, logger, logLevel,
models, retry e timeout. Isso é mais útil do que parece — em um
diagnóstico, dá para logar a configuração que o cliente realmente montou, em
vez de supor.
A fetch ser injetável é o detalhe que resolve teste: você passa a sua própria
implementação e testa o fluxo inteiro sem rede.
const client = new TypeSafeClient({
timeout: 8000,
retry: { maxRetries: 3, backoffInitialMs: 250 },
defaultModel: "jev-1.13.0",
});
Sobrescritas parciais de retentativa herdam os campos não informados do cliente ou dos padrões do SDK. Os valores padrão e o comportamento completo estão em retentativas e tempo limite.
Os erros que o systemOne lança
A documentação da classe lista quatro situações:
- Validação local: perguntas vazias, ou
criteriade Score que não é uma lista de pelo menos duas entradas. Esse erro acontece antes da rede. - Resposta não 2xx depois das retentativas.
- Falha de conexão ou tempo esgotado depois das retentativas.
- Cancelamento pelo chamador.
O tratamento de cada código de status está em erros e exceções.
Por onde continuar
Para a versão em Python do mesmo fluxo, SDK Python. Para chamar sem SDK nenhum, a API HTTP sem SDK. Para testar um texto em português antes de escrever código, use o playground.
Perguntas frequentes
Como instalo o SDK JavaScript do Jev?
Com npm install @typesafe-ai/sdk. A documentação oficial indica Node.js 20 ou mais novo. O cliente lê a chave da variável de ambiente TYPESAFE_API_KEY, e o pacote traz ESM, CommonJS e declarações TypeScript.
Preciso usar TypeScript?
Não, o pacote funciona em JavaScript puro. Mas o principal ganho do SDK é a inferência de tipos: os tipos das respostas são derivados das perguntas que você escreveu, e isso só aparece no editor com TypeScript.
O que muda em relação ao SDK Python?
O método chama-se systemOne em vez de system_one, as perguntas são criadas pelos ajudantes choice, score e noul em vez das classes Choice, Score e Noul, e não há acessores separados por tipo: tudo sai de response.answers. Os tempos de retentativa em JavaScript são em milissegundos.
Como configuro o tempo limite e a retentativa?
Pelo construtor do cliente ou por chamada. Os padrões documentados são 2 retentativas, backoff inicial de 500 ms dobrando até 5.000 ms, jitter de 0,25, repetição nos status 408, 429 e 500 a 599, com Retry-After respeitado até 60.000 ms.
Que erros o systemOne pode lançar?
A documentação lista quatro situações: perguntas vazias ou criteria de Score com menos de duas entradas; resposta não 2xx depois das retentativas; falha de conexão ou tempo esgotado depois das retentativas; e cancelamento pelo chamador.