ux improved
This commit is contained in:
@@ -65,7 +65,7 @@ export async function touchConversationState({ tenant_id, wa_chat_id }) {
|
||||
on conflict (tenant_id, wa_chat_id)
|
||||
do update set
|
||||
updated_at = now()
|
||||
returning tenant_id, wa_chat_id, state, last_intent, context, updated_at
|
||||
returning tenant_id, wa_chat_id, state, last_intent, last_order_id, context, state_updated_at, updated_at, created_at
|
||||
`;
|
||||
const { rows } = await pool.query(q, [tenant_id, wa_chat_id]);
|
||||
return rows[0] || null;
|
||||
@@ -272,10 +272,16 @@ export async function getRunById({ tenant_id, run_id }) {
|
||||
export async function getRecentMessagesForLLM({
|
||||
tenant_id,
|
||||
wa_chat_id,
|
||||
limit = 20,
|
||||
maxCharsPerMessage = 800,
|
||||
}) {
|
||||
const lim = Math.max(1, Math.min(50, parseInt(limit, 10) || 20));
|
||||
const limRaw = parseInt(process.env.LIMIT_CONVERSATIONS || "", 10);
|
||||
const maxCharsRaw = parseInt(process.env.MAX_CHARS_PER_MESSAGE || "", 10);
|
||||
if (!Number.isFinite(limRaw) || limRaw <= 0) {
|
||||
throw new Error("LIMIT_CONVERSATIONS env is required and must be a positive integer");
|
||||
}
|
||||
if (!Number.isFinite(maxCharsRaw) || maxCharsRaw <= 0) {
|
||||
throw new Error("MAX_CHARS_PER_MESSAGE env is required and must be a positive integer");
|
||||
}
|
||||
const lim = Math.max(1, Math.min(50, limRaw));
|
||||
const q = `
|
||||
select direction, ts, text
|
||||
from wa_messages
|
||||
@@ -290,7 +296,7 @@ export async function getRecentMessagesForLLM({
|
||||
|
||||
return rows.reverse().map((r) => ({
|
||||
role: r.direction === "in" ? "user" : "assistant",
|
||||
content: String(r.text).trim().slice(0, maxCharsPerMessage),
|
||||
content: String(r.text).trim().slice(0, maxCharsRaw),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -557,6 +563,28 @@ 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
|
||||
from product_reco_rules
|
||||
where tenant_id=$1 and active=true
|
||||
order by priority asc, id asc
|
||||
`;
|
||||
const { rows } = await pool.query(sql, [tenant_id]);
|
||||
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
|
||||
from product_reco_rules
|
||||
where tenant_id=$1 and rule_key=$2
|
||||
limit 1
|
||||
`;
|
||||
const { rows } = await pool.query(sql, [tenant_id, rule_key]);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
export async function getProductEmbedding({ tenant_id, content_hash }) {
|
||||
const sql = `
|
||||
select tenant_id, content_hash, content_text, embedding, model, updated_at
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import crypto from "crypto";
|
||||
import {
|
||||
getConversationState,
|
||||
insertMessage,
|
||||
insertRun,
|
||||
touchConversationState,
|
||||
@@ -124,17 +123,56 @@ 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
|
||||
|
||||
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;
|
||||
const prev = await getConversationState(tenantId, chat_id);
|
||||
mark("after_getConversationState");
|
||||
mark("after_touchConversationState");
|
||||
const isStale =
|
||||
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({
|
||||
tenant_id: tenantId,
|
||||
wa_chat_id: chat_id,
|
||||
@@ -158,7 +196,6 @@ export async function processMessage({
|
||||
const history = await getRecentMessagesForLLM({
|
||||
tenant_id: tenantId,
|
||||
wa_chat_id: chat_id,
|
||||
limit: 20,
|
||||
});
|
||||
const conversation_history = collapseAssistantMessages(history);
|
||||
mark("after_getRecentMessagesForLLM_for_plan");
|
||||
@@ -185,6 +222,26 @@ 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 isSimulated = provider === "sim" || meta?.source === "sim";
|
||||
@@ -397,8 +454,8 @@ export async function processMessage({
|
||||
run_id,
|
||||
end_to_end_ms,
|
||||
ms: {
|
||||
db_state_ms: msBetween("start", "after_getConversationState"),
|
||||
db_identity_ms: msBetween("after_getConversationState", "after_getExternalCustomerIdByChat"),
|
||||
db_state_ms: msBetween("start", "after_touchConversationState"),
|
||||
db_identity_ms: msBetween("after_touchConversationState", "after_getExternalCustomerIdByChat"),
|
||||
insert_in_ms: msBetween("after_getExternalCustomerIdByChat", "after_insertMessage_in"),
|
||||
history_for_plan_ms: msBetween("after_insertMessage_in", "after_getRecentMessagesForLLM_for_plan"),
|
||||
insert_run_ms: msBetween("before_insertRun", "after_insertRun"),
|
||||
|
||||
Reference in New Issue
Block a user