@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
- Requisitos
- Conceptos principales
- Configuración rápida
- Arquitectura de providers
- Uso del chat
- Enviar mensajes programáticamente
- Registrar herramientas UI
- Registrar renderers de subagentes
- Sincronización en tiempo real
- Adjuntos
- Sesiones
- Planes y tareas
- API de hooks y componentes
- Endpoints esperados
- Estructura interna
- Build y desarrollo
Instalación
npm install @tarileo/react @tarileo/events @tarileo/utilsEn 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
SSEProviderde@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:
inputSchemayoutputSchemason esquemas Zod.inputSchemase serializa a JSON Schema para enviarse al backend enuiTools.- Si defines
componentyrender,componenttiene prioridad. - Si no existe renderer para una tool,
ToolRenderermuestra 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 partsBuild y desarrollo
# Compilar el paquete
bun run --filter @tarileo/react build
# Compilar en modo watch
bun run --filter @tarileo/react build:watchEl 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:
SSEProviderapunte a${apiUrl}/api/v1/events/stream;TariRealtimeSyncesté montado dentro delSSEProvider;- la sesión esté rastreada por el store, por ejemplo al usar
useTariAgent,TariChatotari.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
