mejoras en el modelo de clarificacion de productos

This commit is contained in:
Lucas Tettamanti
2026-01-17 06:31:49 -03:00
parent 63b9ecef61
commit 204403560e
24 changed files with 1940 additions and 873 deletions

View File

@@ -565,7 +565,8 @@ export async function searchProductAliases({ tenant_id, q = "", limit = 20 }) {
export async function getRecoRules({ tenant_id }) {
const sql = `
select id, tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
select id, tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority,
trigger_product_ids, recommended_product_ids, created_at, updated_at
from product_reco_rules
where tenant_id=$1 and active=true
order by priority asc, id asc
@@ -574,9 +575,26 @@ export async function getRecoRules({ tenant_id }) {
return rows;
}
/**
* Buscar reglas que tengan alguno de los productos como trigger.
*/
export async function getRecoRulesByProductIds({ tenant_id, product_ids = [] }) {
if (!product_ids?.length) return [];
const sql = `
select id, tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority,
trigger_product_ids, recommended_product_ids, created_at, updated_at
from product_reco_rules
where tenant_id=$1 and active=true and trigger_product_ids && $2::int[]
order by priority asc, id asc
`;
const { rows } = await pool.query(sql, [tenant_id, product_ids]);
return rows;
}
export async function getRecoRuleByKey({ tenant_id, rule_key }) {
const sql = `
select id, tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority, created_at, updated_at
select id, tenant_id, rule_key, trigger, queries, boosts, ask_slots, active, priority,
trigger_product_ids, recommended_product_ids, created_at, updated_at
from product_reco_rules
where tenant_id=$1 and rule_key=$2
limit 1

View File

@@ -123,28 +123,7 @@ export async function processMessage({
meta = null,
}) {
const { started_at, mark, msBetween } = makePerf();
// #region agent log
fetch("http://127.0.0.1:7242/ingest/86c7b1cd-c414-4eae-852c-08e57e562b3b", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sessionId: "debug-session",
runId: "pre-fix",
hypothesisId: "H2",
location: "pipeline.js:128",
message: "processMessage_enter",
data: {
tenantId: tenantId || null,
provider,
chat_id: chat_id || null,
text_len: String(text || "").length,
},
timestamp: Date.now(),
}),
}).catch(() => {});
// #endregion
const prev = await touchConversationState({ tenant_id: tenantId, wa_chat_id: chat_id });
const prev = await touchConversationState({ tenant_id: tenantId, wa_chat_id: chat_id });
mark("start");
const stageDebug = dbg.perf;
@@ -153,27 +132,7 @@ export async function processMessage({
prev?.state_updated_at &&
Date.now() - new Date(prev.state_updated_at).getTime() > 24 * 60 * 60 * 1000;
const prev_state = isStale ? "IDLE" : prev?.state || "IDLE";
// #region agent log
fetch("http://127.0.0.1:7242/ingest/86c7b1cd-c414-4eae-852c-08e57e562b3b", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sessionId: "debug-session",
runId: "pre-fix",
hypothesisId: "H3",
location: "pipeline.js:150",
message: "conversation_state_loaded",
data: {
prev_state,
isStale: Boolean(isStale),
state_updated_at: prev?.state_updated_at || null,
has_context: Boolean(prev?.context && typeof prev?.context === "object"),
},
timestamp: Date.now(),
}),
}).catch(() => {});
// #endregion
let externalCustomerId = await getExternalCustomerIdByChat({
let externalCustomerId = await getExternalCustomerIdByChat({
tenant_id: tenantId,
wa_chat_id: chat_id,
provider: "woo",
@@ -203,6 +162,9 @@ export async function processMessage({
logStage(stageDebug, "history", { has_history: Array.isArray(conversation_history), state: prev_state });
let reducedContext = prev?.context && typeof prev?.context === "object" ? { ...prev.context } : {};
// #region agent log
fetch("http://127.0.0.1:7242/ingest/86c7b1cd-c414-4eae-852c-08e57e562b3b",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"pipeline.js:164",message:"pipeline_loaded_context",data:{prev_state,has_prev_context:!!prev?.context,reducedContext_has_order_basket:!!reducedContext?.order_basket,reducedContext_basket_count:reducedContext?.order_basket?.items?.length||0,reducedContext_basket_labels:(reducedContext?.order_basket?.items||[]).map(i=>i.label)},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"H3-H4"})}).catch(()=>{});
// #endregion
let decision;
let plan;
let llmMeta;
@@ -222,28 +184,7 @@ export async function processMessage({
llmMeta = { kind: "nlu_v3", audit: decision.audit || null };
tools = [];
mark("after_turn_v3");
// #region agent log
fetch("http://127.0.0.1:7242/ingest/86c7b1cd-c414-4eae-852c-08e57e562b3b", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
sessionId: "debug-session",
runId: "pre-fix",
hypothesisId: "H4",
location: "pipeline.js:198",
message: "turn_v3_result",
data: {
intent: plan?.intent || null,
next_state: plan?.next_state || null,
missing_fields: Array.isArray(plan?.missing_fields) ? plan.missing_fields.length : null,
actions_count: Array.isArray(decision?.actions) ? decision.actions.length : null,
},
timestamp: Date.now(),
}),
}).catch(() => {});
// #endregion
const runStatus = llmMeta?.error ? "warn" : "ok";
const runStatus = llmMeta?.error ? "warn" : "ok";
const isSimulated = provider === "sim" || meta?.source === "sim";
const invariants = {
@@ -401,6 +342,10 @@ export async function processMessage({
woo_customer_error: wooCustomerError,
};
// #region agent log
fetch("http://127.0.0.1:7242/ingest/86c7b1cd-c414-4eae-852c-08e57e562b3b",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({location:"pipeline.js:345",message:"pipeline_saving_context",data:{reducedContext_basket_count:reducedContext?.order_basket?.items?.length||0,context_patch_basket_count:decision?.context_patch?.order_basket?.items?.length||0,final_context_basket_count:context?.order_basket?.items?.length||0,final_context_basket_labels:(context?.order_basket?.items||[]).map(i=>i.label),plan_intent:plan?.intent},timestamp:Date.now(),sessionId:"debug-session",hypothesisId:"H2-H4"})}).catch(()=>{});
// #endregion
const nextState = safeNextState(prev_state, context, { requested_checkout: plan.intent === "checkout" }).next_state;
plan.next_state = nextState;
@@ -429,6 +374,9 @@ export async function processMessage({
await updateRunLatency({ tenant_id: tenantId, run_id, latency_ms: end_to_end_ms });
}
// Incluir carrito completo para la UI
const fullBasket = context?.order_basket?.items || [];
sseSend("run.created", {
run_id,
ts: nowIso(),
@@ -437,7 +385,7 @@ export async function processMessage({
status: runStatus,
prev_state,
input: { text },
llm_output: { ...plan, _llm: llmMeta },
llm_output: { ...plan, _llm: llmMeta, full_basket: { items: fullBasket } },
tools,
invariants,
final_reply: plan.reply,