Hooks y búsqueda en vivo
Además de los helpers integrados, el asistente expone unos cuantos hooks: helpers cuyo comportamiento por defecto no hace nada, así que el widget se comporta exactamente igual que antes hasta que los sobrescribes. Se sobrescriben igual que cualquier helper (en settings.extensions.helpers, o asignando skdwn.instance.helpers.<name> en tiempo de ejecución desde la página que lo integra). El núcleo los llama en momentos concretos, así que no tienes que conectar nada en una plantilla.
Hooks de eventos
| Hook | Se dispara | Recibe |
|---|---|---|
onQuerySubmitted(query) | Justo después de que el usuario envíe una pregunta. | query: el texto enviado. |
onResponseReceived(result) | Cuando llega una respuesta. | result: { query, reply, references }. |
onFormSubmitted(formId, values) | Después de enviar un formulario. | formId y el objeto values enviado. |
No devuelven nada: úsalos para efectos secundarios como analítica, tu propia interfaz o avisar a la página anfitriona. Por ejemplo, para enviar cada pregunta y respuesta a tu herramienta de analítica:
// settings.extensions.helpers
{
onQuerySubmitted: (query) => window.analytics?.track('assistant_question', { query }),
onResponseReceived: (result) =>
window.analytics?.track('assistant_answer', {
query: result.query,
sources: (result.references || []).length,
}),
onFormSubmitted: (formId, values) =>
window.analytics?.track('assistant_form', { formId, ...values }),
}
Por defecto no hacen nada
Cada hook viene como una función vacía, así que si no lo tocas no cambia nada. Solo pagas por lo que sobrescribes.
Búsqueda en vivo: searchProvider
searchProvider convierte el cuadro de búsqueda en un cuadro de sugerencias instantáneas: mientras el usuario escribe, el asistente llama a tu proveedor (con debounce) y muestra lo que devuelva como un desplegable bajo el cuadro, antes de que llegue a enviar una consulta completa. Está desactivado hasta que aportas uno.
Contrato
// (query: string, ctx: { assistantId }) => Promise<Item[]> | Item[] | undefined
searchProvider: async (query) => {
const res = await fetch(`https://example.com/search?q=${encodeURIComponent(query)}`);
const rows = await res.json();
return rows.map((r) => ({
title: r.name, // shown text (and the query run if the row has no url)
url: r.href, // optional — see below
summary: r.excerpt, // optional secondary line
image: r.thumbnail, // optional thumbnail
metadata: { price: r.price }, // optional free-form, passed to the template
}));
}
Cada elemento es { title, url?, summary?, image?, metadata? }:
title: el texto que se muestra y la consulta que se ejecuta al pulsar una fila
sin URL (o su botón Ask).
url: opcional. Si está → la fila es un enlace y al pulsarla se navega (en la misma pestaña).
Si no está → al pulsar la fila se ejecuta el título como consulta.
summary: segunda línea opcional.image: miniatura opcional.metadata: objeto libre opcional (precio, distintivos, valoración…). El elemento
completo se pasa a la plantilla suggestion, así que todo lo que pongas aquí está disponible cuando cambies el estilo de las filas.
Lo que ve el usuario
- Mientras el proveedor se ejecuta, se muestra un esqueleto de carga en el
desplegable, para que el cuadro nunca quede vacío.
- Cada fila tiene además un botón "Ask" que abre el asistente con el título de esa
fila como consulta: útil para convertir un resultado en una pregunta más completa.
- El desplegable se cierra cuando el usuario hace clic fuera o abre el overlay.
Limita los resultados con settings.suggestionsLimit (por defecto 5). Es un valor solo de configuración: defínelo en la configuración del asistente; no hay control en la interfaz.
Cambia el estilo de las filas sobrescribiendo la plantilla suggestion (una fila); el contenedor exterior suggestions no cambia. El elemento completo está disponible como item, así que puedes mostrar tu metadata:
{% comment %} settings.extensions.templates.suggestion {% endcomment %}
<div class="skdwn-suggestion-row" role="option">
<a class="skdwn-suggestion" href="{{ item.url }}" onclick="skdwn.instance.helpers.dismissSuggestions()">
<span class="skdwn-suggestion-text">
<span class="skdwn-suggestion-title">{{ item.title | escape }}</span>
{% if item.metadata.price %}<span class="skdwn-suggestion-summary">{{ item.metadata.price }}</span>{% endif %}
</span>
</a>
<button type="button" class="skdwn-suggestion-ask" data-query="{{ item.title | escape }}"
onclick="skdwn.instance.helpers.askSuggestion(this)">{{ 'ask' | t: 'Ask' }}</button>
</div>
Envía la identidad del visitante a tu servicio de búsqueda
Un searchProvider se ejecuta en el navegador, así que puede llamar a cualquier endpoint al que llegue la página. Si tu búsqueda necesita el usuario que ha iniciado sesión, pasa un token mediante startOptions.params y léelo desde tu proveedor: el mismo mecanismo que usan los servicios vinculados.