> ## 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.

# GET /api/agent/stream

> Envia un mensaje y recibe la respuesta en streaming via SSE

Endpoint principal para interactuar con el agente. Usa **Server-Sent Events (SSE)** para enviar la respuesta en tiempo real, token por token.

## Request

```bash theme={null}
GET https://api.thaliq.com/api/agent/stream?q={mensaje}
```

### Query Parameters

| Parametro        | Requerido | Descripcion                                                                                                                                                  |
| ---------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `q`              |     Si    | El mensaje del usuario (URL-encoded)                                                                                                                         |
| `conversationId` |     No    | ID de conversacion existente. Si se omite o expiro, el backend crea una nueva. **Valores reservados** (`pending`, `new`, `null`, `undefined`) son rechazados |
| `agentId`        |     No    | Override del agente. Si se omite, se usa el agente bindeado a la API key (o el default del tenant si no hay binding)                                         |
| `agentType`      |     No    | `'general'` por defecto                                                                                                                                      |
| `channel`        |     No    | `'platform' \| 'widget' \| 'sdk' \| 'studio' \| 'whatsapp' \| 'telegram' \| 'slack'`. Afecta filtrado en stats e inbox                                       |
| `actionResponse` |     No    | Respuesta a una accion HITL pendiente (JSON URL-encoded)                                                                                                     |

### Headers

Ver [Autenticacion](/api-reference/authentication) para el detalle completo. Headers comunes:

| Header               | Requerido | Descripcion                       |
| -------------------- | :-------: | --------------------------------- |
| `X-API-Key`          |     Si    | API Key del tenant                |
| `X-Integration-Type` |     No    | `widget` o `sdk`                  |
| `X-User-Id`          |     No    | ID del usuario final (tracking)   |
| `X-Participant-Id`   |     No    | Fingerprint del visitante anonimo |
| `X-MCP-Tokens`       |     No    | JSON `{"<serverId>":"<token>"}`   |
| `Authorization`      |     No    | `Bearer <jwt>` (passthrough MCP)  |

## Eventos SSE

La respuesta es un stream de eventos SSE. Cada evento tiene un `event` type y `data` JSON:

```
event: meta
data: {"conversationId":"conv_abc123"}

event: status
data: {"message":"Pensando..."}

event: content.delta
data: {"delta":"Nuestro "}

event: content.delta
data: {"delta":"horario es "}

event: content.delta
data: {"delta":"de 9am a 6pm."}

event: response.completed
data: {"conversationId":"conv_abc123"}
```

### Tipos de eventos

| Evento               | Descripcion                                                                                                                                                   | Data                                                                                                  |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `meta`               | Metadata inicial de la conversacion (se emite tras resolver/crear el thread). Antes de este evento, **no** consideres que tenes un `conversationId` valido    | `{ conversationId }`                                                                                  |
| `keepalive`          | Heartbeat cada 20s para evitar que proxies/CDNs corten la conexion idle                                                                                       | `{ ts }`                                                                                              |
| `status`             | Estado intermedio del agente ("Pensando...", "Buscando en documentos...")                                                                                     | `{ text }`                                                                                            |
| `content.delta`      | Fragmento de texto de la respuesta. Se emiten muchos en orden — concatenalos                                                                                  | `{ delta }`                                                                                           |
| `tool.start`         | El agente comenzo a ejecutar una tool                                                                                                                         | `{ tool }`                                                                                            |
| `tool.end`           | La tool termino de ejecutarse                                                                                                                                 | `{ tool, success, durationMs }`                                                                       |
| `rag.context`        | Chunks RAG recuperados (debug — solo cuando hay docs subidos)                                                                                                 | `{ documentsUsed, totalChunks, queryUsed, tokenCount }`                                               |
| `action`             | Accion interactiva pendiente (Human-in-the-Loop). El stream **se cierra** despues de este evento — para continuar mandar `actionResponse` en un nuevo request | `{ type, instructionId, message, options?, fields? }`                                                 |
| `handoff`            | Escalacion a un humano (la conversacion entra al inbox)                                                                                                       | `{ message, agentName?, reason? }`                                                                    |
| `response.completed` | Stream completado. Util para capturar metadata final (messageId para feedback)                                                                                | `{ message, metadata: { messageId, model, generatedAt }, promptTokens, completionTokens, insights? }` |
| `error`              | Error durante el procesamiento. El stream se cierra                                                                                                           | `{ message }`                                                                                         |

## Ejemplo con curl

```bash theme={null}
curl -N -H "X-API-Key: tq_live_xxx" \
  "https://api.thaliq.com/api/agent/stream?q=Hola%20necesito%20ayuda"
```

## Ejemplo con JavaScript

```javascript theme={null}
const params = new URLSearchParams({ q: 'Hola, necesito ayuda' });
const response = await fetch(
  `https://api.thaliq.com/api/agent/stream?${params}`,
  {
    headers: {
      'X-API-Key': 'tq_live_xxx',
    },
  }
);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { value, done } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });

  // Procesar eventos separados por doble newline
  let idx;
  while ((idx = buffer.indexOf('\n\n')) !== -1) {
    const rawEvent = buffer.slice(0, idx);
    buffer = buffer.slice(idx + 2);

    let eventType = 'message';
    const dataLines = [];

    for (const line of rawEvent.split('\n')) {
      if (line.startsWith('event:')) eventType = line.slice(6).trim();
      else if (line.startsWith('data:')) dataLines.push(line.slice(5).trim());
    }

    const data = JSON.parse(dataLines.join('\n'));

    switch (eventType) {
      case 'content.delta':
        process.stdout.write(data.delta); // Mostrar texto progresivamente
        break;
      case 'tool.start':
        console.log(`\n[Tool: ${data.tool}]`);
        break;
      case 'response.completed':
        console.log('\n--- Fin ---');
        break;
    }
  }
}
```

## Ejemplo con EventSource (alternativa)

```javascript theme={null}
const params = new URLSearchParams({ q: 'Hola' });
const es = new EventSource(
  `https://api.thaliq.com/api/agent/stream?${params}&apiKey=tq_live_xxx`
);

es.addEventListener('content.delta', (e) => {
  const data = JSON.parse(e.data);
  document.getElementById('response').textContent += data.delta;
});

es.addEventListener('response.completed', () => {
  es.close();
});

es.addEventListener('error', () => {
  es.close();
});
```

<Warning>
  `EventSource` no soporta custom headers. Para enviar la API Key como header (recomendado), usa `fetch` con `ReadableStream` como en el ejemplo anterior.
</Warning>

## Respondiendo a acciones interactivas

Cuando recibes un evento `action`, el stream se cierra. Para responder, envias un nuevo request con el parametro `actionResponse`:

```javascript theme={null}
// Respuesta a un confirm
const actionResponse = JSON.stringify({
  instructionId: 'inst_abc123',
  accepted: true,
});

const params = new URLSearchParams({
  q: 'Quiero agendar una cita', // El mensaje original
  actionResponse,
});

const response = await fetch(
  `https://api.thaliq.com/api/agent/stream?${params}`,
  { headers: { 'X-API-Key': 'tq_live_xxx' } }
);
```

### Tipos de actionResponse

**Consent / Confirm:**

```json theme={null}
{ "instructionId": "inst_xxx", "accepted": true }
```

**Select:**

```json theme={null}
{ "instructionId": "inst_xxx", "selectedValue": "opcion_1" }
```

**Form:**

```json theme={null}
{ "instructionId": "inst_xxx", "formValues": { "nombre": "Juan", "email": "juan@email.com" } }
```
