CreaRack-SL

Oráculo de EL — Asistente conversacional del Workspace

Asistente conversacional integrado en la caja de búsqueda del header de workspace.crearack.com. Reutiliza toda la infraestructura del Bibliotecario (embeddings BGE-M3, retrieval sobre bib_chunks, síntesis con Gemma 4 26B-A4B-IT vía Google AI Studio) con un nuevo modo de síntesis 'oracle' cuyo scope abarca el universo EsfericLabs completo: CreaRack Pro, Workspace, ADRs, runbooks, claude-method (pendiente Fase 2).

Construido en 4 PRs encadenados durante la sesión 72 (s72, 2026-05-19 tarde). Fase 3 cerrada en PR#53.


Motivación

Edu leyó la guía del Bibliotecario y detectó que el 90% del backend necesario ya existía. La caja de búsqueda del header usaba solo Fuse.js local; cablearlo al grafo era la pieza que faltaba. El Tutor de CreaRack Pro servía de referencia de patrón (modo 'tutor', multi-turno con history).


Arquitectura

Detección híbrida automática

SearchInline.tsx detecta si la query debe ir al Oráculo o al índice Fuse local mediante shouldAskOracle(query, mode):

  • Condición automática (modo Auto): ≥4 palabras O contiene ?/¿ O palabra interrogativa (qué/cómo/dónde/por qué/cuál/quién/cuándo/what/how/where/why/which/who/when). Mínimo 8 caracteres.
  • Override manual: 3 chips — Auto / Buscar (fuerza Fuse) / Preguntar (fuerza Oráculo).
  • Debounce 450ms + AbortController anti-tormenta.

Endpoint POST /api/oraculo/ask

functions/api/oraculo/ask.ts (~80 LOC tras PR#53):

POST /api/oraculo/ask
Body: { question: string, mode?: string, history?: TutorMessage[] }
Response: { answer, sources[], model, chunks_used, duration_ms }

Flujo interno:

  1. Valida question (max 500 chars) y history (shape {role, content}, cap servidor 12 turnos).
  2. Retrieval sin filtros app/source_type sobre todo el corpus del Bibliotecario (TOP_K = 8).
  3. Threshold relevance (PR#53): si matches[0].score < RELEVANCE_FLOOR (0.4) y history.length === 0 → respuesta honesta inmediata sin invocar al modelo (ahorra ~2s + tokens). En multi-turno NO aplica.
  4. Si pasa el threshold: llama a synthesizeAnswer(apiKey, question, matches, 'oracle', history?) en archivo-core.ts.
  5. INSERT best-effort a tabla D1 oraculo_queries (telemetría, sin almacenar respuestas).

Modo 'oracle' en archivo-core.ts

buildOraclePrompts genera un system prompt distinto de 'help' (restringido a CreaRack Pro) y de 'tutor' (IT general sin grounding):

  • Scope: universo EsfericLabs completo.
  • Tono: coloquial, primera persona, 100-250 palabras objetivo.
  • Honestidad obligada: si los chunks no cubren, responder "No tengo info clara sobre eso en el grafo; lo que sí veo es <X>..." antes que alucinar.
  • Multi-turn: si llega history, se serializa como bloque "--- CONVERSACIÓN HASTA AHORA ---" con turnos Usuario: / Oráculo: (mismo patrón que modo 'tutor').

Telemetría oraculo_queries (D1)

Migración 0031_create_oraculo_queries.sql. Campos: question, sources_count, top_relevance, duration_ms, mode, created_at. Sin almacenar respuestas (no inflar BD, no duplicar contenido). El campo top_relevance permite detectar gaps de corpus (queries con score bajo habitual = área no indexada).


Chat multi-turno (SearchInline.tsx)

  • Estado React: turns: Turn[] (reemplaza oracleAnswer string único, introducido en PR#52).
  • Trigger: Enter (sin debounce, a diferencia del modo búsqueda automática).
  • Caja secundaria .search-inline-oracle-followup con focus automático tras cada respuesta.
  • Botón Nueva conversación (visible solo cuando inChat === true): resetea turns[].
  • Botón Cerrar (siempre visible cuando el dropdown está abierto, introducido en PR#53): dispara setOpen(false) + inputRef.current?.blur().
  • Auto-scroll al final del chat tras cada turno.
  • Errores se renderizan como turn assistant con flag is-error pero NO se incluyen en el historyPayload del próximo turno (no contaminan el contexto del modelo).
  • Render markdown con marked (mismo patrón que NoteEditor.tsx).
  • Fuentes clickables → /wiki/<slug> cuando sourceToHref(path) mapea a src/content/wiki/<slug>.md.

Threshold de relevancia (RELEVANCE_FLOOR · PR#53)

const RELEVANCE_FLOOR = 0.4;

Calibrado empíricamente sobre embeddings BGE-M3:

Rango scoreInterpretación
> 0.5Info clara en el grafo
0.4 – 0.5Tangencial
< 0.4Ruido — no invocar al modelo

Cuando topScore < 0.4 y sin history previo → respuesta honesta inmediata + top 5 fuentes débiles como chips informativos. La entrada en oraculo_queries con top_relevance bajo sirve como señal de gap de corpus.

Excepción multi-turno: en conversaciones con history, el threshold NO aplica. El contexto del chat puede dar sentido a follow-ups aunque el retrieval de la nueva pregunta sea flojo.


Cobertura del corpus (s72)

FuenteEstado
Workspace .md (wikis)✅ vía Bibliotecario-Ingest
Workspace .ts/.tsx/.mjs✅ vía bib-reindex-ts.yml
CreaRack-Pro .py + .md✅ vía cron Hetzner bib_ast.py
claude-method/❌ sin workflow · Fase 2 pendiente

Fase 2 — Plan concreto (Opción C recomendada): nuevo workflow .github/workflows/bib-reindex-claude-method.yml en workspace que clona claude-method via GH_PAT y corre bib_ast_ts.mjs --root external/claude-method. Cron diario 00:30 UTC (tras el cron TS de 00:15). Ejecución en sesión futura.


PRs de implementación

PRCommitDescripción
#5056463f6Backend: endpoint POST /api/oraculo/ask, modo 'oracle', migración oraculo_queries
#514e282a1Frontend Fase 1: UI híbrida SearchInline.tsx, chips Auto/Buscar/Preguntar, 14 clases CSS
#52a1da9a0Multi-turn: estado turns[], caja followup, botón Nueva conversación, cap 12 turnos
#53(cierre s72)Cierre Fase 3: botón Cerrar, RELEVANCE_FLOOR=0.4, documentación s72

Validación en producción (Edu · s72)

  • Velocidad: ~1-2s por turno en queries simples, ~5-7s en exploratorias.
  • Tono: OK — coloquial, primera persona, sin filler intros.
  • Honestidad detectada: pregunta “por qué retiramos OpenRouter” → respuesta honesta con 8 fuentes chip (no wikis, no clickables — comportamiento esperado).
  • Botón Cerrar: detectado como gap por Edu tras PR#52, añadido en PR#53.
  • CI: 4/4 verde en cada PR (Prettier · TypeScript · Astro · CF Pages).

Decisiones de arquitectura relevantes

  • Modo 'oracle' separado de 'help' y 'tutor': el system prompt de 'help' está hard-restricted a “in-app help assistant for CreaRack Pro”. Reutilizarlo habría bloqueado preguntas sobre Workspace o ADRs Esferic Labs.
  • Sin persistencia D1 de conversaciones: chat efímero en cliente. Telemetría sí (por turno, sin respuesta).
  • Threshold solo en first-turn: en multi-turno el contexto del chat da sentido a follow-ups con retrieval flojo.
  • Avalancha Bibliotecario-Ingest (footgun documentado): 4 PRs × 4-5 commits autónomos = ~18 deploys CF Pages. CF cancela los antiguos, solo el último queda Active. Refactor del bot para batch queda apuntado como deuda no-crítica.

Véase también

  • [[workspace—que-es-workspace]] — contexto general del workspace donde está integrado el Oráculo

Page parcialmente aislada: el Oráculo es una feature nueva sin precedentes directos en el grafo wiki actual. Candidata a ampliar related cuando se indexen páginas sobre archivo-core, Bibliotecario-Ingest, synthesizeAnswer y la tabla oraculo_queries.