@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.
Maintainers
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-sdkRequer 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.completedda telefonia), monte os turnos a partir da transcrição e chameonConversationEnded. - 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(default3) — re-tentativas em erros transitórios (429/5xx/rede), com backoff exponencial.timeoutMs(default30000) — 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.
