Jangada AIJangada AI

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-ai

Os 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.

ProviderInstale
openai, azure, groq, openrouter, deepseeknpm install openai
anthropicnpm install @anthropic-ai/sdk
gemini, vertex, GeminiInteractionsnpm install @google/genai (Interactions exige 1.33+)
bedrocknpm install @aws-sdk/client-bedrock-runtime
mistralnpm install @mistralai/mistralai
ollamanada (fala HTTP direto com o servidor)
structured output com Zodnpm install zod
PDF, DOCX e XLSX no promptnpm 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 / MongoDBnpm 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

TemaPythonJavaScript / TypeScript
Asynccomplete e acompletesó complete (Promise)
Nomesmax_tokens, tool_callsmaxTokens, toolCalls
Variáveis do templatecomplete(prompt, nome="Ana")complete(prompt, { variables: { nome: "Ana" } })
Structured outputclasse PydanticZod, Standard Schema ou JSON Schema
Toolsfunção Python vira tool pela assinaturatool({ name, parameters, execute })
.envcarregado no import jangada_aicarregado no import "jangada-ai/node"
Cancelamentonão temsignal em todas as chamadas
Backoff, TTL e pollingsegundosmilissegundos (backoffBaseMs, pollIntervalMs)
Graphthen()connect()
A2Aapp Starlettehandler Request => Response (buildA2aHandler) ou serveA2a
Arquivos do discoDocument("arq.pdf")readDocument("arq.pdf") de jangada-ai/node

O que vem no pacote

ImportO que tem
jangada-aiLLM (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/nodeler arquivo e .env, runInSession, serveMcp, serveA2a
jangada-ai/mcpMCPClient, runAgent, servidor MCP e Code Mode
jangada-ai/ragRAG, chunking (inclusive semântico), rerank, stores em memória, pgvector e MongoDB
jangada-ai/evalDataset, Evaluator, evaluate
jangada-ai/prebuilttools prontas: calculadora, CPF/CNPJ, CEP, Wikipedia, busca web, clima, HTTP
jangada-ai/a2aservidor 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.

On this page