JavaScript / TypeScript
A jangada também existe para JavaScript e TypeScript, no pacote npm
jangada-ai. A ideia é a mesma da
lib Python: trocar provider, modelo e chave sem mudar o resto do código, com
retry e fallback por tipo de erro, structured output, tools, streaming e custo em
cada resposta.
O código-fonte é TypeScript, mas o pacote publicado é JavaScript (ESM e
CommonJS) com os tipos (.d.ts) junto. Funciona em projeto JS puro; em TS você
ganha autocompletar e checagem de tipos.
Versão atual: 1.0.2, com paridade com a lib Python: 11 providers, tools, MCP, agentes, RAG, eval, A2A, guardrails, cache e observability (ver O que vem no pacote).
Instalação
npm install jangada-aiOs SDKs dos providers são dependências opcionais: instale só os que for usar.
A lib importa o SDK apenas quando o provider é chamado, então import "jangada-ai"
funciona sem nenhum deles.
| Provider | Instale |
|---|---|
openai, azure, groq, openrouter, deepseek | npm install openai |
anthropic | npm install @anthropic-ai/sdk |
gemini, vertex, GeminiInteractions | npm install @google/genai (Interactions exige 1.33+) |
bedrock | npm install @aws-sdk/client-bedrock-runtime |
mistral | npm install @mistralai/mistralai |
ollama | nada (fala HTTP direto com o servidor) |
| structured output com Zod | npm install zod |
| PDF, DOCX e XLSX no prompt | npm install unpdf mammoth exceljs (PDF como imagem: @napi-rs/canvas) |
| MCP (cliente e servidor) | npm install @modelcontextprotocol/sdk (Code Mode: quickjs-emscripten) |
| RAG no Postgres / MongoDB | npm install pg / npm install mongodb |
Roda em Node 22 ou mais novo, Bun, Deno e runtimes edge (Cloudflare Workers,
Vercel Edge). O núcleo não usa o sistema de arquivos. Ler arquivo e .env fica
no subpath jangada-ai/node.
Primeira chamada
JavaScript (ESM):
import { LLM } from "jangada-ai";
import "jangada-ai/node"; // carrega o .env do projeto (OPENAI_API_KEY...)
const llm = new LLM("openai", "gpt-4o-mini");
const comp = await llm.complete("Explique o que é uma jangada em uma frase.");
console.log(comp.text, comp.usage, comp.cost);JavaScript (CommonJS):
const { LLM } = require("jangada-ai");TypeScript é igual, com os tipos inferidos.
Trocar de provider é trocar duas strings:
new LLM("anthropic", "claude-sonnet-4-5");
new LLM("gemini", "gemini-2.5-flash");
new LLM("groq", "openai/gpt-oss-20b");Templates, params e fallback
const llm = new LLM("openai", "gpt-4o-mini", {
system: "Você atende a {{ empresa }}.",
temperature: 0.3,
maxRetries: 2, // 429, 5xx e timeout repetem no mesmo modelo
fallbacks: [new LLM("anthropic", "claude-haiku-4-5")], // depois, outro provider
});
const comp = await llm.complete("Olá, sou {{ nome }}.", {
variables: { empresa: "Padaria Pão Quente", nome: "Ana" },
});Os params canônicos são temperature, maxTokens (padrão 8192), topP, topK,
stop e seed. Cada adapter traduz para o nome nativo e descarta o que o
provider não aceita. Params específicos de um provider vão em extra.
Toda chamada aceita signal (AbortSignal) para cancelar, inclusive retries e
fallbacks pendentes.
Structured output
Com Zod 4.2 ou mais novo, parsed vem validado e tipado:
import * as z from "zod";
const Pessoa = z.object({ nome: z.string(), idade: z.number().int() }).meta({ title: "Pessoa" });
const comp = await llm.parse("Ana tem 30 anos.", Pessoa);
comp.parsed; // { nome: "Ana", idade: 30 }Também aceita JSON Schema puro (jsonSchema(objeto, { validate })) e outras
libs que seguem o padrão Standard Schema. JSON fora do schema vira
OutputValidationError, que cai para o próximo fallback.
Tools
import { tool } from "jangada-ai";
const clima = tool({
name: "clima",
description: "Temperatura atual de uma cidade",
parameters: z.object({ cidade: z.string() }),
execute: async ({ cidade }) => ({ cidade, temperatura: 31 }),
});
const comp = await llm.complete("Como está o tempo em Recife?", { tools: [clima] });
for (const call of comp.toolCalls) {
const args = await clima.parseArgs(call.args);
const resultado = call.result(await clima.execute(args));
// reenvie: history = [..., comp.assistantMessage(), { role: "tool", content: [resultado] }]
}Tools nativas, que o provider executa: webSearch(), webFetch(),
codeExecution(), fileSearch(), googleMaps(), computerUse(). Funcionam
na OpenAI e Azure (Responses API), Anthropic, Gemini, Groq, Bedrock e Mistral,
cada um com o que o provider oferece.
Streaming
for await (const pedaco of llm.stream("Conte até 5.")) process.stdout.write(pedaco);
for await (const ev of llm.streamComplete("Uma curiosidade sobre o Recife.")) {
if (ev.type === "text") process.stdout.write(ev.text);
else console.log(ev.completion.cost); // resposta completa: toolCalls, usage, custo
}Vision e arquivos
import { readImage } from "jangada-ai/node";
await llm.complete("Descreva a imagem.", { images: [await readImage("foto.jpg")] });
await llm.complete("E esta?", { images: ["https://exemplo.com/foto.png"] });No núcleo (edge), passe Image.fromBytes(...), uma data URI ou uma URL.
Agentes
import { Agent, Squad, tool } from "jangada-ai";
const atendente = new Agent(llm, { role: "Atendente", tools: [clima] });
const r = await atendente.run("Qual o clima em Recife?");
console.log(r.text, r.cost, r.toolTrace);
const pesquisador = new Agent(llm, { role: "Pesquisador", goal: "listar fatos curtos" });
const redator = new Agent(llm, { role: "Redator", goal: "escrever uma frase" });
await new Squad([pesquisador, redator]).run("jangadas no Ceará");Flow e Graph também existem. No Graph, a ligação entre nós é connect()
(no Python é then(), que em JS tornaria o objeto "thenable").
MCP
import { MCPClient, runAgent } from "jangada-ai/mcp";
import { serveMcp } from "jangada-ai/node";
// servir tools da jangada como servidor MCP
const srv = await serveMcp([clima], { transport: "http", port: 3333 });
// consumir um servidor MCP
await using mcp = await new MCPClient({ url: "https://meu-mcp/mcp" }).connect();
const r = await runAgent(llm, "Use as tools do servidor.", { client: mcp });await using fecha a conexão no fim do bloco. Quem conecta é o connect().
RAG
import { RAG, vectorStore } from "jangada-ai/rag";
const store = vectorStore(process.env.DATABASE_URL); // postgresql://, mongodb:// ou "memory"
const rag = new RAG(new LLM("openai", "text-embedding-3-small"), store, { chat: llm });
await rag.syncTexts(["A padaria abre às 6h.", "Aceitamos PIX."], { documentId: "faq" });
const resposta = await rag.ask("Como posso pagar?");O esquema no Postgres e no MongoDB é o mesmo da lib Python, inclusive o hash dos chunks e o lock da indexação incremental. Python e JS podem usar o mesmo banco.
A2A e eval
import { serveA2a } from "jangada-ai/node";
await serveA2a(atendente, { port: 4000 }); // Agent Card em /.well-known/agent-card.json
import { Dataset, Evaluator, evaluate } from "jangada-ai/eval";
const res = await evaluate(dataset, (ex) => llm.complete(ex.inputs.q), [
Evaluator.fn("exato", (saida, ref) => saida.text.trim() === ref),
]);Em edge, use buildA2aHandler de jangada-ai/a2a: ele devolve um handler
(Request) => Promise<Response>.
Diferenças em relação ao Python
| Tema | Python | JavaScript / TypeScript |
|---|---|---|
| Async | complete e acomplete | só complete (Promise) |
| Nomes | max_tokens, tool_calls | maxTokens, toolCalls |
| Variáveis do template | complete(prompt, nome="Ana") | complete(prompt, { variables: { nome: "Ana" } }) |
| Structured output | classe Pydantic | Zod, Standard Schema ou JSON Schema |
| Tools | função Python vira tool pela assinatura | tool({ name, parameters, execute }) |
.env | carregado no import jangada_ai | carregado no import "jangada-ai/node" |
| Cancelamento | não tem | signal em todas as chamadas |
| Backoff, TTL e polling | segundos | milissegundos (backoffBaseMs, pollIntervalMs) |
Graph | then() | connect() |
| A2A | app Starlette | handler Request => Response (buildA2aHandler) ou serveA2a |
| Arquivos do disco | Document("arq.pdf") | readDocument("arq.pdf") de jangada-ai/node |
O que vem no pacote
| Import | O que tem |
|---|---|
jangada-ai | LLM (complete, parse, stream, streamComplete, embed, transcribe), templates, retry e fallback, erros normalizados, custo por resposta, profiles, tools e tools nativas, vision e documentos, cache exato e semântico, guardrails, Flow, Graph, Agent, Squad, stepBack, plan, detectObjects, GeminiInteractions, observability e prompt registry |
jangada-ai/node | ler arquivo e .env, runInSession, serveMcp, serveA2a |
jangada-ai/mcp | MCPClient, runAgent, servidor MCP e Code Mode |
jangada-ai/rag | RAG, chunking (inclusive semântico), rerank, stores em memória, pgvector e MongoDB |
jangada-ai/eval | Dataset, Evaluator, evaluate |
jangada-ai/prebuilt | tools prontas: calculadora, CPF/CNPJ, CEP, Wikipedia, busca web, clima, HTTP |
jangada-ai/a2a | servidor A2A web-standard |
Providers: OpenAI, Azure OpenAI, Groq, OpenRouter, DeepSeek, Anthropic, Gemini, Vertex, Bedrock, Mistral e Ollama. As diferenças assumidas em relação ao Python estão na tabela acima.