feat(ai): agente IA interno con RAG sobre NAN + app web en /ai
- API: /api/ai/chat, /conversations, /documents con embeddings qwen3-embedding, coseno en SQLite, dedup por hash, historial de conversaciones - Base de conocimiento semilla (6 docs, 36 chunks): catálogo DIAGONAL, propuestas del cotizador, créditos, proceso de venta, FAQ, privacidad - App agente-ia (Vite/React/Tailwind, StudioBlank) servida en /ai/ vía nginx - 21 tests nuevos (91/91 verdes)
This commit is contained in:
34
apps/agente-ia/src/lib/sesion.test.ts
Normal file
34
apps/agente-ia/src/lib/sesion.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { cargarSesion, guardarSesion, limpiarSesion, type StorageLike } from './sesion'
|
||||
|
||||
function storageFalso(): StorageLike & { datos: Map<string, string> } {
|
||||
const datos = new Map<string, string>()
|
||||
return {
|
||||
datos,
|
||||
getItem: (k) => datos.get(k) ?? null,
|
||||
setItem: (k, v) => void datos.set(k, v),
|
||||
removeItem: (k) => void datos.delete(k),
|
||||
}
|
||||
}
|
||||
|
||||
describe('sesion del chat (localStorage)', () => {
|
||||
it('devuelve null cuando no hay sesión guardada o está vacía', () => {
|
||||
const s = storageFalso()
|
||||
expect(cargarSesion(s)).toBeNull()
|
||||
s.setItem('frasa-ai:sessionId', '')
|
||||
expect(cargarSesion(s)).toBeNull()
|
||||
})
|
||||
|
||||
it('guarda y recupera el sessionId', () => {
|
||||
const s = storageFalso()
|
||||
guardarSesion('conv-123', s)
|
||||
expect(cargarSesion(s)).toBe('conv-123')
|
||||
})
|
||||
|
||||
it('limpiarSesion elimina el sessionId (nueva conversación)', () => {
|
||||
const s = storageFalso()
|
||||
guardarSesion('conv-123', s)
|
||||
limpiarSesion(s)
|
||||
expect(cargarSesion(s)).toBeNull()
|
||||
})
|
||||
})
|
||||
22
apps/agente-ia/src/lib/sesion.ts
Normal file
22
apps/agente-ia/src/lib/sesion.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// Sesión del chat persistida en localStorage: al recargar, la conversación sigue viva.
|
||||
const CLAVE_SESION = 'frasa-ai:sessionId'
|
||||
|
||||
/** Subconjunto de Storage para poder probar sin DOM */
|
||||
export interface StorageLike {
|
||||
getItem(clave: string): string | null
|
||||
setItem(clave: string, valor: string): void
|
||||
removeItem(clave: string): void
|
||||
}
|
||||
|
||||
export function cargarSesion(storage: StorageLike = localStorage): string | null {
|
||||
const id = storage.getItem(CLAVE_SESION)
|
||||
return id && id.length > 0 ? id : null
|
||||
}
|
||||
|
||||
export function guardarSesion(sessionId: string, storage: StorageLike = localStorage): void {
|
||||
storage.setItem(CLAVE_SESION, sessionId)
|
||||
}
|
||||
|
||||
export function limpiarSesion(storage: StorageLike = localStorage): void {
|
||||
storage.removeItem(CLAVE_SESION)
|
||||
}
|
||||
Reference in New Issue
Block a user