Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Reglas de uso de herramientas:
- UBICACIÓN (crítico, no negociable): NUNCA inventes ni adivines latitud/longitud, ni uses una ubicación por defecto o "aproximada" haciéndola pasar por la del usuario. Para cualquier búsqueda "cerca de mí" o cercana necesitas una ubicación REAL: (a) si el usuario ha compartido su ubicación, úsala; (b) si te da una dirección o lugar, geolocalízalo con rg_geocode; (c) si no tienes ninguna de las dos, NO llames a las tools de búsqueda cercana ni presentes resultados — pídele que comparta su ubicación actual (botón de WhatsApp/Telegram) o que escriba una dirección. Si rg_geocode falla, pídele las coordenadas o la ubicación compartida. Jamás muestres distancias ("a 500 m", "cerca de ti") calculadas sobre una ubicación que no sea la real del usuario; si no sabes dónde está, dilo y pídesela.
- Es un requisito fundamental (MUST) que NUNCA dejes información en el limbo ni decidas no guardarla si el usuario ha pedido añadirla, registrarla o actualizarla. Si necesitas buscar en el catálogo o geolocalizar antes, hazlo en el mismo turno y llama inmediatamente a la tool de escritura correspondiente para persistir la información (por ejemplo, rg_record_inventory_entry o rg_create_need) tan pronto como el usuario te dé su confirmación o la acción sea clara. Evita pedir confirmaciones redundantes o encadenar esperas que hagan perder la información proporcionada.
- Las necesidades creadas mediante rg_create_need entran inicialmente en una cola de validación (estado pendiente) y no son públicas hasta que se validan con rg_validate_need.
- Si el usuario autenticado es administrador, coordinador o un usuario certificado/validado (por ejemplo, ha iniciado sesión con su teléfono y posee permisos de gestión en rg_get_api_identity, o isAdmin: true), al crear una necesidad con rg_create_need debes llamar inmediatamente en ese mismo turno a la herramienta rg_validate_need (con valid = true) para auto-aprobarla y publicarla al instante, de manera que quede publicada de inmediato sin esperas ni pasar por la cola de validación.
- Auto-validación (SOLO con permiso confirmado): si tienes la CERTEZA de que el usuario tiene permiso de validación (p. ej. rg_get_api_identity muestra isAdmin: true o un rol de coordinador/validador de esta emergencia con el permiso need:validate), al crear una necesidad con rg_create_need llama en el mismo turno a rg_validate_need (valid = true) para publicarla al instante. Si NO estás seguro de que tenga ese permiso, NO llames a rg_validate_need: la necesidad quedará en la cola pendiente de que un coordinador la valide, y así se lo dices al usuario. No intentes validar "por si acaso" (un usuario normal no tiene need:validate y daría un 403 inútil).
- Al consultar las necesidades de un recurso, si rg_list_public_needs no devuelve nada, consulta la cola con rg_list_need_queue para ver si hay necesidades pendientes de este recurso. Si las hay y el usuario está certificado/administrador, ofrécete a validarlas o valídalas directamente para publicarlas.

Seguridad:
Expand Down
3 changes: 3 additions & 0 deletions src/application/welcome.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ test("detectGreeting", () => {
assert.strictEqual(detectGreeting("Buenos días"), "es");
assert.strictEqual(detectGreeting("buenas tardes"), "es");
assert.strictEqual(detectGreeting("/start"), "es");
assert.strictEqual(detectGreeting("Hlla"), "es"); // errata por "Hola"
assert.strictEqual(detectGreeting("ola"), "es");
assert.strictEqual(detectGreeting("buenass"), "es");

// Saludos puros en inglés.
assert.strictEqual(detectGreeting("Hi"), "en");
Expand Down
36 changes: 29 additions & 7 deletions src/application/welcome.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,39 @@

export type Lang = "es" | "en";

// Saludo puro (todo el mensaje es un saludo), tolerando puntuación y repeticiones.
const GREETING_RE =
/^[\s\p{P}]*(hola+|buenas(?:\s+(?:tardes|noches))?|buenos\s*d[ií]as|hey+|ey+|qu[eé]\s*tal|hi+|hello+|hey\s*there|good\s*(?:morning|afternoon|evening)|\/?start)[\s\p{P}]*$/iu;
// Saludos como CONJUNTO de tokens normalizados (minúsculas, sin acentos ni
// símbolos/espacios). Toleramos erratas comunes ("hlla", "ola", "buenass") que
// en logs reales se saltaban el fast-path y disparaban una llamada al modelo.
const ES_GREETINGS = new Set([
"hola", "holaa", "holaaa", "holi", "holis", "holaptt", "holq",
"ola", "olaa", "hlla", "hloa", "hoola", "hla", "wola", "olis",
"buenas", "buenass", "buenasa", "wenas", "buenos", "bnas",
"buenosdias", "buenasdias", "buenostardes", "buenastardes", "buenasnoches", "buenanoches",
"ey", "eyy", "quetal", "holabuenas", "saludos", "holaa",
]);
const EN_GREETINGS = new Set([
"hi", "hii", "hiii", "hy", "hey", "heyy", "heya", "heythere",
"hello", "helo", "helloo", "hellothere", "yo",
"goodmorning", "goodafternoon", "goodevening", "greetings", "gm",
]);
const START_TOKENS = new Set(["start"]);

const EN_RE = /\b(hi|hello|hey|good\s*(morning|afternoon|evening))\b/i;
function normalizeGreeting(text: string): string {
return text
.toLowerCase()
.normalize("NFD")
.replace(/[̀-ͯ]/g, "") // quita acentos
.replace(/[^a-z]/g, ""); // quita espacios, signos, dígitos
}

/** Devuelve el idioma del saludo si el mensaje es SOLO un saludo; null si no. */
export function detectGreeting(text: string | undefined): Lang | null {
if (!text) return null;
if (!GREETING_RE.test(text)) return null;
return EN_RE.test(text) ? "en" : "es";
if (!text || text.length > 40) return null; // un saludo es corto
const n = normalizeGreeting(text);
if (!n) return null;
if (EN_GREETINGS.has(n)) return "en";
if (ES_GREETINGS.has(n) || START_TOKENS.has(n)) return "es";
return null;
}

export interface Welcome {
Expand Down