removed the voice agent

This commit is contained in:
2026-09-02 09:23:53 +05:30
parent 8ae5e7ebb9
commit e94a483cfa
5 changed files with 327 additions and 9 deletions
+69
View File
@@ -0,0 +1,69 @@
/* How far do the agent's numbers drift from the CRM dashboard?
The dashboard resolves a lead's stage by looking up `leadstages` and taking
the furthest stage across pipelines; the CRM's own code comments say
`Lead.current_stage` is "stale and never written". The agent's lead tools
read that stale field, so this measures the resulting gap.
*/
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
import { connectMongo } from '../src/data/mongo.js';
import { Lead } from '../src/data/models/index.js';
dotenv.config();
const CRM = process.env.CRM_PUBLIC_URL || 'https://crm.wele.in';
const token = jwt.sign({ id: '6a00cefe524bebd27037a968' }, process.env.CRM_JWT_SECRET, { expiresIn: '15m' });
await connectMongo();
// ── what the AGENT currently reports (stale field) ──────────────────────────
const agentStages = await Lead.aggregate([
{ $group: { _id: '$current_stage', n: { $sum: 1 } } },
{ $sort: { n: -1 } },
]);
const agent = Object.fromEntries(agentStages.map((r) => [r._id || 'unset', r.n]));
const agentTotal = agentStages.reduce((s, r) => s + r.n, 0);
// ── what the DASHBOARD reports (leadstages lookup, workshop excluded) ───────
// parseRange takes from/to as YYYY-MM-DD in IST and DEFAULTS TO TODAY — a
// missing range silently returns one day, which is the first trap here.
const today = new Date(Date.now() + 5.5 * 3600e3).toISOString().slice(0, 10);
const res = await fetch(`${CRM}/api/dashboard/leads?from=2020-01-01&to=${today}`, {
headers: { Authorization: `Bearer ${token}` },
signal: AbortSignal.timeout(60000),
});
if (!res.ok) {
console.log(`dashboard call failed: ${res.status} ${(await res.text()).slice(0, 200)}`);
process.exit(1);
}
const dash = await res.json();
console.log('=== DASHBOARD response shape ===');
console.log(' ', Object.keys(dash).join(', '));
const d = dash.data ?? dash;
console.log(' data keys:', Object.keys(d).join(', '));
console.log('\n=== TOTAL LEADS ===');
console.log(` agent (Lead collection) ${agentTotal}`);
console.log(` dashboard totalLeads ${d.totalLeads ?? d.total ?? '(not found)'}`);
console.log('\n=== STAGE DISTRIBUTION ===');
console.log(` ${'stage'.padEnd(24)} ${'agent'.padStart(7)} ${'dashboard'.padStart(10)} gap`);
console.log(` dashboard cards.total_leads ${d.cards?.total_leads}`);
console.log(` dashboard range ${d.range?.from} → ${d.range?.to}`);
const funnel = d.funnel || d.stages || {};
const dashStages = Array.isArray(funnel)
? Object.fromEntries(funnel.map((f) => [f._id || f.stage || f.name, f.count ?? f.total]))
: funnel;
const keys = [...new Set([...Object.keys(agent), ...Object.keys(dashStages)])];
for (const k of keys) {
const a = agent[k] ?? 0;
const b = dashStages[k] ?? 0;
const gap = b - a;
console.log(` ${String(k).padEnd(24)} ${String(a).padStart(7)} ${String(b).padStart(10)} ${gap === 0 ? '—' : (gap > 0 ? '+' : '') + gap}`);
}
console.log('\nRaw dashboard payload (first 900 chars) for field mapping:');
console.log(JSON.stringify(d).slice(0, 900));
process.exit(0);
+50
View File
@@ -0,0 +1,50 @@
/* Shape of every CRM dashboard endpoint, so the agent tools can be written
against what they actually return rather than against a guess. */
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';
dotenv.config();
const CRM = process.env.CRM_PUBLIC_URL || 'https://crm.wele.in';
const token = jwt.sign({ id: '6a00cefe524bebd27037a968' }, process.env.CRM_JWT_SECRET, { expiresIn: '15m' });
const today = new Date(Date.now() + 5.5 * 3600e3).toISOString().slice(0, 10);
const from = '2026-08-01';
const ENDPOINTS = [
'dashboard/leads',
'dashboard/marketing',
'dashboard/retargeting',
'dashboard/budget',
'dashboard/courses',
'dashboard/analytics',
'dashboard/meta-analytics',
];
const shape = (v, depth = 0) => {
if (Array.isArray(v)) return v.length ? `[${v.length} × ${shape(v[0], depth + 1)}]` : '[]';
if (v && typeof v === 'object') {
const keys = Object.keys(v);
if (depth >= 1) return `{${keys.slice(0, 8).join(', ')}${keys.length > 8 ? ', …' : ''}}`;
return `{\n${keys.map((k) => ` ${k}: ${shape(v[k], depth + 1)}`).join('\n')}\n }`;
}
return typeof v === 'string' ? `"${String(v).slice(0, 24)}"` : String(v);
};
for (const ep of ENDPOINTS) {
const url = `${CRM}/api/${ep}?from=${from}&to=${today}`;
try {
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` }, signal: AbortSignal.timeout(90000) });
const body = await res.text();
if (!res.ok) { console.log(`\n${ep} HTTP ${res.status} ${body.slice(0, 120)}`); continue; }
const j = JSON.parse(body);
const d = j.data ?? j;
console.log(`\n${'─'.repeat(70)}\n${ep} (${(body.length / 1024).toFixed(1)} kB)`);
console.log(` ${shape(d)}`);
// Headline numbers are what the assistant will most often be asked for.
if (d.cards) console.log(` cards → ${JSON.stringify(d.cards)}`);
if (d.totals) console.log(` totals → ${JSON.stringify(d.totals).slice(0, 300)}`);
if (d.summary) console.log(` summary → ${JSON.stringify(d.summary).slice(0, 300)}`);
} catch (e) {
console.log(`\n${ep} ERROR ${e.message.slice(0, 90)}`);
}
}
process.exit(0);
+29
View File
@@ -0,0 +1,29 @@
/* Does crm_dashboard return the dashboard's own numbers, across every section? */
import dotenv from 'dotenv';
dotenv.config();
process.env.CRM_API_BASE = process.env.CRM_PUBLIC_URL || 'https://crm.wele.in';
const { crmDashboard } = await import('../src/tools/crm/dashboard.tools.js');
const cfg = { configurable: { user: { id: '6a00cefe524bebd27037a968', name: 'Test', role: 'admin' }, runtime: { toolCallCount: 0 } } };
const CASES = [
['leads', 'all_time'], ['leads', 'this_month'], ['marketing', 'this_month'],
['budget', 'this_month'], ['courses', 'this_month'], ['analytics', 'last_7_days'],
['retargeting', 'this_month'], ['meta_analytics', 'this_month'],
];
let pass = 0;
for (const [section, range] of CASES) {
try {
const raw = await crmDashboard.invoke({ section, range }, cfg);
const r = typeof raw === 'string' ? JSON.parse(raw) : raw;
if (r.ok === false) { console.log(`FAIL ${section}/${range}: ${r.error}`); continue; }
const d = r.data ?? r;
const head = d.cards ? JSON.stringify(d.cards) : (d.overview ? JSON.stringify(d.overview).slice(0,150) : Object.keys(d).slice(0,6).join(','));
console.log(`PASS ${section.padEnd(15)} ${range.padEnd(12)} ${d.period?.from}→${d.period?.to}`);
console.log(` ${head.slice(0, 190)}`);
pass++;
} catch (e) { console.log(`FAIL ${section}/${range}: ${e.message.slice(0,120)}`); }
}
console.log(`\n${pass}/${CASES.length} sections working`);
process.exit(0);