npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gabrielonrails/axon-sdk

v0.1.0

Published

SDK Node/TypeScript da Axon — envie transcrições de agentes de IA e receba boletins de qualidade A–F.

Readme

@gabrielonrails/axon-sdk

SDK Node/TypeScript da Axon — a camada de qualidade para agentes de IA. Envie transcrições de conversas e a Axon devolve um boletim A–F por dimensão, com evidência citada, causa-raiz e correção.

Instalação

npm install @gabrielonrails/axon-sdk
# ou: pnpm add @gabrielonrails/axon-sdk / yarn add @gabrielonrails/axon-sdk

Requer Node 18+ (usa fetch nativo).

Gerando uma chave de API

No app da Axon: Configurações → Integração → Chaves de API → Gerar chave. A chave (axon_sk_…) é exibida uma única vez — guarde em uma variável de ambiente. Defina AXON_API_KEY.

Uso

import { Axon } from "@gabrielonrails/axon-sdk";

const axon = new Axon({
  apiKey: process.env.AXON_API_KEY!,
  // baseUrl: "https://axon-dev.com", // default
});

const result = await axon.ingest("cobranca", [
  {
    id: "conv-001", // opcional — torna o reenvio idempotente
    channel: "voz", // "voz" | "chat" | "whatsapp"
    turns: [
      { role: "client", text: "Quero um desconto." },
      { role: "agent", text: "Posso aplicar 20% de desconto agora mesmo." },
    ],
  },
]);

console.log(result);
// { accepted: 1, agent: { id, name }, conversation_ids: [...], status: "evaluating" }

Açúcar sintático equivalente:

await axon.agent("cobranca").ingest([{ turns: [...] }]);

O agente é criado automaticamente na primeira ingestão se ainda não existir. A avaliação roda de forma assíncrona.

Acompanhar e ler o resultado

// Aguarda a avaliação desta conversa concluir (polling com timeout)
const status = await axon.waitForEvaluation("cobranca", "conv-001");
console.log(status.status, status.evaluation?.overall); // "done" "C+"

// Status pontual (sem esperar)
await axon.getConversation("cobranca", "conv-001");

// Boletim atual do agente (overall A–F, dimensões, problemas)
const report = await axon.getReport("cobranca");
console.log(report.overall, report.dimensions, report.problems);

Monitoramento em tempo real

A Axon monitora seus agentes em streaming: você não precisa exportar um lote no fim do dia. O padrão é um hook de fim de conversa — assim que uma conversa termina (cliente desliga, sessão de chat encerra, ticket fecha), envie a transcrição. A avaliação roda de forma assíncrona e o boletim no dashboard atualiza sozinho (a tela tem indicador "Ao vivo" e recarrega periodicamente).

import { Axon } from "@gabrielonrails/axon-sdk";

const axon = new Axon({ apiKey: process.env.AXON_API_KEY! });

// Chame isto no momento em que a conversa encerra, no seu próprio runtime.
async function onConversationEnded(conv) {
  // Fire-and-forget: não bloqueie o encerramento da conversa esperando a Axon.
  // O SDK já faz retry com backoff; o id torna o reenvio idempotente.
  void axon
    .ingest(conv.agentName, [
      {
        id: conv.id, // mesmo id em retries → não duplica
        channel: conv.channel, // "voz" | "chat" | "whatsapp"
        turns: conv.turns,
      },
    ])
    .catch((err) => console.error("[axon] ingest falhou:", err));
}

Exemplos de onde plugar o hook:

  • Voz/URA: no evento de fim de chamada (ex.: webhook call.completed da telefonia), monte os turnos a partir da transcrição e chame onConversationEnded.
  • Chat/WhatsApp: ao fechar a sessão por inatividade ou ao resolver o ticket.
  • Agente de IA próprio: logo após enviar a última mensagem ao usuário.

Cada conversa avaliada individualmente assim que chega significa detecção de degradação em tempo quase real — a Axon dispara alertas (e-mail/webhook) quando uma conversa recebe nota baixa (D/F) ou quando a média recente do agente cai em relação à janela anterior, sem esperar um relatório semanal.

Volume alto? Você pode agrupar várias conversas numa só chamada (axon.ingest(agent, [conv1, conv2, ...])) — cada uma é avaliada de forma independente. O rate limit é por requisição, então lotes menores e frequentes costumam ser melhores que um lote gigante.

Sem o SDK (HTTP puro)

O hook de fim de conversa é só um POST — você não precisa do SDK. Chame o endpoint de ingestão direto do seu backend ou até do webhook da sua telefonia/chat:

# Dispare no fim da conversa. O "id" mantém os retries idempotentes.
curl -X POST https://axon-dev.com/api/v1/agents/cobranca/transcripts \
  -H "Authorization: Bearer $AXON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "transcripts": [
        { "id": "conv-001", "channel": "voz",
          "turns": [ { "role": "client", "text": "..." },
                     { "role": "agent",  "text": "..." } ] } ] }'

# → 202  { "accepted": 1, "status": "evaluating" }

API

new Axon({ apiKey, baseUrl?, fetch?, maxRetries?, timeoutMs? })

  • maxRetries (default 3) — re-tentativas em erros transitórios (429/5xx/rede), com backoff exponencial.
  • timeoutMs (default 30000) — timeout por requisição.

axon.ingest(agent, transcripts): Promise<AxonIngestResult>

axon.getConversation(agent, externalId): Promise<AxonConversationStatus>

axon.getReport(agent): Promise<AxonReport>

axon.waitForEvaluation(agent, externalId, { timeoutMs?, intervalMs? })

axon.agent(name){ ingest, getReport, getConversation, waitForEvaluation }

interface AxonTranscript {
  id?: string;
  channel?: "voz" | "chat" | "whatsapp";
  duration?: string;
  version?: string;
  result?: string;
  queue?: string;
  turns: { role: "client" | "agent" | "tool"; text: string }[];
}

Erros viram AxonError com .status e .code (invalid_api_key, no_transcripts, etc.).

Idempotência e retries

Defina id em cada transcrição: reenviar a mesma id atualiza a conversa em vez de criar uma duplicata (a fila de avaliação também é idempotente por conversa). Combinado com os retries automáticos do SDK, isso torna seguro reenviar em caso de timeout ou erro transitório — sem risco de boletins duplicados.

// Reenviar este mesmo payload é seguro: atualiza, não duplica.
await axon.ingest("cobranca", [{ id: "conv-001", turns: [...] }]);

Privacidade

A Axon faz redação de PII (e-mail, CPF/CNPJ, telefone, cartão, CEP) antes de persistir e antes de enviar ao juiz LLM. Ainda assim, evite enviar dados sensíveis desnecessários.