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

@tarileo/react

v0.1.2

Published

React UI layer for the Tari framework - chat components, hooks, and real-time sync

Readme

@tarileo/react

Capa React de Tari para construir interfaces de agentes IA con chat, sesiones, renderizado de herramientas UI, sincronización en tiempo real por SSE, adjuntos, subagentes y paneles de progreso.

Este paquete no implementa el backend del agente: consume los endpoints HTTP y eventos SSE expuestos por la aplicación que integra Tari.

Tabla de contenidos

Instalación

npm install @tarileo/react @tarileo/events @tarileo/utils

En este monorepo se usa como workspace:

bun add @tarileo/react@workspace:*

Requisitos

  • React ^19.2.0.
  • Un backend compatible con Tari bajo ${apiUrl}/api/v1.
  • Un token de autenticación disponible en localStorage.getItem("bearer_token").
  • Para sincronización en tiempo real, envolver la sección protegida con SSEProvider de @tarileo/events/react.
  • Los componentes incluidos usan clases Tailwind/shadcn (bg-background, text-muted-foreground, border, etc.); la aplicación host debe proveer esos estilos o reemplazar renderers cuando aplique.

Conceptos principales

| Concepto | Descripción | | --- | --- | | TariFrontend | Cliente frontend creado con createTari. Contiene registros de tools, subagentes, SyncService y metadatos de sesiones activas. | | TariProvider | Provider global que expone una instancia de TariFrontend vía React context. | | TariAgent | Provider de un agente concreto. Normalmente envuelve el panel o chat que usará TariChat. | | SyncService | Cliente HTTP para sesiones, mensajes, adjuntos, tareas y cancelación. | | useTariStore | Store Zustand interna con sesiones, mensajes, parts, streaming, tareas y subagentes. | | UI tools | Definiciones frontend que describen cómo mostrar estados de carga y resultados de herramientas ejecutadas por el agente. | | Subagent renderers | Renderers especializados para resultados de delegate_to_subagent. |

Configuración rápida

// lib/tari.ts
import { createTari } from "@tarileo/react";

export const tari = createTari({
  apiUrl: import.meta.env.VITE_API_URL || "http://localhost:3000",
});
// root.tsx
import { TariProvider } from "@tarileo/react";
import { tari } from "./lib/tari";

export function App() {
  return (
    <TariProvider tari={tari}>
      <Outlet />
    </TariProvider>
  );
}
// protected-layout.tsx
import { SSEProvider } from "@tarileo/events/react";
import { TariRealtimeSync } from "@tarileo/react";

const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3000";

export function ProtectedLayout() {
  return (
    <SSEProvider url={`${API_URL}/api/v1/events/stream`}>
      <TariRealtimeSync />
      <Outlet />
    </SSEProvider>
  );
}

Arquitectura de providers

La estructura recomendada es:

import {
  TariAgent,
  TariChat,
  TariProvider,
  useTariAgent,
} from "@tarileo/react";
import { tari } from "./lib/tari";

function ProductAgentProvider({ children }: { children: React.ReactNode }) {
  const agent = useTariAgent({ name: "product-creator" });

  return (
    <TariAgent value={agent}>
      {children}
    </TariAgent>
  );
}

export function AppShell() {
  return (
    <TariProvider tari={tari}>
      <ProductAgentProvider>
        <aside className="h-full">
          <TariChat variant="sidebar" />
        </aside>
      </ProductAgentProvider>
    </TariProvider>
  );
}

TariChat, TariChatComposer y otros componentes que consumen useTariAgentInstance deben renderizarse dentro de TariAgent.

Uso del chat

Chat completo

import { TariChat } from "@tarileo/react";

export function AssistantPanel() {
  return (
    <div className="h-full">
      <TariChat
        variant="sidebar"
        welcome={
          <div className="rounded-xl bg-muted px-4 py-3 text-sm">
            Cuéntame qué producto quieres crear.
          </div>
        }
      />
    </div>
  );
}

TariChat incluye:

  • lista de sesiones del agente;
  • creación, selección y archivado de sesiones;
  • mensajes del usuario y asistente;
  • renderizado automático de tool calls;
  • composer con subida de archivos;
  • panel de plan activo cuando existen tareas.

Composer independiente

import { TariChatComposer } from "@tarileo/react";

export function CompactComposer() {
  return (
    <TariChatComposer
      compact
      placeholder="Pide un cambio..."
      accept="image/*,application/pdf"
    />
  );
}

Enviar mensajes programáticamente

Desde un agente React

import { useTariAgentInstance } from "@tarileo/react";

export function ImproveButton({ product }: { product: unknown }) {
  const agent = useTariAgentInstance();

  async function handleClick() {
    await agent.chat
      .sendMessage("Mejora este producto para venderlo mejor.")
      .context({
        id: "current-product",
        description: "Producto actualmente seleccionado",
        value: product,
      })
      .execute();
  }

  return <button onClick={handleClick}>Mejorar con IA</button>;
}

Desde la instancia tari

import { tari } from "./lib/tari";

await tari.prompt({
  agent: "product-creator",
  prompt: "Crea una pizza margarita familiar.",
  openPanel: true,
});

También puedes continuar una sesión existente:

await tari.prompt({
  sessionId: "session_123",
  prompt: "Ahora agrega una variante mediana.",
});

Cuando openPanel es true, el store emite el evento de navegador tari:session-activated. Puedes escucharlo con useTariPanel.

import { useTariPanel } from "@tarileo/react";

function PanelOpener() {
  const { shouldOpen, pendingAgent, acknowledgeOpen } = useTariPanel();

  useEffect(() => {
    if (shouldOpen && pendingAgent === "product-creator") {
      // abrir drawer, navegar o enfocar panel
      acknowledgeOpen();
    }
  }, [shouldOpen, pendingAgent, acknowledgeOpen]);

  return null;
}

Registrar herramientas UI

Las herramientas UI permiten que el frontend conozca la metadata de una tool y renderice su resultado.

import { defineUITool, useRegisterTool } from "@tarileo/react";
import { z } from "zod";

const publishProductTool = defineUITool({
  name: "publish_product",
  description: "Publica un producto creado por IA",
  inputSchema: z.object({
    productId: z.string(),
  }),
  outputSchema: z.object({
    productId: z.string(),
    name: z.string(),
    status: z.enum(["published", "draft"]),
  }),
  loading: {
    text: "Publicando producto...",
    icon: "sparkles",
    color: "amber",
  },
  render: ({ result }) => (
    <div className="rounded-lg border p-3">
      Producto publicado: {result.name}
    </div>
  ),
});

export function ProductTools() {
  useRegisterTool(publishProductTool);
  return null;
}

Notas:

  • inputSchema y outputSchema son esquemas Zod.
  • inputSchema se serializa a JSON Schema para enviarse al backend en uiTools.
  • Si defines component y render, component tiene prioridad.
  • Si no existe renderer para una tool, ToolRenderer muestra un fallback con el resultado JSON.

Registrar renderers de subagentes

ToolRenderer detecta resultados de delegate_to_subagent y busca un renderer por output.key.

import { useRegisterUiSubAgent } from "@tarileo/react";

export function ProductSubAgents() {
  useRegisterUiSubAgent("product-review", {
    onRender: ({ result, childSessionId, isLoading, error }) => (
      <section className="rounded-lg border p-3">
        {isLoading ? "Analizando..." : null}
        {error ? <p className="text-red-600">{error}</p> : null}
        <pre>{JSON.stringify(result, null, 2)}</pre>
        {childSessionId ? <small>Sesión hija: {childSessionId}</small> : null}
      </section>
    ),
  });

  return null;
}

Sincronización en tiempo real

TariRealtimeSync se suscribe a eventos de @tarileo/events y mantiene el store sincronizado:

  • ejecución iniciada, completada o fallida;
  • deltas de texto streaming;
  • mensajes agregados;
  • subagentes iniciados, con progreso, completados o con error;
  • planes y tareas creadas, iniciadas, actualizadas, completadas, canceladas o fallidas.
import { SSEProvider } from "@tarileo/events/react";
import { TariRealtimeSync } from "@tarileo/react";

<SSEProvider url={`${apiUrl}/api/v1/events/stream`}>
  <TariRealtimeSync />
  <YourProtectedApp />
</SSEProvider>;

Comportamiento interno:

  • solo sincroniza sesiones rastreadas por el store;
  • reintenta sincronización hasta 3 veces por sesión;
  • debounce de sync de 500 ms;
  • timeout de streaming de 30 segundos para forzar re-sync;
  • re-sincroniza sesiones rastreadas al reconectar SSE.

Adjuntos

TariChatComposer ya integra subida de archivos con useTariUpload. Para usarlo manualmente:

import { useTariUpload } from "@tarileo/react";

function UploadButton({ agent, sessionId }: { agent: string; sessionId?: string }) {
  const { upload, isUploading } = useTariUpload({ agent, sessionId });

  async function handleFile(file: File) {
    const attachment = await upload(file, "analysis");
    if (!attachment) return;

    // Enviar luego con agent.chat.sendMessage(...).attachment(attachment).execute()
  }

  return <button disabled={isUploading}>Subir archivo</button>;
}

Los adjuntos usan POST /assistant/attachments con FormData y bearer token desde localStorage.

Sesiones

Hook de agente

const agent = useTariAgent({
  name: "product-creator",
  sessionId: "session_123", // opcional
});

Retorna:

| Campo | Descripción | | --- | --- | | name | Nombre del agente. | | sessionId | Sesión activa o null. | | chat | API de chat (sendMessage, stop, status, error, isSyncing). | | metadata | Metadata de la sesión actual desde el store. | | isLoadingSession | Indica si la sesión se está sincronizando. | | createSession() | Crea una nueva sesión para el agente. | | archiveSession(sessionId) | Archiva una sesión. | | cancelSession(sessionId, reason?) | Cancela la ejecución activa de una sesión. | | isCreatingSession | Estado de creación de sesión. |

Listar y administrar sesiones

import { useTariAgentSessions } from "@tarileo/react";

function Sessions() {
  const { sessions, isLoading, error, refresh, createSession, archiveSession } =
    useTariAgentSessions("product-creator");

  // renderizar lista...
}

Planes y tareas

import { ActivePlanPanel, useTariTasks } from "@tarileo/react";

function PlanSummary({ sessionId }: { sessionId: string }) {
  const { plan, tasks } = useTariTasks(sessionId);

  if (!plan) return null;

  return (
    <ActivePlanPanel
      planId={plan.id}
      description={plan.description}
      onTaskClick={(taskId) => console.log(taskId)}
    />
  );
}

useTariTasks toma el sessionId del TariChatContext cuando existe; si no, usa el sessionId que se pasa como argumento.

API de hooks y componentes

Componentes

| Export | Uso | | --- | --- | | TariProvider | Provider global de la instancia TariFrontend. | | TariAgent | Provider de un agente concreto. | | TariRealtimeSync | Sincroniza el store desde eventos SSE. | | TariChat | Chat completo con lista de sesiones, mensajes, composer y plan activo. | | TariChatComposer | Composer con texto, adjuntos y stop. | | ChatMessageItem | Renderiza un mensaje individual. | | ToolRenderer | Renderiza tool invocations registradas. | | ToolLoading | Estado visual de carga de una tool. | | ActivePlanPanel | Panel expandible de plan activo y tareas. | | TaskList | Lista de tareas de planner. | | PlannerGeneratePlanResult | Renderer para resultado de generación de plan. | | PlannerDelegateResult | Renderer para resultado de delegación. |

Hooks

| Export | Uso | | --- | --- | | useTari() | Obtiene la instancia TariFrontend. | | useTariAgent(config) | Crea/conecta una instancia de agente React. | | useTariAgentInstance() | Lee el agente del context actual. | | useTariChat(options) | API base de chat por agente/sesión. | | useTariChatMessages(sessionId) | Mensajes normalizados y mensajes compatibles con chat UI. | | useTariAgentSessions(agent) | Lista, crea, refresca y archiva sesiones. | | useTariUpload(options) | Sube adjuntos. | | useTariTasks(sessionId?) | Lee plan y tareas de una sesión. | | useTariSubAgent(subAgentId) | Lee estado de un subagente. | | useTariPanel() | Detecta solicitudes para abrir panel desde tari.prompt. | | useRegisterTool(tool) | Registra una UI tool mientras el componente está montado. | | useIsToolRegistered(name) | Indica si una tool está registrada. | | useRegisterUiSubAgent(key, registration) | Registra renderer para subagente. | | useTariStore | Acceso directo al store Zustand interno. |

Utilidades y clases

| Export | Uso | | --- | --- | | createTari(config) | Crea una instancia TariFrontend. | | TariFrontend | Clase principal del cliente React. | | defineUITool(tool) | Helper tipado para definir UI tools. | | UIToolRegistry | Registro de herramientas UI. | | UiSubAgentRegistry | Registro de renderers de subagentes. | | SyncService | Cliente HTTP de sincronización. | | SendMessageBuilder | Builder fluent para mensajes con adjuntos/contexto/selección. | | toChatMessage, toChatMessages | Adaptadores de mensajes internos a ChatMessage. | | isToolInvocationPart, getToolInvocationFromPart | Helpers para parts de tool invocation. |

Endpoints esperados

createTari({ apiUrl }) crea un SyncService con baseUrl = ${apiUrl}/api/v1.

| Método | Ruta | Uso | | --- | --- | --- | | GET | /assistant/sessions/:sessionId | Obtener sesión con mensajes y parts. | | GET | /assistant/sessions/:sessionId/tasks | Obtener plan y tareas de una sesión. | | GET | /assistant/sessions/:sessionId/tasks/:taskId | Obtener detalle de tarea y sesión hija. | | POST | /assistant/sessions/:sessionId/tasks/:taskId/cancel | Cancelar tarea. | | POST | /assistant/messages | Enviar mensaje a un agente. | | POST | /assistant/attachments | Subir archivo adjunto. | | POST | /assistant/sessions | Crear sesión. | | DELETE | /assistant/sessions/:sessionId | Archivar sesión. | | POST | /assistant/sessions/:sessionId/cancel | Cancelar ejecución de sesión. | | GET | /assistant/sessions?agent=... | Listar sesiones de un agente. | | GET | /events/stream | Stream SSE usado por @tarileo/events/react. |

Todas las llamadas HTTP usan:

Authorization: Bearer <localStorage.bearer_token>

Excepto adjuntos, que omite Content-Type para que el navegador configure el boundary de FormData.

Estructura interna

src/
├── agent-context.tsx              # Provider/hook de agente concreto
├── builders/
│   └── send-message-builder.ts    # Builder fluent para mensajes
├── chat-provider.tsx              # Contexto de sesión para componentes de chat
├── components/
│   ├── chat/                      # Chat, composer, mensajes y lista de sesiones
│   ├── planner/                   # Planes, tareas y resultados de planner
│   ├── tool-loading.tsx           # UI de loading para tools
│   └── tool-renderer.tsx          # Resolución y render de tool calls
├── hooks/                         # Hooks públicos y selectores de store
├── provider.tsx                   # TariProvider/useTari
├── registry.ts                    # Registro de UI tools
├── services/
│   └── sync-service.ts            # Cliente HTTP
├── store/                         # Zustand store y tipos normalizados
├── subagent-registry.ts           # Registro de renderers de subagentes
├── tari-realtime-sync.tsx         # Bridge SSE -> store
├── tari.ts                        # TariFrontend/createTari/defineUITool
├── types.ts                       # Tipos públicos de chat/tools
└── utils/                         # Adaptadores y helpers de parts

Build y desarrollo

# Compilar el paquete
bun run --filter @tarileo/react build

# Compilar en modo watch
bun run --filter @tarileo/react build:watch

El build usa tsup y genera ESM + declaraciones TypeScript en dist/.

Troubleshooting

useTari must be used within a TariProvider

El componente está usando hooks de Tari fuera de:

<TariProvider tari={tari}>...</TariProvider>

useTariAgentInstance must be used within a TariAgent

TariChat, TariChatComposer o un componente que llama useTariAgentInstance debe estar dentro de:

const agent = useTariAgent({ name: "product-creator" });

<TariAgent value={agent}>...</TariAgent>

No llegan deltas de streaming

Verifica que:

  • SSEProvider apunte a ${apiUrl}/api/v1/events/stream;
  • TariRealtimeSync esté montado dentro del SSEProvider;
  • la sesión esté rastreada por el store, por ejemplo al usar useTariAgent, TariChat o tari.prompt;
  • el backend emita eventos compatibles de @tarileo/events.

Las llamadas HTTP fallan con 401

SyncService lee el token desde localStorage.getItem("bearer_token"). Asegúrate de guardarlo antes de usar el chat o adapta la autenticación en la aplicación host.

Licencia

MIT