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

@zihin/agent-client

v0.1.0

Published

Núcleo de invocação de agentes Zihin.ai — padrão único para n8n, Paperclip e integrações futuras. Stream direto (SSE bufferizado) + triggers assíncronos com callback.

Readme

@zihin/agent-client

Núcleo de invocação de agente Zihin.ai — o padrão único que n8n, Paperclip e integrações futuras usam para acionar agentes hospedados na Zihin. Zero dependência de plataforma.

Contexto e decisões: docs/issues/PLANO-padrao-agent-client.md (issue #16). Contrato verificado contra o BE (zihin-agent-builder/server-llm) em 2026-06-28.

A ideia

Toda entrada externa na Zihin atravessa um agente (RBAC, quota, HITL, auditoria, memória) — não a call crua de LLM. Este pacote esconde os detalhes de transporte (SSE, triggers) atrás de uma API simples, e oferece dois estilos de invocação:

| Estilo | Método | Quando usar | |---|---|---| | Direto / imediato | invokeAgent / streamAgent | espera a resposta (n8n, request/resposta). Zero setup. | | Assíncrono / desacoplado | createTrigger + dispatchAgent (+ getExecution) | dispara e recebe via callback (serverless, execução longa). |

Instalação

npm install @zihin/agent-client

Requer Node >= 18 (usa fetch/ReadableStream globais).

Uso — caminho direto

import { createClient } from '@zihin/agent-client';

const zihin = createClient({ apiKey: process.env.ZIHIN_API_KEY! }); // zhn_live_*

// Imediato — buffeia o SSE e consolida response + metrics
const res = await zihin.invokeAgent({
  agentId: 'uuid-do-agente',
  message: 'Qual a previsão de vendas?',
  sessionId: previousSessionId, // opcional, continua a conversa
});
console.log(res.content);     // texto final
console.log(res.usage);       // { inputTokens, outputTokens, totalTokens, costUsd }
console.log(res.sessionId);   // guarde para a próxima mensagem
console.log(res.model);       // modelo efetivo

// Ao vivo — deltas conforme o agente pensa/usa tools/responde
for await (const chunk of zihin.streamAgent({ agentId, message: 'Olá' })) {
  if (chunk.type === 'token') process.stdout.write(chunk.content);
  if (chunk.type === 'tool') console.log('tool:', chunk.tool);
}

Uso — caminho assíncrono (triggers)

// 1x: provisiona (ou reaproveita) um webhook ligado ao agente.
// PREFIRA findOrCreateTrigger — o BE não tem unicidade de nome, então createTrigger
// repetido cria duplicatas. findOrCreate reusa por (agente + nome).
const { triggerId, webhookUrl, created } = await zihin.findOrCreateTrigger({
  agentId,
  name: 'Integração X',
  mode: 'async',
  callbackUrl: 'https://minha-plataforma.com/webhook/zihin',
});

// N vezes: dispara (responde 202 na hora; resultado chega no callback)
const { accepted, executionId } = await zihin.dispatchAgent({
  triggerId,
  payload: { message: 'Processa este pedido' },
});

// opcional: polling do resultado em vez de callback
const exec = await zihin.getExecution({ triggerId, executionId });

O modo sync do trigger (mode: 'sync') responde 200 + JSON na hora (dispatchResult.agentResponse).

Ciclo de vida do trigger

await zihin.listTriggers({ agentId });        // lista (filtros: agentId/triggerType/enabledOnly)
await zihin.getTrigger({ triggerId });        // detalhe (inclui webhookUrl)
await zihin.deleteTrigger({ triggerId });     // remove (requer key admin/owner; editor → 403)

Dropdown de agentes

const agents = await zihin.listAgents(); // GET /api/v2/agents
// [{ id, name, commercialName, status, toolsCount, ... }]

Permissões da API key

  • invokeAgent / streamAgent — qualquer role.
  • createTrigger / getExecution — exigem key admin ou editor (default é admin). Keys member recebem ZihinAgentError com kind: 'auth'.

Erros

Todos os erros são ZihinAgentError com kind (config | auth | not_found | rate_limit | timeout | aborted | server | network | protocol | unknown), status, code, retryable e — para depurar em produção externa — endpoint ("POST host/path"), attempts e requestId (handle do BE para o suporte correlacionar). Erros de rede carregam a causa-raiz (ECONNREFUSED/ENOTFOUND/TLS…) na mensagem. As mensagens redigem só segredos (key/Bearer/stack) — request_id/trace_id são preservados. Cancele com AbortSignal via params.signal.

Robustez (timeout / retry / limites)

  • Timeout cobre tudo — headers e o corpo/stream inteiro. timeoutMs (default 120s, igual ao cap do BE) é o tempo máximo total da chamada; AbortSignal do chamador funciona durante todo o stream.
  • Retry sem duplicar efeito — GET (idempotente) retenta em rede/429/5xx; POST com efeito (invokeAgent/dispatchAgent/createTrigger) retenta só em 429/503 e nunca em erro de rede (o request pode ter sido processado). Backoff exponencial 1s→10s com jitter.
  • Anti-DoS de memória — limites de stream maxStreamEventBytes (1MB) e maxStreamTotalBytes (64MB); estourar aborta com protocol. Configuráveis no createClient.
  • includeRaw — por padrão invokeAgent não retém os eventos brutos (raw: []) para economizar memória; passe includeRaw: true para recebê-los. streamAgent sempre entrega os chunks ao vivo.
  • Segurança de transporteredirect: 'error' (um 3xx para outro host vazaria a key) e cache: 'no-store' (evita polling stale em Next.js/edge) em toda requisição. Retry-After do servidor é respeitado em 429/503.

Observabilidade e portabilidade

  • Hooks (opt-in, sem console): onRetry(info) (a cada retentativa, com endpoint/attempt/ delayMs/reason/status) e onError(err).
  • fetch injetávelfetch? na config; por padrão usa globalThis.fetch (Node ≥18). Um preflight dá erro config claro se não houver fetch.
  • Portável — sem Buffer; node:crypto só é carregado se você usar signRequest. Roda em Node; para edge/serverless, injete fetch se necessário.
const zihin = createClient({
  apiKey,
  timeoutMs: 60_000,
  maxRetries: 2,
  maxStreamEventBytes: 2 * 1024 * 1024,
  onRetry: (info) => myLogger.warn('zihin retry', info),
  // fetch: customFetch,  // ambientes sem fetch global
});

SSRF: a validação de base/callback URL é por nome de host. Com allowCustomBaseUrl: true um host que resolva para IP privado (DNS rebinding) passa — mantenha o whitelist em ambiente sensível.

Segurança

Reusa as primitivas de security.ts: validação SSRF da base URL (whitelist Zihin por padrão; libere com allowCustomBaseUrl), limites de payload, sanitização de erro, validação de formato de key e HMAC opcional.

Dev

npm run build && npm test   # smoke test offline (mocka fetch), sem rede