Novedades · Changelog

Cada semana, un poco mejor.

Mejoramos GarBotGPT casi a diario. Estas son las novedades más recientes: nuevas herramientas, mejoras de velocidad y arreglos, contadas en claro.

  1. v8.17.0

    Refactor v8.17 — Helpers de Spotify extraídos (-314 líneas)

    Helpers de Spotify (intent parsing + API calls) salen al módulo `spotify-helpers.ts`. DI eliminada en Spotify tool.

    Nuevo

    • 🎵 8 helpers de Spotify a spotify-helpers.ts
    • 🔄 Retry on 429 con Retry-After header
    • 🎤 deriveSpotifyPlaylistNameFromPrompt + deriveSpotifySearchIntent
    • 📡 searchSpotifyTracks (con paginación), fetchSpotifyPlaylists, fetchSpotifyPlaylistTrackPreview
    • DI eliminada en spotify.ts (11 → 0 DI)

    Nuevo módulo

    • `src/lib/server/chat/helpers/spotify-helpers.ts` (~330 líneas).
    • Tipos públicos: SpotifyTrackDigest, SpotifyPlaylistDigest.
    • Internos: delay, getRetryDelayFromHeaders, normalizePlaylistName, stripCountExpression, fallbackPlaylistName, parseSpotifyTrackItem, asObj.

    Tools afectados

    • tools/spotify.ts: SpotifyToolContext 11 → 5 campos.
    • route.ts: 11138 → 10824 líneas (-314).
  2. v8.16.0

    Refactor v8.16 — Helpers de documento extraídos (-150 líneas)

    Primer paso del Bloque A. Helpers puros de manipulación de strings, parseo JSON, detección de tipo de archivo, parseo de números con formato europeo/americano y QuickChart URLs salen al módulo `document-helpers.ts`.

    Nuevo

    • 🧱 10+ helpers puros a document-helpers.ts
    • 🔤 normalizeForKey, sanitizeMarkdownCell, parseJsonContent
    • 📁 SPREADSHEET_EXTENSIONS + isSpreadsheetAttachment + extractFileExtension
    • 🔢 parseRequestedCount, toNumericValue (europeo/americano), buildQuickChartUrl
    • 📄 GeneratedDocumentExt + inferDocumentOutputFormat

    Nuevo módulo

    • `src/lib/server/chat/helpers/document-helpers.ts` (~210 líneas).
    • Funciones puras sin red, sin DB, sin estado. Manipulación de strings, detección de tipos de archivo, parseo robusto.
    • normalizeForKey usado en 20+ sitios de route.ts queda compartido.

    route.ts cambios

    • Helpers eliminados de route.ts y reemplazados por import statement.
    • route.ts: 11288 → 11138 líneas (-150).
  3. v8.15.0

    GarMusic Cinema — reproductor totalmente nuevo con waveform y color dinámico

    Rediseño completo desde cero con concepto editorial-cinematográfico. El album art es el héroe, el color del player se extrae del propio cover en tiempo real, la barra de progreso es un waveform de 56 barras que representa la "huella" musical de cada pista, y todo flota sobre un mesh gradient animado que también usa el color del cover.

    Nuevo

    • 🌊 Waveform de 56 barras como barra de progreso — pintada con el accent en la parte reproducida
    • 🎬 Mesh gradient animado en backdrop usando el color extraído
    • 🪟 Parallax 3D en cover (perspective 1100px, max 8°), con glow follower del ratón
    • 📰 Tipografía editorial: serif italic para labels + sans con tracking negativo en titles
    • Grain texture SVG sutil overlay (4% opacity, blend overlay)
    • 🌫️ Cover con vignette + shine + breathing animation cuando suena
    • 🔮 Botón Play con glow pulsante en accent color cuando hay reproducción
    • ⏱️ Modo fullscreen cinematográfico con cover gigante y vignette radial

    Mejorado

    • 🎨 Color de acento DINÁMICO extraído del album cover (con fallback hash si CORS bloquea)
    • Las 4 barras alrededor del playhead bouncean para simular reactivity audio (sin Web Audio API)

    Detalles únicos

    • Waveform deterministico por track (hash FNV-1a + senos mezclados) → cada canción tiene su huella única.
    • Click en cualquier punto del waveform = seek directo.
    • Stripe vertical de color en la fila de la playlist que está sonando.
    • Cover con animación "breath" sutil (scale 1 ↔ 1.02) cuando suena.
    • Color de acento se aplica vía CSS variable y atraviesa todo el componente (waveform, accent buttons, glows, focus states, fill volumen).

    Sin cambios

    • Audio engine, crossfade, shuffle, repeat, mute, volumen.
    • Persistencia localStorage (key con sufijo v2 para no chocar con la versión anterior).
    • Atajos teclado: Space, ←, →, Esc.
    • Búsqueda y drag & drop en la playlist.
    • Detección automática por flag music_player o URLs .mp3.
  4. v8.14.0

    Music Player — rediseño completo estética premium (Apple Music / Tidal)

    El reproductor GarMusic se rediseña desde cero con estética minimalista premium inspirada en Apple Music y Tidal. Fuera los gradientes saturados, el disco que gira, las ondas concéntricas y las pills de colores. En su lugar: el album cover domina la composición y su versión ampliada + desenfocada da el color al bloque entero (igual que en Spotify Now Playing). Tipografía SF Pro con jerarquía clara, controles minimalistas con SVG vectoriales, progreso ultrafino con thumb que aparece en hover, playlist tipo Spotify Desktop con número de pista que se transforma en ▶ al hover y en equalizer cuando suena.

    Nuevo

    • 🖼️ El cover ampliado y desenfocado pinta el bloque (sin gradientes hardcoded)
    • Glassmorphism real: vidrio negro 35% sobre el backdrop borroso
    • 🎯 Controles SVG vectoriales nítidos en cualquier resolución
    • 🎵 Playlist estilo Spotify Desktop: número → ▶ on hover → equalizer cuando suena
    • 📐 Tipografía SF Pro Display + tabular nums para tiempos
    • 🌫️ Progress thin (4px) que crece a 6px on hover, thumb aparece on hover
    • ⏯️ Botón Play prominente en blanco con sombra cinematográfica
    • 🖥️ Modo fullscreen renovado (cover grande + título + artist)
    • typecheck verde, build verde

    Mejorado

    • 🎨 Rediseño completo: minimalista, premium, Apple Music style

    Comportamiento conservado

    • Mismo audio engine: load/play/pause/seek/crossfade
    • Misma persistencia localStorage por player_id
    • Mismos atajos teclado (Space, ←, →, Esc)
    • Misma búsqueda + drag & drop en la playlist
    • Mismo shuffle, repeat, mute, volumen, crossfade configurable

    Lo que cambia

    • Layout: cover + info + controles arriba; playlist a la derecha (desktop) o debajo (mobile).
    • Header con marca G, eq animado cuando suena, label "Reproductor del chat".
    • Iconos lucide/feather en SVG en lugar de caracteres unicode.
    • Footer minimalista con greeting y stats de sesión.
    • Sin temas de color hardcoded — el color sale del album cover.
  5. v8.13.0

    Music Player tool — reproductor GarMusic Nova en el chat

    Nueva tool: cuando se activa el botón "Reproductor de música" en el menú del chat (icono 🎵), o cuando el mensaje contiene URLs `.mp3`, la respuesta del asistente embebe un reproductor completo: portada con parallax 3D, playlist con búsqueda y drag&drop, controles play/prev/next/shuffle/repeat/mute, crossfade configurable, modo Now Playing en pantalla completa, atajos teclado, persistencia (índice + tiempo escuchado) en localStorage. Adaptado del plugin Open WebUI a React/TypeScript con styled-jsx para no chocar con Tailwind.

    Nuevo

    • 🎵 Tool Music Player con reproductor completo dentro de la burbuja del asistente
    • 🪩 Parallax 3D en portada · disco animado · ondas cuando suena
    • 🎶 Playlist con búsqueda + drag & drop · persistencia localStorage
    • ⏯️ Crossfade configurable (0–3s) · shuffle · repeat · atajos teclado
    • 🔗 Auto-detecta URLs .mp3 en el mensaje y crea playlist con ellas
    • 🚀 Llama al asistente con `music_player: true` desde el toggle del menú

    Mejorado

    • 🎨 8 temas (purple_dream, ocean_blue, sunset_orange, forest_green, rose_gold, midnight_dark, candy_pink, cyber_neon)

    Backend

    • `src/lib/server/chat/tools/music.ts` — runMusicTool({inputText, explicitlyEnabled}) → { systemPromptAddition, musicPlayerMeta }.
    • Detección: flag `music_player: true` en el body o regex `\.mp3` en el inputText.
    • Devuelve `meta_json.music_player` con playlist + greeting + theme + crossfade_ms + source.
    • Playlist por defecto con 25 canciones GarMusic. Si hay URLs .mp3 en el mensaje, las usa en lugar de la default.

    Frontend

    • `src/components/chat/MusicPlayer.tsx` — componente self-contained con audio, playlist, parallax, mini-bar de estado.
    • styled-jsx para CSS scoped (no choca con Tailwind global).
    • Persistencia: índice de pista + tiempo escuchado + canciones reproducidas por player_id (= message.id).
    • Cleanup completo del audio + listeners en unmount.
    • Botón toggle 🎵 en el menú de tools (mobile + desktop).
    • MessageBubble detecta `meta_json.music_player` y renderiza el componente.
  6. v8.12.0

    Refactor v8.12 — System prompt builders extraídos a módulo puro

    Cinco fragmentos del system prompt salen de route.ts a un único módulo de funciones puras: `src/lib/server/chat/prompt-builders.ts`. Los fragmentos: recuerdos del usuario, instrucciones del Code Interpreter, contexto del proyecto (instrucciones + memorias + inventario), contexto de carpeta (instrucciones + memorias + inventario), y plantilla de generación de documento (xlsx/json/markdown). Sin DI — todo son funciones que toman datos y devuelven string.

    Nuevo

    • 🧱 5 system prompt builders → prompt-builders.ts
    • 🧮 67 líneas inline reemplazadas por 5 llamadas (1 línea cada una)
    • 🪶 Funciones puras — sin red, sin BD, sin mutación
    • typecheck verde, build verde

    Seguridad

    • 🔒 Comportamiento idéntico — mismos textos exactos para cada caso

    Nuevo módulo

    • `src/lib/server/chat/prompt-builders.ts` (~110 líneas).
    • Exporta: buildUserMemoriesPrompt, buildCodeInterpreterPrompt, buildProjectContextPrompt, buildFolderContextPrompt, buildDocumentGenerationPrompt.
    • Cada función devuelve "" si no aplica el contexto, o el fragmento concatenado con \n\n al sistema.

    route.ts cambios

    • userMemories: 3 → 1 línea.
    • Code Interpreter: 21 → 2 líneas (con comentario).
    • Proyecto context: 11 → 1 línea.
    • Folder context: 13 → 1 línea.
    • Document generation: 19 → 1 línea.
    • Total: 67 → 6 líneas en route.ts.

    Próximos releases

    • v8.13 — DeepResearch (~320 líneas, ALTO RIESGO).
    • v8.14 — NetworkDriveRag (~1.800 líneas).
    • v8.15 — Streaming progressive REAL (refactor SSE).
  7. v8.11.0

    Refactor v8.11 — Spreadsheet analysis tool extraído

    El bloque Spreadsheet analysis (118 líneas: lectura xlsx con SheetJS, cálculo de stats numéricos por columna, detección de eje categórico para chart, generación de URLs QuickChart) sale a `src/lib/server/chat/tools/spreadsheet.ts`. Mantiene los límites originales: 3 archivos máx, 3 hojas por archivo, 1200 filas muestreadas, 40 columnas máx, 4 charts.

    Nuevo

    • 📊 Spreadsheet analysis (118 líneas) → tools/spreadsheet.ts
    • 🧬 2 helpers DI (toNumericValue, buildQuickChartUrl)
    • typecheck verde, build verde

    Seguridad

    • 🔒 Comportamiento idéntico — mismos thresholds para columnas numéricas/categóricas

    Nuevo módulo

    • `src/lib/server/chat/tools/spreadsheet.ts` (~190 líneas) — runSpreadsheetTool(ctx) → { systemPromptAddition, spreadsheetChartImages, status }.
    • Importa xlsx dinámicamente (igual que antes) y descarga del bucket user-files via serviceClient inyectado.
    • Status: ok | error | skipped (skipped si no hay attachments).

    Próximos releases

    • v8.12 — DeepResearch (~320 líneas, ALTO RIESGO).
    • v8.13 — NetworkDriveRag (~1.800 líneas).
    • v8.14 — Streaming progressive REAL.
  8. v8.10.0

    Refactor v8.10 — YouTube summary tool extraído

    El bloque YouTube summary (50 líneas: descarga metadata + transcript de hasta 2 vídeos en paralelo, fallback a búsqueda web si la transcripción es pobre, construcción del [RESUMEN DE YOUTUBE] block del system prompt) sale a `src/lib/server/chat/tools/youtube.ts`. Status enum ok|error|skipped.

    Nuevo

    • 🎬 YouTube summary (50 líneas) → tools/youtube.ts
    • 🧬 4 helpers DI (runWithConcurrency, fetchYouTubeMetadata, fetchYouTubeTranscript, searchWeb)
    • typecheck verde, build verde

    Seguridad

    • 🔒 Comportamiento idéntico — slice 12000 chars de transcript, slice 320 de fallback sources

    Nuevo módulo

    • `src/lib/server/chat/tools/youtube.ts` (~135 líneas) — runYoutubeTool(ctx) → { systemPromptAddition, youtubeSummaries, status }.
    • Mantiene los límites originales: 2 vídeos máx en paralelo, transcript a 12000 chars, 5 fuentes de fallback si transcript < 120 chars.
    • Corre antes del tool-timeline en route.ts (no llama recordTool).

    Próximos releases

    • v8.11 — Spreadsheet analysis (~140 líneas, lectura xlsx + tablas + chart candidates).
    • v8.12 — DeepResearch (~320 líneas, ALTO RIESGO).
    • v8.13 — NetworkDriveRag (~1.800 líneas).
  9. v8.9.0

    Refactor v8.9 — OCR tool extraído (gpt-4o-mini visión + factura)

    Continúa el strangler-pattern. El bloque OCR (72 líneas: llamada a gpt-4o-mini visión, parseo JSON con summary + full_text + document_type + language + confidence + invoice_fields, construcción del bloque [OCR ADJUNTOS] del system prompt) se mueve a `src/lib/server/chat/tools/ocr.ts`. Status enum: ok | error | skipped. Si OCR falla no bloquea la respuesta del modelo principal.

    Nuevo

    • 👁️ OCR (72 líneas) → tools/ocr.ts
    • 📦 12 líneas en route.ts en lugar de 72
    • typecheck verde, build verde

    Seguridad

    • 🔒 Comportamiento idéntico — mismo prompt JSON + mismas heurísticas

    Nuevo módulo

    • `src/lib/server/chat/tools/ocr.ts` (~150 líneas) — runOcrTool(ctx) → { systemPromptAddition, ocrOutput, status }.
    • Status: ok | error | skipped (skipped si no hay imágenes o no hay API key).
    • parseJsonContent inyectado vía DI; el resto (URL, modelo, prompts) viven en el módulo.

    Próximos releases

    • v8.10 — DeepResearch (~320 líneas) — ALTO RIESGO: muta webSources/rankedWebSources + cache global.
    • v8.11 — NetworkDriveRag (~1.800 líneas con ~30 helpers internos).
    • v8.12 — Streaming progressive REAL.
    • v8.13 — Provider streams a `streaming/{openai,anthropic,google}.ts`.
  10. v8.8.0

    Refactor v8.8 — Google AdSense + Google Analytics extraídos (en paralelo)

    Continúa el strangler-pattern. Dos bloques grandes salen del monolito en una sola release: Google AdSense (172 líneas — modo summary y modo comparison hoy-vs-ayer, con métricas + dimensiones + report meta para cards) y Google Analytics GA4 (99 líneas — modo summary y modo comparison con previousDateRanges, breakdown por dimensiones). Ambos a `src/lib/server/chat/tools/google-{adsense,analytics}.ts`. Se enchufan al multi-tool parallel: AdSense + Analytics + web/db/spotify/gmail/microsoft pueden correr a la vez.

    Nuevo

    • 📈 Google AdSense (172 líneas) → tools/google-adsense.ts
    • 📊 Google Analytics GA4 (99 líneas) → tools/google-analytics.ts
    • 🧬 AdSense: 10 helpers DI · Analytics: 0 DI (todo viene de google-analytics-intent.ts)
    • typecheck verde, build verde

    Mejorado

    • Ambos en multi-tool parallel — corren con web/db/spotify/gmail/microsoft

    Seguridad

    • 🔒 Comportamiento idéntico — mismos systemPrompts y reportMetas

    Nuevos módulos

    • `src/lib/server/chat/tools/google-adsense.ts` (~250 líneas) — runAdSenseTool(ctx) → { systemPromptAddition, adsenseReportMeta, status }.
    • `src/lib/server/chat/tools/google-analytics.ts` (~170 líneas) — runGoogleAnalyticsTool(ctx) → { systemPromptAddition, googleAnalyticsReportMeta, status }.
    • AdSense maneja modo summary (con dateRange + dimensions + rowsTable) y modo comparison hoy-vs-ayer (Promise.all por cuenta).
    • Analytics maneja modo summary (con dimensions + breakdown rows) y modo comparison (con previousDateRanges).

    route.ts cambios

    • `adsensePromise` y `googleAnalyticsPromise` se lanzan junto al resto de promises del multi-tool parallel.
    • AdSense: bloque de 172 líneas reemplazado por 9 líneas de await + recordTool.
    • Analytics: bloque de 99 líneas reemplazado por 9 líneas de await + recordTool.
    • Reduce ~250 líneas netas en el monolito.

    Próximos releases

    • v8.9 — Calendar + Drive + Monday + Github + restantes integraciones (~700 líneas).
    • v8.10 — NetworkDriveRag (~1800 líneas con ~30 helpers internos).
    • v8.11 — DeepResearch (~400 líneas).
    • v8.12 — Streaming progressive REAL (refactor SSE).
  11. v8.7.0

    Refactor v8.7 — Microsoft 365 (Outlook + OneDrive) extraído + en paralelo

    Continúa el strangler-pattern del monolito. El bloque Microsoft 365 (156 líneas: lectura Outlook con focused/sender/email filters, envío Outlook con borrador + confirmación + fallback mailto, lectura de OneDrive con search) se mueve a `src/lib/server/chat/tools/microsoft.ts`. Se enchufa al multi-tool parallel: si el usuario activa Microsoft + otra integración, ahora corren en paralelo. Comparte 11 helpers de redacción de correo con Gmail (parseGmailSendIntent, generateGmailDraftIfNeeded, etc.) — siguen en route.ts y se inyectan vía DI.

    Nuevo

    • 📨 Bloque Microsoft 365 (156 líneas) extraído a tools/microsoft.ts
    • 🧬 19 helpers inyectados vía DI (11 compartidos con Gmail + Drive helpers + parseRequestedCount + extractGmailSenderName)
    • typecheck verde, build verde

    Mejorado

    • Microsoft 365 también va en paralelo con web/db/spotify/gmail

    Seguridad

    • 🔒 Comportamiento idéntico — mismo orden de aplicación al systemPrompt

    Nuevo módulo

    • `src/lib/server/chat/tools/microsoft.ts` (~250 líneas) — runMicrosoftTool(ctx) → { systemPromptAddition, status, durationMs }
    • Maneja los 3 modos: mail read (Outlook con filter focused/sender/email), mail send (con confirmación + mailto fallback), drive read (OneDrive search).
    • fetchMicrosoftMessages, sendMicrosoftMail y fetchMicrosoftDriveFiles ya estaban en `@/lib/microsoft-graph` — se importan directos.

    route.ts cambios

    • `microsoftPromise` se lanza junto a webSearchPromise/dbQueryPromise/spotifyPromise/gmailPromise.
    • Bloque inline (try/catch + 156 líneas) reemplazado por 7 líneas: `await microsoftPromise` + recordTool().
    • Helpers compartidos con Gmail siguen en route.ts. Se podrán mover a un módulo `mail-helpers` cuando ambos estén estables.

    Próximos releases

    • v8.8 — AdSense + Google Analytics (~340 líneas, con report metas).
    • v8.9 — Calendar + Drive + Monday + Github + restantes.
    • v8.10 — NetworkDriveRag (~1800 líneas con ~30 helpers).
    • v8.11 — DeepResearch (~400 líneas).
  12. v8.6.0

    Refactor v8.6 — Gmail tool extraído a su módulo (en paralelo con web/db/spotify)

    Continúa el strangler-pattern del monolito api/chat/route.ts: el bloque Gmail (122 líneas, lectura de bandeja + envío con borrador + fallback mailto) se mueve a `src/lib/server/chat/tools/gmail.ts` con el mismo patrón de Dependency Injection que web/db/spotify. Al extraerlo se enchufa al multi-tool parallel: cuando el usuario activa Gmail + otra tool, ahora corren en paralelo. Los helpers internos (parseGmailSendIntent, fetchGmailMessages, sendGmailMessage, etc.) siguen en route.ts y se inyectan vía context — Microsoft 365 también los usa, así que se extraerán cuando ese bloque también salga.

    Nuevo

    • 📧 Bloque Gmail (122 líneas) extraído a tools/gmail.ts
    • 🧬 17 helpers inyectados vía DI (regex EMAIL_ADDRESS_RE + parseRequestedCount + parseGmailSendIntent + fetchGmailMessages + sendGmailMessage + …)
    • typecheck verde, build verde

    Mejorado

    • Gmail también va en paralelo con web_search + db_query + spotify

    Seguridad

    • 🔒 Comportamiento idéntico — mismo orden de aplicación al systemPrompt

    Nuevo módulo

    • `src/lib/server/chat/tools/gmail.ts` (~210 líneas) — runGmailTool(ctx) → { systemPromptAddition, status, durationMs }
    • GmailToolContext con 17 helpers inyectados vía DI (ningún helper se mueve todavía).
    • Maneja capacidad real, lectura de bandeja con filtro Gmail q=, envío con borrador + confirmación, fallback mailto si no hay token.

    route.ts cambios

    • `gmailPromise` se lanza junto a webSearchPromise/dbQueryPromise/spotifyPromise en el bloque MULTI-TOOL PARALLEL.
    • Bloque inline (try/catch + 122 líneas) reemplazado por 7 líneas: `await gmailPromise` + recordTool().
    • Helpers internos (parseGmailSendIntent, etc.) siguen en route.ts hasta que Microsoft 365 también se extraiga.

    Próximos releases

    • v8.7 — Microsoft 365 (Outlook + OneDrive) ~580 líneas. Comparte helpers Gmail.
    • v8.8 — AdSense + Google Analytics + Calendar + Drive + Monday + Github (~700 líneas).
    • v8.9 — NetworkDriveRag (~1800 líneas con ~30 helpers internos).
    • v8.10 — DeepResearch (~400 líneas).
  13. v8.5.0

    Multi-tool parallel REAL — web_search + db_query + spotify corren simultáneamente

    Hito importante del refactor v8.x: ahora cuando el usuario activa múltiples tools, web_search + db_query + spotify NO esperan unos a otros — corren con Promise.all() y el tiempo total es max(web, db, spotify) en lugar de sum(). Beneficio típico: respuestas con tools 2-3× más rápidas. Implementado lanzando las promises temprano (justo después de calcular los inputs) y haciendo `await thePromise` en cada call site original — el orden de aplicación al systemPrompt se mantiene exacto.

    Nuevo

    • ⏱️ Tiempo total: max(web=5s, db=2s, spotify=1s) = 5s en lugar de 8s
    • 🛠️ typecheck verde, build verde

    Mejorado

    • web_search + db_query + spotify ahora corren EN PARALELO
    • Sin cambios de comportamiento — solo optimización de timing

    Seguridad

    • 🔒 Orden del systemPrompt preservado (mismo orden de aplicación)

    route.ts cambios

    • Justo después de las var declarations (línea ~9156), lanzar las 3 promises:
    • - webSearchPromise = effectiveWebSearch ? runWebSearchTool(...) : null
    • - dbQueryPromise = effectiveDbQuery ? runDbQueryTool(...) : null
    • - spotifyPromise = effectiveSpotify ? runSpotifyTool(...) : null
    • En cada call site original, hacer `await thePromise` en lugar de `await runXTool(...)`.
    • Orden de aplicación al systemPrompt: web → db → spotify (igual que antes).

    Próximos parallels

    • rag_search no se paraleliza aún porque está mucho antes en el flow (línea 7000) — en v8.6 mover su call al mismo punto.
    • Integraciones gmail/microsoft/etc están entre medio y no extraídas — quedan secuenciales por ahora.
    • Cuando todos los tools estén extraídos (v8.10+), un Promise.allSettled global puede paralelizar TODO.
  14. v8.4.0

    Refactor: Spotify tool extraído del monolito (cambio de plan)

    Continúa el refactor v8.x. NetworkDriveRag y DeepResearch resultaron ser MUCHO más grandes (1800 y 400+ líneas con 30+ helpers locales) — extraerlos limpiamente requiere reorganizar también esos helpers, lo que es trabajo de varias releases. Pivotamos a integraciones más self-contained: Spotify (~100 líneas) extraído a `lib/server/chat/tools/spotify.ts` con dependency injection. typecheck verde, comportamiento idéntico.

    Nuevo

    • 🎵 Nueva función pura: runSpotifyTool(ctx) → SpotifyToolResult
    • 🔌 5 helpers inyectados (fetchSpotifyPlaylists, searchSpotifyTracks, etc.)
    • ✂️ route.ts pierde ~100 líneas de spotify inline
    • ⏸️ networkDriveRag (1800 líneas) y deepResearch (400+ líneas) deferred — requieren extracción de helpers locales primero

    tools/spotify.ts

    • runSpotifyTool(ctx) maneja read + create con permisos scope-based.
    • Tipos SpotifyTrackDigest y SpotifyPlaylistDigest en módulo (compat con los del route.ts).
    • Errores: 429 (rate limit) tratado distinto que el resto.
    • spotifyPlaylistsMeta + spotifyPlaylistPreviewMeta devueltos para el caller.

    Próximo plan

    • v8.5.0: Multi-tool parallel REAL — wrapping web_search + rag + db_query + spotify (4 tools ya extraídos) en Promise.allSettled.
    • v8.6.0+: Resto de integraciones (gmail, drive, calendar, microsoft, monday, github) — se irán extrayendo cuando los helpers estén disponibles.
    • NetworkDriveRag y DeepResearch: extraer en releases dedicadas (v8.10+) tras mover helpers locales.
  15. v8.3.0

    Refactor: db_query extraído del monolito

    Continúa el refactor v8.x. El bloque MÁS COMPLEJO del chat route (db_query, ~245 líneas con SQL gen via gpt-4o-mini, fallback automático a SELECT * FROM tabla, schema inventario, telemetría) ahora vive en `lib/server/chat/tools/db-query.ts` con `runDbQueryTool(ctx) → result`. Helpers (selectDbConnectionForPrompt, sanitizeMarkdownCell, wantsDbSchemaListing, etc.) siguen en route.ts y se inyectan vía context. typecheck verde, build verde, comportamiento idéntico.

    Nuevo

    • 🧱 Nueva función pura: runDbQueryTool(ctx) → DbQueryToolResult
    • 🔌 12 helpers inyectados vía context (decryptSecret, sanitizeMarkdownCell, etc.)
    • ✂️ route.ts pierde ~245 líneas (12.276 → 12.021)
    • 📦 ChatDbConnection type movido a tools/types.ts (compartido)
    • typecheck verde, build verde, comportamiento intacto

    tools/db-query.ts (~340 líneas)

    • Status enum extendido: ok | error | no_connection | no_schema
    • runTablePreviewFallback como helper interno cerrado.
    • Imports limpios desde @/lib/db-runtime y @/lib/secret-store.
    • Tipos del context usan typeof de las funciones reales para evitar incompatibilidades de unions estrictas.

    route.ts

    • Block legacy de 245 líneas eliminado completamente.
    • Reemplazado por llamada a runDbQueryTool con 12 helpers como dependencies.
    • recordTool sigue marcando con tool name "db_query".

    Próxima release

    • v8.4.0: runNetworkDriveRag (~200 líneas) — similar al RAG pero contra network_drives + network_files.
  16. v8.2.0

    Refactor: rag_search extraído del monolito

    Continúa el refactor v8.x. El bloque inline de 75 líneas del RAG (project scope, match_file_chunks + fallback threshold + file_contents persistidos + citation tracking) ahora vive en `lib/server/chat/tools/rag-search.ts` con `runRagSearchTool(ctx) → result`. tool-timeline movido al inicio del handler para estar en scope de todos los tools. typecheck verde, build verde.

    Nuevo

    • 🧱 Nueva función pura: runRagSearchTool(ctx) → RagSearchToolResult
    • 🔄 fetchChunks helper con threshold inicial 0.62 + fallback 0.48 (idéntico al inline)
    • 🎯 Soporta scope por projectId Y por fileIds (preparado para folder/attachments en futuras releases)
    • 📦 Citation tracking estricto preservado
    • ✂️ route.ts pierde 75 líneas (12.276 → 12.201)
    • tool-timeline movido al inicio del handler (antes estaba después del bloque RAG)

    tools/rag-search.ts

    • RagSearchToolContext: serviceClient, queryEmbedding, ragMode, citeMode, projectId, fileIds[].
    • RagSearchToolResult: systemPromptAddition, sources[], chunks[], status, detail, durationMs.
    • fetchChunks(): primary threshold 0.62 → fallback 0.48 (mismo comportamiento).
    • STRICT_PROMPT_PREFIX, ASSISTED_PROMPT_PREFIX, CITATION_TRACKING_BLOCK extraídos como constantes.
    • Manejo de no_results vs error vs ok como status enum.
    • Filtrado por fileIds opcional para scope folder/attachments.

    route.ts

    • Block inline RAG-project reemplazado por llamada a runRagSearchTool.
    • _toolTimeline + recordTool movidos al inicio del handler (antes del primer tool block).
    • recordTool ahora marca el RAG con tool name "rag_project" (preparado para "rag_folder" después).

    Verificación

    • npm run typecheck → 0 errors
    • npm run build → completo, todas las rutas compiladas

    Próxima release

    • v8.3.0: runDbQuery + helpers (~250 líneas, más complejo: tiene fallback automático, schema inventario, gen SQL con gpt-4o-mini, telemetría).
  17. v8.1.0

    Refactor: web_search extraído del monolito chat route

    Continúa el refactor v8.x. El bloque inline de 80 líneas de web_search ahora vive en `lib/server/chat/tools/web-search.ts` con interfaz pura `runWebSearchTool(ctx) → result`. Los helpers (rankWebSources, collectDeepResearchImages) siguen en route.ts y se inyectan vía context — esto permite extraer la orquestación sin romper nada (otras 500 líneas de helpers se moverán en v8.x posteriores). Sin cambios funcionales, typecheck verde, build verde, comportamiento idéntico.

    Nuevo

    • 🧱 Nueva función pura: runWebSearchTool(ctx) → WebSearchToolResult
    • 🔌 Dependency injection para los helpers (rankWebSources + collectDeepResearchImages)
    • 📦 Nuevo módulo: src/lib/server/chat/tools/web-search.ts (~190 líneas)
    • 📘 Nuevo módulo: src/lib/server/chat/tools/types.ts (tipos compartidos)
    • ✂️ route.ts pierde 80 líneas inline (12.356 → 12.276)
    • typecheck verde, build verde, sin cambios de comportamiento

    Nuevo módulo tools/web-search.ts

    • WebSearchToolContext interface con rawInput, effectiveQuery, deepResearch, researchMode + helpers inyectados.
    • WebSearchToolResult interface con systemPromptAddition, webAnswerSummary, webSources, rankedWebSources, webSearchImages, durationMs, status, detail.
    • Lógica idéntica al inline original: search → enrich (si deep) → rank → format prompt → collect images.
    • Manejo de errores: try/catch interno + return {status:"error", detail}.

    route.ts cambios

    • Import: runWebSearchTool desde el nuevo módulo.
    • Block inline reemplazado por llamada a runWebSearchTool con dependencies inyectadas.
    • Variables externas (webAnswerSummary, webSources, rankedWebSources, webSearchImages, systemPrompt) actualizadas con el resultado.
    • recordTool sigue funcionando sin cambios.

    Verificación

    • npm run typecheck → 0 errors
    • npm run lint → 0 errors en mis archivos nuevos (los 132 errores existentes son de archivos no tocados)
    • npm run build → completo sin errores, todas las rutas compiladas

    Próxima release

    • v8.2.0: runRagSearch (file_chunks + match_file_chunks). Más complejo: ~300 líneas con vector search + sources push.
  18. v8.0.0

    Refactor del chat route — fundación para sacar el monolito de 12k líneas

    src/app/api/chat/route.ts tiene 12.356 líneas: 14 tool blocks, RAG, memorias, live runs, persistencia, providers... todo en un solo archivo. Esto bloquea multi-tool parallel real, streaming progressive y tests E2E. v8.0.0 establece la fundación: estructura `src/lib/server/chat/tools/`, README con roadmap completo de extracción tool-por-tool, y primera pieza extraída como prueba del patrón (`tool-timeline.ts`). Las siguientes 11 releases (v8.1 → v8.11) sacan tools una a una con tests, hasta llegar a multi-tool parallel REAL en v8.8 y streaming progressive en v8.9.

    Nuevo

    • 🏗️ Bump a v8.x.0 marca el inicio del refactor mayor del chat route.
    • 📁 Estructura nueva: src/lib/server/chat/tools/ con README arquitectónico.
    • 🧱 Primera extracción: createToolTimeline() ahora vive en tool-timeline.ts (era inline en route.ts).
    • 📋 Roadmap claro de 11 releases siguientes con scope concreto y líneas estimadas.
    • Sin cambios funcionales — el comportamiento del chat es idéntico.
    • Sin cambios de schema.
    • 🎯 Próxima release (v8.1): runWebSearch + helpers (rankWebSources, collectDeepResearchImages) — ~200 líneas extraídas.

    Estructura nueva

    • src/lib/server/chat/README.md actualizado con estado actual + roadmap completo + patrón de extracción.
    • src/lib/server/chat/tools/tool-timeline.ts — createToolTimeline() factory con métodos start/done/record/entries/toSseEvent.
    • Patrón documentado: cada tool exporta una función pura runXTool(ctx) → result que devuelve systemPromptAddition + sources + metadata.
    • Convenciones documentadas: no mutar arrays compartidos, errores con status flag, LLM intermedio recibe apiKey por context.

    route.ts (cambios mínimos)

    • Importa createToolTimeline desde el nuevo módulo.
    • recordTool() ahora delega a la instancia del timeline.
    • toolTimelineEvent generado vía _toolTimeline.toSseEvent() (sin lógica inline).
    • Sin cambios de comportamiento — typecheck verde.

    Roadmap

    • v8.1.0 → runWebSearch (-200 líneas)
    • v8.2.0 → runRagSearch (-300)
    • v8.3.0 → runDbQuery (-250)
    • v8.4.0 → runNetworkDriveRag (-200)
    • v8.5.0 → runDeepResearch (-400)
    • v8.6.0 → 7 tools de integraciones gmail/drive/calendar/spotify/microsoft/monday/github (-800)
    • v8.7.0 → runDocumentGeneration + runSpreadsheetAnalysis + runCodeInterpreter (-300)
    • v8.8.0 → Multi-tool parallel REAL con Promise.allSettled
    • v8.9.0 → Streaming progressive con SSE events conforme cada tool termina
    • v8.10.0 → Provider streams a streaming/{openai,anthropic,google}.ts
    • v8.11.0 → Memory hierarchy + system prompt builders a módulos propios
  19. v7.42.0

    UI agentes IA del canal + Tool timeline visible durante respuesta

    Cierre de los items pendientes de v7.41. Modal completo de gestión de agentes IA del canal accesible desde un botón "Agentes" en el header (gradient violet→fuchsia). Permite a los admins añadir modelos con trigger configurable (mention/keyword/always), keywords, display name, system prompt y cooldown. Y nuevo evento SSE `tool_timeline_event` que el chat route emite con los timings de cada tool ejecutado (web_search, db_query) — el cliente lo pinta como pill flotante junto al token meter durante el streaming: "🌐 Web 2.1s · 🗃️ DB 0.8s · total 2.9s". El multi-tool parallel real (Promise.all del chat route) sigue deferred — requiere tests E2E antes de tocar el path más crítico de la app.

    Nuevo

    • 🤖 Modal de agentes IA del canal (botón "Agentes" gradient en header).
    • ⏯️ Toggle on/off por agente sin tener que borrarlo.
    • 🗑️ Quitar agente con confirmación.
    • 📊 Tool timeline pill durante streaming: muestra qué tools se ejecutaron y cuánto tardaron.
    • 🌐 Iconos por tool: web_search (Globe azul), db_query (Database emerald), rag (BookOpen violet), network_drive (HardDrive amber).
    • ⏱️ Total acumulado al final de la pill ("total 2.9s").

    Mejorado

    • 🎯 UI completo: select modelo + tabs trigger (Mención/Keyword/Siempre) + keywords + display name + system prompt + cooldown.

    Arreglado

    • 🔴 Tools que fallaron salen en rose con icono de error.

    ChannelAgentsModal.tsx (nuevo)

    • Portal modal con backdrop blur + max 2xl.
    • Header con badge "AGENTES IA" + #channel-name + descripción.
    • Lista de agents con avatar bot + display name + trigger badge color-coded + keywords + system prompt preview.
    • Toggle On/Off por agente (PATCH enabled).
    • Botón eliminar (DELETE) con confirm().
    • Form de añadir colapsable: select modelo + segmented tabs trigger + keywords (CSV) + display name + cooldown number + system prompt textarea.
    • Disabled inputs si no es admin.

    ChannelView.tsx — botón Agentes

    • Nuevo botón gradient violet→fuchsia con icono Sparkles + label "Agentes" en el header.
    • showAgentsModal state que abre/cierra el modal.
    • isAdmin pasado al modal vía myChannelRole === "admin".

    chat/route.ts — SSE tool_timeline_event

    • Variable toolTimeline acumula entries {tool, ms, status, detail} durante la fase de tools.
    • Función helper recordTool(tool, startedAt, status, detail).
    • Tracking en web_search y db_query (try → ok, catch → error).
    • Emisión: data: {"type":"tool_timeline_event","data":{"tools":[...]}} antes de imageGenerationStreamEvent.
    • cleanAssistantStreamContent ahora también filtra tool_timeline_event.

    ChatInput.tsx — handler del evento

    • Parser detecta eventData.type === "tool_timeline_event".
    • window.dispatchEvent('chat-tool-timeline', {conversationId, tools}).
    • continue para no añadir al fullContent.

    ToolTimelinePill.tsx + ChatArea.tsx

    • Componente nuevo con iconos por tool, color por estado, fmtMs(ms) helper, total acumulado.
    • ChatArea escucha custom event 'chat-tool-timeline', filtra por conversationId, guarda en state.
    • Reset state al cambiar de conversación.
    • Render junto al TokenContextMeter en el header del streaming.

    Pendiente realmente difícil (deferred a v7.43+)

    • Multi-tool parallel TRUE: refactor del chat route para que web_search + RAG + db_query corran con Promise.allSettled. Requiere extraer ~400 líneas inline a funciones puras + tests E2E del path completo (chat con cada tool y combinaciones) antes de tocar.
    • Streaming progressive REAL: convertir todo el chat route a SSE desde el inicio (no solo después de los tools). Otra ronda de refactor profundo.
  20. v7.41.0

    AI permanente en canales — agente vive en el canal con triggers configurables

    Implementada la mejora #6 pendiente de v7.40.0: ahora puedes asignar un modelo IA a un canal con tres modos de activación (mention/keyword/always) + cooldown anti-loop + system prompt personalizado para darle personalidad. Antes la IA solo respondía cuando la mencionabas explícitamente con @. Multi-tool parallel y streaming progressive de tools quedan deferred a v7.42 porque requieren refactor profundo (>400 líneas) del chat route que no es seguro hacer en una sola pasada.

    Nuevo

    • 🤖 Modelos IA viven en canales con trigger configurable.
    • 🎯 3 modos de trigger: `mention` (@ explícito), `keyword` (palabras clave), `always` (responde a todo).
    • ⏱️ Cooldown configurable (default 5s) para evitar bucles cuando trigger=always.
    • 👤 Display name custom — el agente puede llamarse "ResearchBot" en lugar del nombre del modelo.
    • 🛡️ Tabla channel_agent_last_reply para implementar cooldown sin race conditions.

    Mejorado

    • 🎨 System prompt personalizado por canal — dale personalidad/foco al agente.

    Seguridad

    • 🔒 RLS: solo admins del canal pueden asignar/quitar agentes. Cualquier miembro los ve.

    Schema (Supabase)

    • Tabla channel_agents (channel_id, agent_id, model_config_id, trigger_mode, trigger_keywords, display_name, system_prompt, cooldown_seconds, enabled).
    • CHECK constraint trigger_mode IN (mention, keyword, always).
    • CHECK constraint: agent_id O model_config_id deben estar set.
    • UNIQUE(channel_id, agent_id) y UNIQUE(channel_id, model_config_id).
    • Indice partial idx_channel_agents_channel WHERE enabled=true.
    • Tabla channel_agent_last_reply (channel_agent_id PK, last_reply_at) para cooldown.
    • Trigger touch_updated_at automático.
    • 4 policies RLS (SELECT cualquier miembro, INSERT/UPDATE/DELETE solo admin).

    API endpoints nuevos

    • GET /api/channels/[id]/agents — lista agents activos con info del modelo enriched.
    • POST /api/channels/[id]/agents — asigna modelo/agent al canal con trigger config.
    • PATCH /api/channels/[id]/agents/[agentId] — actualiza trigger_mode, keywords, system_prompt, etc.
    • DELETE /api/channels/[id]/agents/[agentId] — quita el agent del canal.

    Auto-trigger en POST /api/channels/[id]/messages

    • 1) Mantiene flujo legacy: si hay @mention explícita, el modelo responde igual que antes.
    • 2) Si NO hubo mention, comprueba channel_agents activos con trigger evaluation:
    • - always → triggered=true
    • - keyword → triggered=alguna keyword aparece en lower-case
    • - mention → ya cubierto por el flujo legacy
    • 3) Cooldown check: si han pasado <cooldown_seconds desde last_reply_at, skip.
    • 4) Resuelve ResolvedModel completo via resolveModelByConfigId() (helper nuevo).
    • 5) Pasa extraSystemPrompt del agent a generateChannelModelReply para personality.
    • 6) Marca last_reply_at vía upsert en channel_agent_last_reply.
    • 7) attachments_json del mensaje incluye {kind: "agent_trigger", reason} para debug.

    Pendiente para v7.42

    • UI admin para asignar agentes desde la página del canal (usar API REST que ya existe).
    • Multi-tool parallel: web_search + RAG + db_query con Promise.all en chat/route.ts (~400 líneas refactor).
    • Streaming progresivo: emitir SSE events tool_start/tool_chunk/tool_done conforme llegan resultados de cada tool.
  21. v7.40.0

    IA: 9 mejoras (auto-routing, hybrid RAG, self-RAG, memory hierarchy, citations, auto-debug, token live)

    Paquete grande de mejoras en el sistema de IA: medidor de tokens y context window en vivo durante streaming; detector de formato que añade lenguaje a bloques de código sin language; endpoint de auto-debug que analiza por qué falló una respuesta y propone arreglos (gpt-4o-mini); citation tracking estricto en RAG con formato [N] y verificación; detector de tipo de tarea (code/reasoning/creative/simple/general) extendiendo el auto-router existente; nuevo endpoint /api/memory/hierarchy que consolida memorias proyecto > carpeta > conversación con deduplicación; nuevo endpoint /api/rag/should-search (Self-RAG) que decide si la query necesita RAG/web/db antes de gastar tokens; función SQL match_file_chunks_hybrid que combina vector + tsvector con pesos 70/30. Quedan pendientes (refactor profundo del chat route): multi-tool en paralelo, streaming progresivo y AI permanente en canales.

    Nuevo

    • 📊 TokenContextMeter: tokens en vivo + barra de context window con color (verde/amber/rojo) + coste USD acumulado.
    • 🔧 enhanceMarkdownContent: detecta SQL/JS/TS/Python/JSON/Bash/YAML/CSS/HTML en bloques sin lenguaje declarado.
    • 📚 Citation tracking estricto: cada claim factual con [N] obligatorio, "no inventes citas", "di cuando no tengas info".
    • 🧠 detectTaskType: clasifica input como code/reasoning/creative/simple/general usando ~15 patrones regex.
    • 🪜 Memory hierarchy: GET /api/memory/hierarchy consolida user+project+folder+conversation memories con dedup heurístico y orden por especificidad.
    • 🤔 Self-RAG: POST /api/rag/should-search decide si necesita RAG/web/db con heurística + gpt-4o-mini fallback. Conservador por defecto.
    • 🔍 Hybrid search: nueva función SQL match_file_chunks_hybrid (vector 70% + ts_rank_cd 30%) con normalización por subset, top-50 vector pre-filter, tsvector index GIN.

    Arreglado

    • 🐞 AutoDebugCard: tras thumbs-down, gpt-4o-mini analiza qué falló y sugiere fixes (cambiar modelo, añadir contexto, activar tool, replantear).

    UI nueva

    • src/components/chat/TokenContextMeter.tsx — pill flotante con tokens, context%, $ coste.
    • src/components/chat/AutoDebugCard.tsx — card rose con sugerencias de fix tras thumbs-down.
    • src/lib/format-detector.ts — detectCodeLanguage(), looksLikeTable(), enhanceMarkdownContent(), detectDates().
    • ChatArea.tsx — meter visible debajo del nombre del modelo durante streaming.
    • MessageBubble.tsx — botón "🐞 Auto-debug" tras thumbs-down + render con enhanceMarkdownContent.

    API endpoints nuevos

    • POST /api/debug/analyze — analiza un message_id y devuelve {diagnosis, suggestions[]}.
    • GET /api/memory/hierarchy?folder_id=&project_id=&conversation_id= — devuelve memories consolidadas con scope+pinned+counts.
    • POST /api/rag/should-search — clasificador self-RAG, devuelve {should_rag, should_web, should_db, reason, confidence}.

    Backend mejoras

    • auto-router.ts: detectTaskType() y TASK_PREFERRED_FAMILY map (code → codex/sonnet, reasoning → o1/opus, creative → 4o/sonnet).
    • chat/route.ts: cite_mode prompt reescrito a citation tracking estricto con [N] obligatorio y "no inventes".
    • chat/route.ts: detectTaskType() invocado en auto-route para enriquecer el system prompt (futuro).

    Database

    • file_chunks: nueva columna content_tsv tsvector GENERATED ALWAYS AS (to_tsvector(spanish, content)) STORED.
    • Index GIN idx_file_chunks_content_tsv.
    • Función match_file_chunks_hybrid(user_id, query_text, query_embedding, match_count, file_ids) → top-K combinando vector + keyword.
    • Pre-filter de 50 candidatos por vector + normalización Z-score por subset + score 0.7*vec + 0.3*kw.

    Pendiente (refactor profundo)

    • Multi-tool en paralelo: requiere refactor del chat route para que web_search + RAG + DB corran con Promise.all en lugar de await secuencial.
    • Streaming progresivo: enviar resultados parciales de tools como SSE events conforme llegan.
    • AI permanente en canales: feature aparte que merece su propio análisis. La tabla agents y agent_executions ya existen.
  22. v7.39.0

    Carpetas: anidación, compartir, plantillas y banner — UI completa

    Cierre de la línea de carpetas avanzadas iniciada en v7.37/v7.38. Ahora todas las funciones que tenían el schema listo en DB tienen UI funcional: árbol jerárquico de carpetas en el sidebar, modal de invitar usuarios con roles (viewer/editor/admin), galería de plantillas en el modal de crear carpeta, "Guardar como plantilla" desde Settings, banner image (URL) y picker de carpeta padre. Smart filters se queda para más adelante (necesita un editor de query JSON).

    Nuevo

    • 🪺 Sidebar renderiza carpetas anidadas como árbol con indentación + línea punteada lateral.
    • 🔗 Tab "Compartir" en Settings con búsqueda por email + roles + cambiar/quitar acceso.
    • 💾 Botón "Guardar como plantilla" en tab Organización (con flag pública/privada).
    • 🖼️ Campo "Banner image URL" con preview live.
    • 🌲 Picker de carpeta padre (anidación).
    • 📊 use_count se incrementa cuando alguien usa una plantilla.

    Mejorado

    • 📦 Galería de plantillas en CreateFolderModal con preview y aplicación instantánea.

    API endpoints nuevos

    • GET / POST / PATCH /api/folder-templates — list (own + public), create, increment use_count.
    • DELETE / PATCH /api/folder-templates/:id — solo owner via RLS.
    • GET / POST /api/folders/:id/shares — list (con profiles join) e invite por email/user_id.
    • PATCH / DELETE /api/folders/:id/shares/:shareId — cambiar rol o quitar acceso.
    • Validación de permisos: owner + admins de la carpeta pueden invitar/eliminar; el invitado puede salirse.

    CreateFolderModal — Plantillas

    • Carga GET /api/folder-templates al abrir.
    • Sección colapsable "Empezar desde una plantilla" con grid 2 columnas.
    • Cada tarjeta muestra icono+color, nombre, descripción, badge "Pública", use_count y count tools.
    • Click → applyTemplate() rellena icon/accent/instructions automáticamente.
    • Pill superior con nombre de plantilla aplicada + X para quitarla.
    • Al crear, se incrementa use_count vía PATCH.

    FolderSettingsModal — 2 tabs nuevas

    • Tab "Compartir": email input + role select + invite button (gradient violet→fuchsia).
    • Lista de personas con avatar, nombre, fecha invitación, role select (viewer/editor/admin), botón quitar.
    • Tab "Organización": banner URL con preview + parent folder picker + sección "Guardar como plantilla".
    • Save as template: name + description + toggle pública/privada.

    FolderSettingsModal — saveFolder

    • Persiste banner_url y parent_folder_id junto con los demás campos.

    Sidebar — árbol jerárquico

    • Agrupa folders por parent_folder_id en una map.
    • Renderiza root folders primero. Cada nivel tiene paddingLeft proporcional (max 3 niveles).
    • Borde lateral punteado para indicar la jerarquía visual.
    • Recursive renderWithChildren() ilimitado en profundidad.

    Pendiente

    • 🧠 Smart filters: editor visual de filtros JSON. Schema (smart_filters_json) listo en DB.
    • 🖼️ Banner upload: actualmente solo URL. Falta integración con Storage para upload.
    • 🤖 Auto-classify: sugerir carpeta para chat nuevo basado en primer mensaje.
  23. v7.38.0

    Carpetas avanzadas: color, favorito, anidación, compartir y plantillas (DB + UI)

    Completados los items de v7.37.0 que necesitaban migración de schema. Ahora cada carpeta puede tener un color de acento (13 paletas), marcarse como favorita (sube arriba en el sidebar), anidarse bajo otra carpeta (parent_folder_id), tener un banner image, y existir como "smart folder" con filtros dinámicos. Además se añaden dos tablas nuevas con RLS completo: `folder_shares` para compartir carpetas con otros usuarios (roles viewer/editor/admin) y `folder_templates` para guardar plantillas reutilizables (públicas o privadas). UI integrada en CreateFolderModal y FolderSettingsModal con color picker y toggle de favorito.

    Nuevo

    • Favoritas suben al principio del sidebar automáticamente.

    Mejorado

    • 🎨 13 colores de acento por carpeta (sky, violet, blue, emerald, amber, rose, indigo, teal, orange, pink, cyan, lime, red).
    • 🪺 Anidación: cada carpeta puede tener un `parent_folder_id` (DB lista, UI próxima).
    • 🖼️ Banner image opcional por carpeta (DB lista, UI próxima).
    • 🧠 Smart folders con filtros JSON (DB lista, UI próxima).

    Seguridad

    • 🔗 Compartir carpeta con otro usuario con roles viewer/editor/admin (DB + RLS lista).
    • 📦 Templates de carpeta — guardar y reutilizar configuración (DB + RLS lista).
    • 🛡️ RLS completo en folder_shares y folder_templates con función helper folder_shared_role().

    Schema (Supabase)

    • folders: + parent_folder_id (FK self-ref ON DELETE SET NULL), accent_color, is_favorite, banner_url, smart_filters_json.
    • CHECK constraint folders_no_self_parent (carpeta no puede ser su propia padre).
    • Indices: idx_folders_parent_id (partial WHERE NOT NULL), idx_folders_user_favorite (partial WHERE is_favorite).
    • Tabla folder_shares (folder_id, user_id, role, invited_by, UNIQUE(folder_id, user_id)).
    • Tabla folder_templates con use_count, is_public, todos los campos de carpeta.
    • Función SECURITY DEFINER folder_shared_role(folder_id, user_id) → text.
    • Policies RLS completas en folder_shares (owner+admin gestionan, invitados ven y pueden salirse).
    • Policies RLS completas en folder_templates (own + public read).
    • Policies adicionales en folders: folders_shared_select, folders_shared_update.
    • Trigger touch_updated_at en folder_templates.

    Types (src/lib/types.ts)

    • export type FolderAccentColor (13 valores).
    • Folder ampliada con parent_folder_id, accent_color, is_favorite, banner_url, smart_filters_json.
    • export type FolderShareRole, interface FolderShare.
    • export interface FolderTemplate.

    folder-visuals.tsx — paleta de colores

    • Nuevo FOLDER_ACCENTS record con 13 paletas (icon/soft/dot/gradient/ring por color).
    • export FOLDER_ACCENT_LIST y normalizeFolderAccent() helper.
    • FolderIconBadge ahora acepta prop `accent` para colorear dinámicamente.
    • Backwards-compat: folderAccent legacy ahora apunta a la paleta sky.

    CreateFolderModal — color + favorite

    • Nuevo state accent (sky default) y isFavorite.
    • Color picker con 13 swatches circulares + Check overlay.
    • Toggle de favorito con icono Star + dot indicador.
    • Preview superior muestra el badge con el color elegido + estrella si favorito.
    • onSubmit acepta payload {name, icon, instructions, accent_color, is_favorite} o la firma 3-args legacy (compat).
    • Validación de nombre duplicado se mantiene.

    FolderSettingsModal — color + favorite

    • Hidrata accent + isFavorite del folder existente.
    • Sección nueva "Color de acento" con 13 swatches grandes.
    • Sección nueva "Carpeta favorita" con toggle Star.
    • saveFolder envía accent_color e is_favorite a supabase.
    • Evento geia-folder-updated incluye accent_color e is_favorite para que el sidebar pueda re-render sin recargar.

    Sidebar (Sidebar.tsx + SidebarSleek.tsx)

    • createFolder typed con CreateFolderFn (union: payload | 3-args legacy) usando useCallback<T>.
    • Carpetas se cargan ordenadas por is_favorite DESC primero.
    • FolderIconBadge en cada fila usa folder.accent_color.
    • Estrella amber al lado del nombre si is_favorite.

    Pendiente (UI para próximas releases)

    • Anidación: árbol jerárquico en el sidebar (parent_folder_id ya existe en DB).
    • Compartir carpeta: modal de invitar usuarios (folder_shares ya existe en DB).
    • Templates: galería de plantillas en CreateFolderModal (folder_templates ya existe en DB).
    • Smart folders: editor de filtros JSON.
    • Banner image: upload UI.
  24. v7.37.0

    Carpetas: paquete masivo (búsqueda, drag-drop, export, activity log, fixes…)

    Repaso a fondo del sistema de carpetas con 11 mejoras y arreglos en una sola release. Resumen: pinned arriba, buscador con ⌘F, drag-drop para reordenar, export a JSON/Markdown, sparkline de actividad de los últimos 7 días, chips de tools por defecto en el header, validación inline de nombre duplicado al crear, "Indexar ahora" para ficheros sin indexar, cache scoped por usuario para evitar fugas entre cuentas, atajos de teclado, stats con tamaño total de documentos. Las funciones que requieren cambio de schema (anidación, compartir carpeta, templates, color, banner, smart folders, favorito) quedan documentadas para la siguiente release tras confirmar la migración.

    Nuevo

    • 🔍 Búsqueda inline de chats dentro de la carpeta (⌘F).
    • 🤚 Drag-drop para reordenar chats — persiste folder_sort_order automáticamente.
    • 📌 Pinned chats agrupados arriba con header propio "Fijados".
    • 📥 Export a JSON (full backup con mensajes) o Markdown (legible).
    • 📊 Activity log: sparkline 7 días + count "este mes".
    • 🔧 Chips de "Activas:" mostrando las tools por defecto de la carpeta en el hero.
    • ⚠️ Validación inline de nombre duplicado al crear carpeta — antes el toast desde el padre te hacía perder lo escrito.
    • 🚀 Botón "Indexar ahora" (gradient violeta) para ficheros con ingest_status=none.
    • ⌨️ Atajos: ⌘F enfoca búsqueda, ⌘, abre Settings, Esc limpia búsqueda.
    • 💾 Stats: tamaño total de documentos (KB/MB/GB), último chat, count este mes.

    Seguridad

    • 🔒 Cache de useFolderContext scoped por user_id (antes era global, fuga entre cuentas).

    FolderWelcomeScreen.tsx — rewrite

    • Buscador con focus-ring sky, atajo ⌘F, cierre con Esc, kbd visible cuando vacío.
    • Drag-drop nativo HTML5 con persist en lote: reorder dispara N updates a `conversations.folder_sort_order`. La fila arrastrada se opaca, la dropZone se resalta sky.
    • Pinned chats van a sección propia "Fijados" arriba con divider y header amber. Las pinned no se reordenan (siempre van arriba), solo las "Recientes" son arrastrables.
    • Stats hero ahora muestran chats + último activo, documentos + tamaño total, memoria, knowledge.
    • Sparkline de últimos 7 días (gradient sky → bars proporcional al máximo) + count "X chats este mes" con icono trending.
    • Chips de default_tools en el hero ("Activas: Web · Code · Imagen…") con sparkle violeta.
    • Botón "Exportar" con menú JSON/Markdown.
    • - JSON: backup completo con folder + stats + conversaciones + mensajes.
    • - Markdown: legible, con prompt de carpeta arriba y cada chat formateado.
    • Atajos ⌘F (search), ⌘, (settings), Esc (clear search).

    CreateFolderModal.tsx — validación

    • Nuevo prop `existingNames: string[]`.
    • Validación case-insensitive contra duplicados.
    • Input se pone con border rose + ring rose cuando hay duplicado.
    • Mensaje inline "Ya tienes una carpeta con ese nombre. Elige otro."
    • Botón submit cambia su label a "Nombre duplicado" y se deshabilita.

    FolderSettingsModal.tsx — Indexar ahora

    • El botón "Reindexar" cambia a "Indexar ahora" cuando `ingest_status === "none"` (o vacío).
    • Style gradient violet→fuchsia con sombra y scale al hover, para destacar que ese fichero NO está indexado todavía.
    • Fichero con status `done`/`failed`/`queued` mantiene el botón neutro como antes.

    useFolderContext.ts — cache por usuario

    • folderCache pasa de `Map<id, {name, icon}>` a `Map<id, {userId, name, icon}>`.
    • Lookup invalida la entrada si el slot.userId no coincide con el currentUserId actual.
    • currentUserId se obtiene de supabase.auth.getUser() en el primer fetch.
    • Listener `geia-folder-updated` también escribe el userId actual.
    • Resultado: si cambias de cuenta sin recargar, no ves los nombres/iconos del usuario anterior.

    Sidebar.tsx — pasa existingNames

    • CreateFolderModal recibe `existingNames={folders.map(f => f.name)}`.
    • La validación duplicado del sidebar (toast al crear) sigue funcionando, pero ahora el modal valida ANTES de enviar — no se pierde lo escrito.

    Pendiente (requiere migración de schema)

    • F1 — Carpetas anidadas (parent_folder_id en `folders`).
    • F2 — Compartir carpeta (tabla `folder_shares` + permisos).
    • F3 — Templates (tabla `folder_templates`).
    • F9 — Smart folders / vistas dinámicas (tabla o JSON de filtros).
    • M2/B7 — Color de acento por carpeta (`accent_color` en `folders`).
    • M3 — Banner image (`banner_url` en `folders`).
    • M6 — Favorito (`is_favorite` en `folders`).
    • B1 — Unificar carpetas personales y de proyecto (refactor profundo).
    • F6 — Auto-classification (no requiere schema, pero sí endpoint AI).
    • F11 — Herencia de padre (depende de F1).
  25. v7.36.0

    Draft del chat IA persiste también en chat nuevo (sin id)

    ChatInput ya guardaba el draft por conversación en localStorage, pero sólo cuando había `activeConversationId`. Si abrías un chat NUEVO (sin enviar nada todavía → no hay id) y refrescabas la página, lo escrito se perdía. Fix: usamos el slot `__new__` cuando no hay conversación activa, así el draft sobrevive a refrescos antes del primer envío. Al mandar el primer mensaje (que crea la conversación), limpiamos tanto el slot del nuevo id como el slot `__new__` para que no quede basura.

    Nuevo

    • 💾 Chat nuevo: lo escrito se conserva tras refrescar.
    • 💾 Slot dedicado `geia:chat-draft:__new__` para chats sin id.
    • 🧹 Al enviar desde un chat nuevo, se limpian ambos slots (el `__new__` y el del nuevo id) para evitar drafts huérfanos.
    • El comportamiento existente (draft por conversación abierta) se mantiene intacto.

    Cambios en ChatInput.tsx

    • draftStorageKey: `${PREFIX}${activeConversationId || "__new__"}` (antes devolvía null cuando no había id).
    • Los useEffect de restore y persist ya no early-return con null — siempre operan.
    • handleSubmit captura `wasNewChat = !convId` antes de createConversation.
    • Tras éxito en chat nuevo, además de limpiar `draftStorageKey`, también limpia explícitamente `${PREFIX}__new__` para cubrir el race entre createConversation y el re-render del useMemo.
    • Misma limpieza en la rama de message queue (cuando se mete en cola).
  26. v7.35.0

    Draft de canal persiste al refrescar + Voz: vuelve la transcripción del usuario

    Dos fixes: (1) En canales, lo que escribes en el composer ahora persiste en localStorage por canal — al refrescar la página, recuperas el texto donde lo dejaste. Antes se perdía. (2) En el modo voz, la transcripción de TUS mensajes había dejado de aparecer en el chat. Causa: el modelo `gpt-4o-mini-transcribe` con prompt (introducido en v7.19) era rechazado silenciosamente por OpenAI en algunos casos, dejando de enviar el evento `conversation.item.input_audio_transcription.completed`. Vuelta a `whisper-1` (modelo estable de toda la vida) sin prompt + log explícito si OpenAI vuelve a rechazar la config.

    Nuevo

    • 💾 Composer del canal: tu draft sobrevive a refrescos.
    • 💾 El draft es por canal — cada canal tiene el suyo en localStorage (`channel-draft:{channel.id}`).
    • 💾 Al enviar, el draft se borra del localStorage automáticamente.
    • 💾 Al cambiar de canal, se rehidrata el draft del nuevo.
    • 🎙️ Voz: transcripción del usuario vuelve a aparecer en el chat.
    • 🎙️ Modelo de transcripción revertido de `gpt-4o-mini-transcribe` → `whisper-1` (estable, universal).
    • 🎙️ Eliminado el prompt experimental que reforzaba vocabulario — algunos session.update eran rechazados con esa combinación.

    Mejorado

    • 🪵 Log explícito en consola si OpenAI vuelve a rechazar el `input_audio_transcription` para diagnóstico rápido.

    ChannelView — draft persistido

    • useState con lazy init lee `localStorage.getItem(`channel-draft:${channel.id}`)`.
    • useEffect sync escribe en localStorage cada vez que `input` cambia (vacío → remove, no-vacío → set).
    • useEffect on `channel.id` change rehidrata el draft del nuevo canal.
    • handleSend limpia la entrada del localStorage al enviar.
    • Sin coste perceptible (localStorage es síncrono y barato; sin debounce).

    useRealtimeVoice — fix transcripción usuario

    • input_audio_transcription.model: `gpt-4o-mini-transcribe` → `whisper-1`.
    • Eliminado el campo `prompt` (vocabulario custom). Era experimental y a veces hacía que OpenAI rechazara todo el session.update.
    • Síntoma de la regresión: el usuario hablaba, GIA respondía con voz, pero la burbuja del usuario se quedaba con `…` (placeholder) porque `conversation.item.input_audio_transcription.completed` nunca llegaba → handleTranscript nunca se ejecutaba → la burbuja nunca se actualizaba ni se persistía.
    • Log nuevo en case "error": si el mensaje contiene "transcription" o "input_audio_transcription", warning explícito en consola.
  27. v7.34.0

    Canales: el chat dentro del canal también con estilo nivel dios

    Continuación de v7.33: ahora los mensajes, el composer y los empty states dentro de un canal abierto también tienen el rediseño completo. Avatares de mensaje 10×10 con presence ring animado (verde online, azul typing) + glow detrás, badges "Tú", "IA", "Admin" con gradients, indicador "escribiendo" con dots animados, reactions con gradient violet→fuchsia cuando reaccionaste tú, contador de hilo como pill blue→cyan, toolbar hover con backdrop-blur + iconos coloreados al hover, composer con focus ring violeta y botón send gradient violet→fuchsia→pink con glow, empty state del canal con shimmer + sparkle.

    Nuevo

    • 🦸 Avatar del mensaje: 10×10 con ring de presencia animado (online verde, typing azul) + glow blur detrás.
    • ⌨️ Badge "Tú" en los mensajes propios (indigo pill).
    • 🤖 Badge "IA" gradient violet→fuchsia con logo.
    • 👑 Badge "Admin" gradient amber→orange con corona.
    • ✍️ Badge "escribiendo" con 3 dots animados cuando un usuario está typing.
    • 😀 Reacciones: gradient violet→fuchsia cuando es tuya, pill blanca con backdrop-blur cuando no.
    • 🧵 Contador de hilo: pill blue→cyan con flecha al hover.
    • 🪟 Toolbar hover: rounded-xl + ring + shadow elevada + iconos que cambian a color al hover (smile→amber, reply→blue, pin→amber, link→violet, trash→rose).
    • 😀 Quick emoji picker: rounded-2xl + emojis 18px + scale 1.25 al hover.
    • Empty state del canal: hero icon 80×80 con halo violet→fuchsia→pink, título con shimmer animado, "Sé el primero en escribir 👋".
    • 📂 Botón "Cargar mensajes anteriores": glassy con backdrop-blur + spinner violeta + chevron.
    • 🔢 Contador de chars en el composer pasa a rosa cuando >1800.

    Mejorado

    • Composer: bg blanco/85 con backdrop-blur, focus ring violeta + shadow violeta, botones que escalan, send con gradient violet→fuchsia→pink + glow potente.
    • ⌨️ Hint de @ con kbd visual.

    ChannelView — mensajes

    • Animation entrada: cubic-bezier(0.34, 1.56, 0.64, 1) bounce.
    • Hover: gradient sutil indigo (mensaje propio) o zinc (otros).
    • Avatar 10×10 con ring 2px presence-aware + glow blur detrás.
    • Toolbar hover: rounded-xl, backdrop-blur-xl, shadow elevada, divider antes de Edit/Delete.
    • Quick emoji picker: rounded-2xl con channel-chip-in animation.

    ChannelView — empty state

    • Hero icon 80×80 con halo gradient blur
    • Título #channel.name con shimmer animado
    • Mensaje secundario "Sé el primero en escribir 👋"
    • channel-chip-in animation al entrar

    ChannelView — composer

    • Container glassy: bg-white/85 + backdrop-blur-xl, shadow soft.
    • Focus state: ring violet 2px + shadow violet.
    • Attachment button: rounded-xl, hover scale 1.10, color violet.
    • Send button: gradient violet→fuchsia→pink cuando activo, shadow violet, scale al hover, scale-95 active.
    • Spinner cuando uploading/sending.
    • Hint de @ con kbd visual.
    • Counter rosa cuando >1800 chars.

    ChannelView — reactions

    • Pills con channel-chip-in animation entrada.
    • Reacción propia: gradient violet→fuchsia + ring violeta + shadow.
    • Otras: bg-white/80 backdrop-blur + ring zinc.
    • Emoji 14px + count tabular-nums.
    • Hover: scale 1.10.

    ChannelView — thread badge

    • Pill gradient blue→cyan + ring + flecha →
    • hover scale 1.02
  28. v7.33.0

    Canales: rediseño visual nivel dios

    Repaso a fondo de la sección /channels: aside con orbes flotantes y blur liquid-glass, header con gradient violet→fuchsia→pink, búsqueda más refinada con shortcut visible (⌘K), tabs en píldoras con conteos, fila de canal con glow lateral pulsante cuando está activa, halo en el icono al hover, badges animados (mention shake + pulse), avatares de personas con presence ring que pulsa en verde cuando online o azul cuando typing (con dots animados), header del canal abierto con icono más grande y halo, empty state hero con shimmer en el título y orbes de fondo gigantes.

    Nuevo

    • 🪐 Aside con 3 orbes flotantes detrás (violet, blue, pink) con animación independiente.
    • Botón "+" con gradient violet→fuchsia→pink, escala y glow al hover.
    • ⌘K visible en el placeholder de búsqueda + ring focus violeta.
    • 🎯 Tabs como píldoras con contador (canales: total, personas: count online con dot pulsante).
    • 🌟 Fila de canal activa: glow lateral 3px pulsante con gradient + ring violeta.
    • 🌀 Icono del canal con halo difuso al hover (escala 1.06 + rotate -3°).
    • 🚨 Badge de menciones: gradient rose→pink, pulse + shake.
    • 🔔 Badge de no leídos: gradient violet→indigo, pulse.
    • 🟢 Avatares de personas: ring que pulsa verde cuando online, azul cuando typing.
    • ⌨️ "Typing" con 3 dots animados al lado del estado.
    • 👑 Tag "Admin" amarillo + corona dorada.
    • 🏆 Empty state: orb gigante 600px detrás, hero icon con halo violet→pink, title con shimmer animado, 3 chips Canales/Personas/DMs, hint "⌘K para buscar".

    Mejorado

    • 🎨 Header del canal abierto: icono más grande (40×40) con halo, gradient en el badge "Privado", chip de miembros emerald con dot.

    CSS — globals.css

    • 13 nuevos @keyframes: channel-orb-float-1/2/3, channel-active-pulse, channel-badge-pulse, channel-mention-shake, channel-presence-ring-online, channel-presence-ring-typing, channel-empty-shimmer, channel-chip-in, channel-skeleton-sweep, channel-header-glow.
    • Clases utility nuevas: channels-aside-orb-1/2/3, channel-row-active-bar, channel-badge-mention/unread, channel-presence-online/typing, channel-icon-halo, channel-empty-shimmer-title, channel-chip-in, channel-skeleton, channel-header-glow.
    • prefers-reduced-motion respeta todas las animaciones nuevas.

    Página /channels (page.tsx)

    • Aside ahora bg-white/85 + backdrop-blur-xl con 3 orbes detrás.
    • Header del aside con icono "MessageSquarePlus" en gradient violet→fuchsia→pink y título con gradient text.
    • Empty state nuevo: orbes detrás (600px y 280px y 320px), hero icon Hash 80×80 con halo, sparkle flotante decorativo, título con shimmer, 3 FeatureChip (Canales / Personas / DMs), hint con kbd ⌘K.

    ChannelList (sidebar)

    • Header con padding mayor, separator más sutil, gradient suave de fondo.
    • Search input con ring focus violeta, kbd ⌘K visible cuando vacío, X cuando hay query.
    • Tabs reescritas como píldoras dentro de un container ring + contadores.
    • Filtro de menciones reescrito como pill con gradient rose→pink al activar.
    • Empty states con icon hero + halo + texto secundario.
    • Filas de canal: padding mayor, rounded-xl, transición de translate-x al hover, halo en el icono, descripción inline.
    • Filas de personas: avatar 9×9, presence ring animado verde/azul, dots de typing, tag "Admin" amarillo, → arrow al hover.

    ChannelView (header del canal abierto)

    • Glow detrás del header (gradient ellipse violet + blue) animado.
    • Icono del canal: 40×40 con halo blur, ring violeta, gradient bg.
    • Hash icon en violeta brillante.
    • Tag "Privado" como pill amarilla con shield icon.
    • Chip de miembros: gradient emerald→teal con icono de Users colored.
  29. v7.32.0

    Fix: la card de imagen se duplicaba al terminar la generación

    En v7.25 hicimos persistir la card efímera (`activeImageGenerationRun`) hasta que terminara la imagen. En v7.30 hicimos que el bubble del mensaje persistido también renderizara la card. Resultado: cuando la imagen se attachaba al mensaje, durante unos instantes había DOS cards visibles — la efímera y la del mensaje persistido. Fix: ChatArea oculta la efímera si detecta que la URL ya está en algún mensaje persistido (en meta_json.generated_image_url, meta_json.image_url o attachments_json.kind=generated_image). Además, ChatInput recarga los mensajes inmediatamente tras éxito para que el persistido aparezca rápido.

    Nuevo

    • 🚫 Sin más duplicados: la card efímera desaparece cuando el mensaje persistido la incluye.
    • 🔍 Match por URL exacta entre `imageGenerationRun.imageUrl` y los 3 sitios donde la imagen puede estar persistida.
    • 🛡️ Si la imagen aún no está persistida (race), la efímera sigue mostrándose — sin parpadeo.

    Mejorado

    • ChatInput.tsx hace `loadMessages(convId, { silent: true })` justo después de éxito para acelerar la transición efímero → persistido.

    Cambios en ChatArea.tsx

    • `activeImageGenerationRun` useMemo ahora también depende de `messages`.
    • Cuando run.status === "ready" y run.imageUrl, busca la URL en cada mensaje del conversationId.
    • Match en 3 sitios: meta_json.image_url, meta_json.generated_image_url, attachments_json[kind=generated_image].url.
    • Si encuentra match → devuelve null (oculta la card efímera). Si no → sigue mostrando la efímera.

    Cambios en ChatInput.tsx

    • Tras `setImageGenerationRun({ status: "ready", ... })`, llama a `loadMessages(convId, { silent: true })`.
    • Esto trae el assistant message con la imagen attachada (meta_json + attachments_json) al store.
    • Una vez en el store, ChatArea detecta el match por URL y oculta la efímera.
  30. v7.31.0

    Las frases del centro del preview ahora rotan también

    En v7.29 hicimos rotar el subtítulo de la cabecera de la card, pero las dos líneas grandes del centro del preview ("Renderizando preview" + "La imagen aparecerá aquí al completarse") seguían fijas. Ahora rotan cada 2.2s entre 10 pares (Renderizando preview, Mezclando colores, Esculpiendo formas, Encendiendo luces, Tejiendo detalles, Afinando contraste, Capturando matices, Pintando capas, Casi lista, Empaquetando imagen). Cada cambio entra con un fade-in con blur.

    Nuevo

    • 🔄 10 pares de frases rotativas en el centro del preview (cada 2.2s).
    • Animación fade-in con blur al cambiar de frase (0.7s cubic-bezier).
    • prefers-reduced-motion respetado.

    Arreglado

    • ⏸️ Sólo rotan en estado `running`. En error muestra "Generación detenida" + el error real.

1118 versiones publicadas · página 35 de 38. Míralo dentro de la app.