Tema
SDK — referencia
Superficie pública completa de @nykk/ur-agent-client. No hay nada más: no existe connect(), no existe onMessage, no existe autenticación.
UrAgentClient
ts
new UrAgentClient(options: UrAgentClientOptions)UrAgentClientOptions
| Campo | Tipo | Descripción |
|---|---|---|
agent | string | identifier público o id inmutable del agente. |
apiBase? | string | Origen del backend ur. Por defecto, window.location.origin. |
channel? | string | 'js_sdk' (por defecto), 'widget' o 'demo' (uso interno). Se comprueba contra el estado y los orígenes de ese canal. |
subjectId? | string | Reanuda un hilo concreto en vez del persistido por defecto. Nunca se escribe en storage. |
storage? | UrAgentClientStorage | Persistencia del subjectId por defecto. Por defecto, localStorage. Pasa tu propia implementación (getItem/setItem) en entornos sin localStorage (SSR, ciertos WebViews). |
context? | Record<string, unknown> | Datos por turno para las tools del agente, agrupados por tool. Ver Contexto de cliente. |
getAuthHeaders? | () => Record<string,string> | Promise<Record<string,string>> | Punto de extensión reservado, sin efecto todavía — ver Limitaciones. Sus cabeceras se fusionan en cada petición a /chat y /history. |
Propiedades
subjectId: string(getter) — la identidad de conversación en uso.isNewSubject: boolean(readonly) —truesi elsubjectIdse acaba de generar (no hay nada que restaurar víaloadHistory()).
Métodos
onToken(handler: (delta: string) => void): () => void— delta de texto del turno en curso. Devuelve una función para des-registrar el handler.onNotice(handler: (content: string) => void): () => void— el mensaje automático único que un agente puede tener configurado (ej. un aviso legal). Dispara como máximo una vez por(agente, subjectId, channel), siempre antes que el primeronTokende ese hilo. Si no te suscribes, el texto no se pierde:loadHistory()lo devuelve igual, marcado conisAutoMessage: true.onToolEvent(handler: (event: UrAgentClientToolEvent) => void): () => void— actividad de tools del agente. Solo dispara en el canal internodemo— enwidget/js_sdknunca se emite (el backend no revela qué tools usa un agente a un embed público).onUsage(handler: (usage: UrAgentClientUsage) => void): () => void— tokens/coste del turno. Igual queonToolEvent, solo endemo.onDone(handler: (threadId: string) => void): () => void— el turno ha terminado.onError(handler: (message: string) => void): () => void— fallo de red o del backend. El mensaje es siempre uno "de catálogo" (nunca la excepción real) — es un canal público.setContext(context: Record<string, unknown> | undefined): void— sustituye el contexto de cliente. Surte efecto en el siguientesendMessage().abort(): void— cancela unsendMessageen curso sin dispararonError.resetConversation(): string— aborta cualquier envío en curso, genera y persiste unsubjectIdnuevo (hilo nuevo de verdad en el backend), y lo devuelve.loadHistory(): Promise<UrAgentClientHistory>— turnos previos de estesubjectId, si hay.threadId: nullymessages: []si no hay nada que restaurar (no es un error). A diferencia desendMessage, este sí lanza si la petición falla.sendMessage(text: string): Promise<void>— envía el mensaje y procesa el streaming invocando los handlers registrados arriba. Resuelve cuando el stream termina; no hace falta esperar nada más para saber que el turno acabó — usaonDone/onErrorpara eso. Nunca lanza: los fallos van aonError.
Tipos
ts
interface UrAgentClientHistoryMessage {
role: 'user' | 'bot';
content: string;
time: string | null;
usage?: { inputTokens: number; outputTokens: number }; // solo canal `demo`
toolCalls?: unknown; // solo canal `demo`
isAutoMessage?: boolean;
}
interface UrAgentClientHistory {
threadId: string | null;
messages: UrAgentClientHistoryMessage[];
usage?: UrAgentClientUsage; // solo canal `demo`
modelName?: string; // solo canal `demo`
}
interface UrAgentClientToolEvent {
name: string;
status: 'start' | 'end';
args?: Record<string, unknown>;
}createChatStore
ts
function createChatStore(client: UrAgentClient): UrAgentChatStoreCapa opcional de acumulación de mensajes sobre un UrAgentClient ya creado. Framework-agnóstico — un simple getState()/subscribe(), exactamente la forma que espera useSyncExternalStore en React (ver el ejemplo React) y trivial de reflejar en un signal de Angular (ver el ejemplo Angular). Se suscribe internamente a onToken/onNotice/onDone/onError del cliente que le pasas — sigues pudiendo registrar tus propios handlers sobre ese mismo cliente para lo que el store no cubre (onToolEvent/onUsage, que son solo del canal demo).
UrAgentChatStore
getState(): UrAgentChatStatesubscribe(listener: () => void): () => void— no llama al listener al suscribirte; leegetState()justo después si necesitas el valor inicial.loadHistory(): Promise<void>— sustituyemessagespor el historial previo. Llamar como mucho una vez por montaje, normalmente solo si!client.isNewSubject.send(text: string): Promise<void>— añade el mensaje del usuario y procesa el streaming de la respuesta. No-op mientrasstatus === 'sending'.reset(): void— limpiamessagesy llama aclient.resetConversation().
UrAgentChatState
ts
interface UrAgentChatMessage {
id: string;
role: 'user' | 'bot';
content: string;
time: string | null;
isAutoMessage?: boolean; // el aviso automático del agente
isError?: boolean; // bubble sintético creado por el store al recibir `onError`
pending?: boolean; // el bubble del bot sigue acumulando tokens
}
interface UrAgentChatState {
messages: UrAgentChatMessage[];
status: 'idle' | 'loading-history' | 'sending' | 'error';
error: string | null;
}Si tu cliente no es JavaScript
Este paquete es la vía soportada para integrar un chat en el navegador. Cuando no puedas usarlo —porque tu cliente no es JavaScript, o porque no corre en un navegador— la alternativa es HTTP sin streaming, que devuelve el turno completo de una vez y se autentica con un access token.