> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thaliq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Eventos y errores

> Sistema de eventos, tipos de eventos SSE, y manejo de errores del SDK

## Eventos del SDK

El SDK emite eventos globales que puedes escuchar para monitorear el estado:

```typescript theme={null}
// Error no manejado
thaliq.on('error', (error) => {
  console.error('Error:', error.message);
});

// Rate limit alcanzado
thaliq.on('rateLimit', (info) => {
  console.warn(`Rate limit. Retry en ${info.retryAfter}s`);
});

// Reintento automatico
thaliq.on('retry', (attempt, error, delayMs) => {
  console.warn(`Retry #${attempt} en ${delayMs}ms: ${error.message}`);
});

// Stream iniciado
thaliq.on('stream.start', (conversationId) => {
  console.log('Stream iniciado:', conversationId);
});

// Stream completado
thaliq.on('stream.end', (conversationId) => {
  console.log('Stream completado:', conversationId);
});

// Usuario identificado
thaliq.on('identify', (userId) => {
  console.log('Identificado:', userId);
});

// Estado limpiado
thaliq.on('reset', () => {
  console.log('Reset');
});
```

### Metodos

| Metodo                 | Descripcion                          |
| ---------------------- | ------------------------------------ |
| `on(event, handler)`   | Registra un listener                 |
| `off(event, handler)`  | Elimina un listener                  |
| `once(event, handler)` | Listener que se ejecuta una sola vez |

### Tabla de eventos

| Evento         | Handler                                         | Cuando se emite                  |
| -------------- | ----------------------------------------------- | -------------------------------- |
| `error`        | `(error: ThaliqError) => void`                  | Error no manejado                |
| `rateLimit`    | `(error: ThaliqError & { retryAfter }) => void` | Rate limit alcanzado             |
| `retry`        | `(attempt, error, delayMs) => void`             | Antes de un reintento automatico |
| `stream.start` | `(conversationId) => void`                      | Stream SSE iniciado              |
| `stream.end`   | `(conversationId) => void`                      | Stream SSE finalizado            |
| `identify`     | `(userId: string) => void`                      | `identify()` llamado             |
| `reset`        | `() => void`                                    | `reset()` llamado                |

## Eventos SSE del stream

Al consumir un stream con `for await`, cada evento tiene un campo `type` que identifica su contenido. La tabla completa de tipos:

### Eventos de contenido

| Tipo            | Descripcion        | Campos                   |
| --------------- | ------------------ | ------------------------ |
| `meta`          | Metadata inicial   | `conversationId: string` |
| `status`        | Estado del agente  | `text: string`           |
| `content.delta` | Fragmento de texto | `delta: string`          |

### Eventos de tools

| Tipo         | Descripcion                | Campos                             |
| ------------ | -------------------------- | ---------------------------------- |
| `tool.start` | Tool comienza a ejecutarse | `tool: string`                     |
| `tool.end`   | Tool termino               | `tool: string`, `success: boolean` |

### Eventos interactivos

| Tipo      | Descripcion              | Campos                                                     |
| --------- | ------------------------ | ---------------------------------------------------------- |
| `action`  | Accion HITL requerida    | `action: PendingAction`                                    |
| `handoff` | Escalado a agente humano | `message: string`, `agentName?: string`, `reason?: string` |

### Eventos de finalizacion

| Tipo                 | Descripcion           | Campos                                                  |
| -------------------- | --------------------- | ------------------------------------------------------- |
| `response.completed` | Respuesta completa    | `message`, `conversationId`, `insights[]`, `metadata`   |
| `message_stop`       | Generacion finalizada | `model: string`, `usage: { inputTokens, outputTokens }` |

### Eventos de error y control

| Tipo         | Descripcion                 | Campos                                  |
| ------------ | --------------------------- | --------------------------------------- |
| `rate_limit` | Rate limit excedido         | `message: string`, `retryAfter: number` |
| `error`      | Error durante el stream     | `message: string`                       |
| `keepalive`  | Ping para mantener conexion | `ts: number`                            |

### Ejemplo completo de manejo de eventos

```typescript theme={null}
const stream = thaliq.agent.stream('Analiza los datos');

for await (const event of stream) {
  switch (event.type) {
    case 'meta':
      console.log('Conversacion:', event.conversationId);
      break;

    case 'status':
      showSpinner(event.text);
      break;

    case 'content.delta':
      appendText(event.delta);
      break;

    case 'tool.start':
      showToolIndicator(event.tool);
      break;

    case 'tool.end':
      hideToolIndicator(event.tool, event.success);
      break;

    case 'action':
      await handleAction(event.action);
      break;

    case 'handoff':
      showHandoffNotice(event.message, event.agentName);
      break;

    case 'response.completed':
      showInsights(event.insights);
      saveMessageId(event.metadata?.messageId); // Para feedback
      break;

    case 'rate_limit':
      showRetryCountdown(event.retryAfter);
      break;

    case 'error':
      showError(event.message);
      break;
  }
}
```

## Manejo de errores

El SDK expone errores tipados para un manejo granular:

```typescript theme={null}
import { ThaliqError, RateLimitError, AuthError } from '@thaliq/sdk';

try {
  const response = await thaliq.agent.chat('Hola');
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log(`Rate limit. Retry en ${error.retryAfter}s`);
  } else if (error instanceof AuthError) {
    console.log('API Key invalida o feature no disponible');
  } else if (error instanceof ThaliqError) {
    console.log(`Error ${error.status}: ${error.message}`);
  }
}
```

### Clases de error

| Clase             | HTTP Status | Descripcion                                 |
| ----------------- | :---------: | ------------------------------------------- |
| `ThaliqError`     |     Base    | Error base del SDK                          |
| `AuthError`       |  401 / 403  | API Key invalida o plan insuficiente        |
| `RateLimitError`  |     429     | Rate limit alcanzado (incluye `retryAfter`) |
| `ValidationError` |     400     | Request invalido (ej: falta apiKey)         |
| `ServiceError`    |     503     | Servicio no disponible                      |
| `StreamError`     |      —      | Error durante streaming SSE                 |
| `TimeoutError`    |      —      | Request timeout (configurable)              |
| `ConnectionError` |      —      | Error de red                                |

### Propiedades de ThaliqError

```typescript theme={null}
class ThaliqError extends Error {
  message: string;      // Descripcion del error
  code: ErrorCode;      // Codigo unico (ej: 'AUTH_ERROR')
  status?: number;      // HTTP status (si aplica)
  retryable: boolean;   // Si se puede reintentar
}
```

### Codigos de error

| Codigo             | Descripcion            |
| ------------------ | ---------------------- |
| `AUTH_ERROR`       | Autenticacion fallida  |
| `RATE_LIMIT`       | Rate limit excedido    |
| `VALIDATION_ERROR` | Request invalido       |
| `SERVICE_ERROR`    | Servicio no disponible |
| `STREAM_ERROR`     | Error en streaming     |
| `TIMEOUT_ERROR`    | Timeout de request     |
| `CONNECTION_ERROR` | Error de conexion      |
| `UNKNOWN_ERROR`    | Error no clasificado   |

### RateLimitError

```typescript theme={null}
class RateLimitError extends ThaliqError {
  retryAfter?: number;  // Segundos para esperar
}
```

### StreamError

Error especifico del streaming. Se lanza cuando:

* El servidor envia un evento de error
* Se intenta consumir un stream mas de una vez
* El rate limit se excede durante el stream

```typescript theme={null}
try {
  for await (const event of stream) { /* ... */ }
} catch (error) {
  if (error instanceof StreamError) {
    console.log('Error de stream:', error.message);
  }
}
```

## Errores en SSE vs excepciones

Hay dos formas en que pueden llegar errores durante streaming:

| Mecanismo                  | Cuando                              | Como manejarlo                                     |
| -------------------------- | ----------------------------------- | -------------------------------------------------- |
| Evento `error`             | El agente emite un error controlado | `if (event.type === 'error')` dentro del loop      |
| Evento `rate_limit`        | Se excedio el rate limit del tenant | `if (event.type === 'rate_limit')` dentro del loop |
| Excepcion `StreamError`    | Error de red, stream corrupto       | `try/catch` alrededor del `for await`              |
| Excepcion `RateLimitError` | Rate limit en `chat()` (sin stream) | `try/catch` alrededor de `chat()`                  |

```typescript theme={null}
try {
  for await (const event of stream) {
    if (event.type === 'error') {
      // Error controlado del agente
      console.error('Agent error:', event.message);
    }
    if (event.type === 'rate_limit') {
      // Rate limit — esperar y reintentar
      console.warn(`Rate limit. Espera ${event.retryAfter}s`);
    }
  }
} catch (error) {
  // Error de red, stream corrupto, o doble consumo
  if (error instanceof StreamError) {
    console.error('Stream error:', error.message);
  }
}
```

## Imports

Todos los errores se importan directamente desde el SDK:

```typescript theme={null}
import {
  ThaliqError,
  AuthError,
  RateLimitError,
  ValidationError,
  ServiceError,
  StreamError,
  TimeoutError,
  ConnectionError,
} from '@thaliq/sdk';
```
