badges on the right, evolution api sender

This commit is contained in:
Lucas Tettamanti
2026-01-26 01:21:08 -03:00
parent e85afab3e6
commit 53293ce9b3
13 changed files with 422 additions and 51 deletions

View File

@@ -29,12 +29,16 @@ class ConversationInspector extends HTMLElement {
.item.in { background:#0f1520; border-color:#2a3a55; }
.item.out { background:#111b2a; border-color:#2a3a55; }
.item.active { outline:2px solid #1f6feb; box-shadow: 0 0 0 2px rgba(31,111,235,.25); }
.kv { display:grid; grid-template-columns:70px 1fr; gap:6px 10px; }
.k { color:#8aa0b5; font-size:11px; letter-spacing:.4px; text-transform:uppercase; }
.v { font-size:12px; color:#e7eef7; }
.chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; }
.chip { display:inline-flex; align-items:center; gap:6px; padding:2px 6px; border-radius:999px; background:#1d2a3a; border:1px solid #243247; font-size:11px; color:#8aa0b5; }
.cart { margin-top:6px; font-size:11px; color:#c7d8ee; }
.item-row { display:flex; gap:8px; }
.item-left { flex:1; min-width:0; }
.item-right { display:flex; flex-direction:column; gap:4px; align-items:flex-end; justify-content:flex-start; min-width:60px; }
.kv { display:grid; grid-template-columns:55px 1fr; gap:4px 6px; }
.k { color:#8aa0b5; font-size:10px; letter-spacing:.3px; text-transform:uppercase; }
.v { font-size:11px; color:#e7eef7; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.chips { display:flex; flex-direction:column; gap:3px; align-items:flex-end; }
.chip { display:inline-flex; align-items:center; gap:3px; padding:2px 5px; border-radius:999px; background:#1d2a3a; border:1px solid #243247; font-size:9px; color:#8aa0b5; white-space:nowrap; }
.chip .dot { flex-shrink:0; }
.cart { margin-top:4px; font-size:10px; color:#c7d8ee; line-height:1.3; }
.tool { margin-top:6px; font-size:11px; color:#8aa0b5; }
.dot { width:8px; height:8px; border-radius:50%; }
.ok { background:#2ecc71; } .warn { background:#f1c40f; } .err { background:#e74c3c; }
@@ -216,12 +220,26 @@ class ConversationInspector extends HTMLElement {
toolSummary(tools = []) {
return tools.map((t) => ({
type: t.type || t.name || "tool",
type: this.formatToolName(t.type || t.name || "tool"),
ok: t.ok !== false,
error: t.error || null,
}));
}
formatToolName(name) {
// Nombres cortos para tools comunes
const shortNames = {
"ensure_woo_customer": "woo customer",
"create_order": "create order",
"update_order": "update order",
"send_payment_link": "payment link",
"request_human_takeover": "human takeover",
"add_to_cart": "add to cart",
"human_response_sent": "human response",
};
return shortNames[name] || name.replace(/_/g, " ");
}
render() {
const metaEl = this.shadowRoot.getElementById("meta");
const countEl = this.shadowRoot.getElementById("count");
@@ -269,24 +287,30 @@ class ConversationInspector extends HTMLElement {
: "NLU ok";
el.innerHTML = `
<div class="kv">
<div class="k">${dir === "in" ? "IN" : "OUT"}</div>
<div class="v">${new Date(msg.ts).toLocaleString()}</div>
<div class="k">STATE</div>
<div class="v">${dir === "out" ? nextState : prevState}</div>
<div class="k">INTENT</div>
<div class="v">${dir === "out" ? intent : "—"}</div>
<div class="k">NLU</div>
<div class="v">${dir === "out" && llmMeta ? llmNote : "—"}</div>
</div>
<div class="cart"><strong>Carrito:</strong> ${dir === "out" ? this.formatOrder(basket, pendingItems, order) : "—"}</div>
<div class="chips">
${tools
.map(
(t) =>
`<span class="chip"><span class="dot ${t.ok ? "ok" : "err"}"></span>${t.type}</span>`
)
.join("")}
<div class="item-row">
<div class="item-left">
<div class="kv">
<div class="k">${dir === "in" ? "IN" : "OUT"}</div>
<div class="v">${new Date(msg.ts).toLocaleString()}</div>
<div class="k">STATE</div>
<div class="v">${dir === "out" ? nextState : prevState}</div>
<div class="k">INTENT</div>
<div class="v">${dir === "out" ? intent : "—"}</div>
<div class="k">NLU</div>
<div class="v">${dir === "out" && llmMeta ? llmNote : "—"}</div>
</div>
<div class="cart"><strong>Carrito:</strong> ${dir === "out" ? this.formatOrder(basket, pendingItems, order) : "—"}</div>
</div>
<div class="item-right">
<div class="chips">
${tools
.map(
(t) =>
`<span class="chip"><span class="dot ${t.ok ? "ok" : "err"}"></span>${t.type}</span>`
)
.join("")}
</div>
</div>
</div>
`;
@@ -397,18 +421,24 @@ class ConversationInspector extends HTMLElement {
el.dataset.messageId = msg.message_id;
el.innerHTML = `
<div class="kv">
<div class="k">IN</div>
<div class="v">${new Date(msg.ts).toLocaleString()}</div>
<div class="k">STATE</div>
<div class="v"></div>
<div class="k">INTENT</div>
<div class="v">—</div>
<div class="k">NLU</div>
<div class="v">procesando...</div>
<div class="item-row">
<div class="item-left">
<div class="kv">
<div class="k">IN</div>
<div class="v">${new Date(msg.ts).toLocaleString()}</div>
<div class="k">STATE</div>
<div class="v">—</div>
<div class="k">INTENT</div>
<div class="v"></div>
<div class="k">NLU</div>
<div class="v">procesando...</div>
</div>
<div class="cart"><strong>Carrito:</strong> —</div>
</div>
<div class="item-right">
<div class="chips"></div>
</div>
</div>
<div class="cart"><strong>Carrito:</strong> —</div>
<div class="chips"></div>
`;
list.appendChild(el);