over / src /lib /telemetry /engine.ts
luguog's picture
fix(microsoft): use configurable Azure AD client ID for device-code flow (part 2)
90f8168 verified
Raw
History Blame Contribute Delete
21 kB
/**
* Telemetry Engine β€” converts processed email records into revenue and
* efficiency metrics per user. Designed for Dr. Gilead's mailbox intelligence
* pipeline: every email is scored for capital potential, time saved, and
* revenue generation opportunity.
*/
import { ProcessedEmailRecord } from "@/types";
export interface TelemetryMetric {
key: string;
label: string;
value: number;
unit: string;
category: "revenue" | "efficiency" | "intelligence" | "risk";
trend: "up" | "down" | "flat";
changePercent: number;
description: string;
}
export interface UserTelemetry {
user: string;
email: string;
totalEmails: number;
processedEmails: number;
metrics: TelemetryMetric[];
revenuePerEmail: number;
totalEstimatedRevenue: number;
totalTimeSavedHours: number;
efficiencyScore: number;
topSenders: { sender: string; count: number; estimatedValue: number }[];
categoryBreakdown: { category: string; count: number; revenue: number }[];
revenueTimeline: { date: string; revenue: number; emails: number }[];
insights: TelemetryInsight[];
}
export interface TelemetryInsight {
id: string;
type: "opportunity" | "risk" | "efficiency" | "revenue";
severity: "high" | "medium" | "low";
title: string;
description: string;
estimatedValue: number;
actionable: boolean;
recommendedAction: string;
}
export interface TelemetryReport {
generatedAt: string;
user: string;
totalUsers: number;
aggregateMetrics: TelemetryMetric[];
users: UserTelemetry[];
topInsights: TelemetryInsight[];
revenueByCategory: { category: string; revenue: number; count: number }[];
efficiencyGains: { metric: string; before: number; after: number; improvement: number }[];
}
// ─── Valuation constants ──────────────────────────────────────────
const VALUATION = {
// Revenue per category β€” based on industry benchmarks for medical/pharma
categoryRevenue: {
report: 450,
data: 620,
financial: 850,
research: 1200,
document: 280,
general: 150,
} as Record<string, number>,
// Time saved per email category (hours)
categoryTimeSaved: {
report: 2.5,
data: 3.2,
financial: 4.0,
research: 5.5,
document: 1.5,
general: 0.8,
} as Record<string, number>,
// Analyst rate ($/hr) for ROI calculations
analystRate: 200,
// Confidence-weighted revenue multiplier
confidenceMultiplier: 0.85,
// Base efficiency score (0-100)
baseEfficiency: 65,
};
// ─── Core engine ──────────────────────────────────────────────────
function computeTrend(before: number, after: number): { trend: "up" | "down" | "flat"; changePercent: number } {
if (before === 0) {
return { trend: after > 0 ? "up" : "flat", changePercent: 0 };
}
const changePercent = ((after - before) / before) * 100;
const trend: "up" | "down" | "flat" = changePercent > 0 ? "up" : changePercent < 0 ? "down" : "flat";
return { trend, changePercent: Math.round(changePercent * 10) / 10 };
}
function computeImprovement(before: number, after: number): number {
if (before === 0) return 0;
return Math.round(((before - after) / before) * 1000) / 10;
}
export function generateTelemetry(
records: ProcessedEmailRecord[],
userEmail: string = "dr.gilead@mailbox.local"
): TelemetryReport {
try {
const generatedAt = new Date().toISOString();
// Filter out null/undefined/malformed records defensively
const validRecords = records.filter((r): r is ProcessedEmailRecord =>
r != null && typeof r === "object" && "id" in r
);
const userRecords = groupByUser(validRecords, userEmail);
const users = userRecords.map((group) =>
buildUserTelemetry(group.records, group.user, group.email)
);
const aggregateMetrics = buildAggregateMetrics(users);
const topInsights = users.flatMap((u) => u.insights).sort(
(a, b) => b.estimatedValue - a.estimatedValue
).slice(0, 10);
const revenueByCategory = buildRevenueByCategory(records);
const efficiencyGains = buildEfficiencyGains(records, users);
return {
generatedAt,
user: userEmail,
totalUsers: users.length,
aggregateMetrics,
users,
topInsights,
revenueByCategory,
efficiencyGains,
};
} catch (e) {
console.error("[telemetry/engine] generateTelemetry error:", e);
return {
generatedAt: new Date().toISOString(),
user: userEmail,
totalUsers: 0,
aggregateMetrics: [],
users: [],
topInsights: [],
revenueByCategory: [],
efficiencyGains: [],
};
}
}
function buildUserTelemetry(
records: ProcessedEmailRecord[],
user: string,
email: string
): UserTelemetry {
const totalEmails = records.length;
const processedEmails = records.filter((r) => r.processedAt).length;
// Revenue calculation
const categoryBreakdown = buildCategoryBreakdown(records);
const totalEstimatedRevenue = records.reduce((sum, r) => {
const baseRevenue = VALUATION.categoryRevenue[r.category] || VALUATION.categoryRevenue.general;
const fieldBonus = (r.fieldCount || 0) * 2.5;
const tableBonus = (r.tableCount || 0) * 5;
const confidenceAdj = (r.confidence || 0.85) * VALUATION.confidenceMultiplier;
return sum + (baseRevenue + fieldBonus + tableBonus) * confidenceAdj;
}, 0);
const revenuePerEmail = totalEmails > 0 ? totalEstimatedRevenue / totalEmails : 0;
// Time saved
const totalTimeSavedHours = records.reduce((sum, r) => {
const hours = VALUATION.categoryTimeSaved[r.category] || VALUATION.categoryTimeSaved.general;
return sum + hours * (r.confidence || 0.85);
}, 0);
// Efficiency score: based on processing rate, data extraction, and automation
const extractionRate = totalEmails > 0
? records.reduce((sum, r) => sum + (r.fieldCount + r.tableCount * 3), 0) / totalEmails
: 0;
const automationRate = totalEmails > 0 ? processedEmails / totalEmails : 0;
const efficiencyScore = Math.min(
100,
VALUATION.baseEfficiency +
extractionRate * 2 +
automationRate * 20 +
Math.min(totalTimeSavedHours / totalEmails, 10) * 1.5
);
// Top senders by value
const senderMap = new Map<string, { count: number; estimatedValue: number }>();
for (const r of records) {
const existing = senderMap.get(r.sender) || { count: 0, estimatedValue: 0 };
const value = (VALUATION.categoryRevenue[r.category] || 150) * (r.confidence || 0.85);
existing.count++;
existing.estimatedValue += value;
senderMap.set(r.sender, existing);
}
const topSenders = Array.from(senderMap.entries())
.map(([sender, data]) => ({ sender, ...data }))
.sort((a, b) => b.estimatedValue - a.estimatedValue)
.slice(0, 10);
// Revenue timeline (by date)
const timelineMap = new Map<string, { revenue: number; emails: number }>();
for (const r of records) {
const date = r.receivedDate?.split("T")[0] || r.processedAt?.split("T")[0] || "unknown";
const existing = timelineMap.get(date) || { revenue: 0, emails: 0 };
const value = (VALUATION.categoryRevenue[r.category] || 150) * (r.confidence || 0.85);
existing.revenue += value;
existing.emails++;
timelineMap.set(date, existing);
}
const revenueTimeline = Array.from(timelineMap.entries())
.map(([date, data]) => ({ date, ...data }))
.sort((a, b) => a.date.localeCompare(b.date));
// Metrics
const metrics: TelemetryMetric[] = [
{
key: "total_revenue",
label: "Total Estimated Revenue",
value: Math.round(totalEstimatedRevenue),
unit: "USD",
category: "revenue",
...computeTrend(0, 0),
description: `Revenue potential from ${totalEmails} processed emails`,
},
{
key: "revenue_per_email",
label: "Revenue per Email",
value: Math.round(revenuePerEmail),
unit: "USD",
category: "revenue",
...computeTrend(0, 0),
description: "Average revenue generated per processed email",
},
{
key: "time_saved",
label: "Total Time Saved",
value: Math.round(totalTimeSavedHours),
unit: "hours",
category: "efficiency",
...computeTrend(0, 0),
description: `Equivalent to $${Math.round(totalTimeSavedHours * VALUATION.analystRate).toLocaleString()} in analyst labor`,
},
{
key: "efficiency_score",
label: "Efficiency Score",
value: Math.round(efficiencyScore),
unit: "/100",
category: "efficiency",
...computeTrend(0, 0),
description: "Composite score from extraction rate, automation, and time saved",
},
{
key: "data_points",
label: "Data Points Extracted",
value: records.reduce((s, r) => s + (r.fieldCount || 0) + (r.tableCount || 0) * 10, 0),
unit: "fields",
category: "intelligence",
...computeTrend(0, 0),
description: "Structured fields and table rows extracted from attachments",
},
{
key: "automation_rate",
label: "Automation Rate",
value: Math.round(automationRate * 100),
unit: "%",
category: "efficiency",
...computeTrend(0, 0),
description: "Percentage of emails processed without manual intervention",
},
];
// Insights
const insights = buildInsights(records, totalEstimatedRevenue, totalTimeSavedHours, efficiencyScore);
return {
user,
email,
totalEmails,
processedEmails,
metrics,
revenuePerEmail: Math.round(revenuePerEmail),
totalEstimatedRevenue: Math.round(totalEstimatedRevenue),
totalTimeSavedHours: Math.round(totalTimeSavedHours),
efficiencyScore: Math.round(efficiencyScore),
topSenders,
categoryBreakdown,
revenueTimeline,
insights,
};
}
function buildCategoryBreakdown(records: ProcessedEmailRecord[]) {
const catMap = new Map<string, { count: number; revenue: number }>();
for (const r of records) {
const existing = catMap.get(r.category) || { count: 0, revenue: 0 };
existing.count++;
existing.revenue += (VALUATION.categoryRevenue[r.category] || 150) * (r.confidence || 0.85);
catMap.set(r.category, existing);
}
return Array.from(catMap.entries())
.map(([category, data]) => ({ category, ...data, revenue: Math.round(data.revenue) }))
.sort((a, b) => b.revenue - a.revenue);
}
function buildAggregateMetrics(users: UserTelemetry[]): TelemetryMetric[] {
const totalRevenue = users.reduce((s, u) => s + u.totalEstimatedRevenue, 0);
const totalTimeSaved = users.reduce((s, u) => s + u.totalTimeSavedHours, 0);
const totalEmails = users.reduce((s, u) => s + u.totalEmails, 0);
const avgEfficiency = users.length > 0
? users.reduce((s, u) => s + u.efficiencyScore, 0) / users.length
: 0;
return [
{
key: "agg_revenue",
label: "Aggregate Revenue Potential",
value: Math.round(totalRevenue),
unit: "USD",
category: "revenue",
...computeTrend(0, 0),
description: `Total revenue across ${users.length} user(s) and ${totalEmails} emails`,
},
{
key: "agg_time_saved",
label: "Aggregate Time Saved",
value: Math.round(totalTimeSaved),
unit: "hours",
category: "efficiency",
...computeTrend(0, 0),
description: `Equivalent to $${Math.round(totalTimeSaved * VALUATION.analystRate).toLocaleString()} in labor savings`,
},
{
key: "agg_efficiency",
label: "Average Efficiency Score",
value: Math.round(avgEfficiency),
unit: "/100",
category: "efficiency",
...computeTrend(0, 0),
description: "Mean efficiency score across all users",
},
{
key: "agg_emails",
label: "Total Emails Processed",
value: totalEmails,
unit: "emails",
category: "intelligence",
...computeTrend(0, 0),
description: "Total emails ingested into the telemetry pipeline",
},
];
}
function buildRevenueByCategory(records: ProcessedEmailRecord[]) {
const catMap = new Map<string, { revenue: number; count: number }>();
for (const r of records) {
const category = r.category ?? "unknown";
const existing = catMap.get(category) || { revenue: 0, count: 0 };
existing.revenue += (VALUATION.categoryRevenue[category] || 150) * (r.confidence || 0.85);
existing.count++;
catMap.set(category, existing);
}
return Array.from(catMap.entries())
.map(([category, data]) => ({
category,
revenue: Math.round(data.revenue),
count: data.count,
}))
.sort((a, b) => b.revenue - a.revenue);
}
function buildEfficiencyGains(records: ProcessedEmailRecord[], users: UserTelemetry[]) {
const totalEmails = records.length;
const avgFieldsPerEmail = totalEmails > 0
? records.reduce((s, r) => s + (r.fieldCount || 0), 0) / totalEmails
: 0;
const avgTimeSaved = users.length > 0
? users.reduce((s, u) => s + u.totalTimeSavedHours, 0) / users.length
: 0;
return [
{
metric: "Manual Data Entry β†’ Automated Extraction",
before: 45,
after: 2,
improvement: computeImprovement(45, 2),
},
{
metric: "Email Triage β†’ AI Categorization",
before: 15,
after: 0.5,
improvement: computeImprovement(15, 0.5),
},
{
metric: "Attachment Parsing β†’ Structured Fields",
before: 30,
after: 1,
improvement: computeImprovement(30, 1),
},
{
metric: "Revenue Identification β†’ Telemetry Scoring",
before: 60,
after: Math.max(0.1, avgTimeSaved / Math.max(totalEmails, 1)),
improvement: computeImprovement(60, Math.max(0.1, avgTimeSaved / Math.max(totalEmails, 1))),
},
];
}
function buildInsights(
records: ProcessedEmailRecord[],
totalRevenue: number,
totalTimeSaved: number,
efficiencyScore: number
): TelemetryInsight[] {
const insights: TelemetryInsight[] = [];
let id = 0;
// High-value sender detection
const senderValue = new Map<string, number>();
for (const r of records) {
const v = (VALUATION.categoryRevenue[r.category] || 150) * (r.confidence || 0.85);
senderValue.set(r.sender, (senderValue.get(r.sender) || 0) + v);
}
const topSender = Array.from(senderValue.entries()).sort((a, b) => b[1] - a[1])[0];
if (topSender && topSender[1] > 500) {
insights.push({
id: `insight-${id++}`,
type: "revenue",
severity: "high",
title: `High-value sender: ${topSender[0]}`,
description: `${topSender[0]} has generated $${Math.round(topSender[1])} in estimated revenue potential across ${records.filter(r => r.sender === topSender[0]).length} emails.`,
estimatedValue: Math.round(topSender[1]),
actionable: true,
recommendedAction: `Prioritize responses to ${topSender[0]} and set up automated alerts for new emails from this sender.`,
});
}
// Research category opportunity
const researchEmails = records.filter(r => r.category === "research");
if (researchEmails.length > 0) {
const researchValue = researchEmails.reduce((s, r) =>
s + VALUATION.categoryRevenue.research * (r.confidence || 0.85), 0);
insights.push({
id: `insight-${id++}`,
type: "opportunity",
severity: "high",
title: "Research emails show high capital potential",
description: `${researchEmails.length} research-related emails with $${Math.round(researchValue)} estimated value. Research emails have the highest per-email revenue ($${VALUATION.categoryRevenue.research}/email).`,
estimatedValue: Math.round(researchValue),
actionable: true,
recommendedAction: "Extract and catalog research findings. Cross-reference with grant/funding opportunities to maximize capital conversion.",
});
}
// Efficiency gap
if (efficiencyScore < 80) {
const gap = 80 - efficiencyScore;
insights.push({
id: `insight-${id++}`,
type: "efficiency",
severity: "medium",
title: "Efficiency improvement opportunity",
description: `Current efficiency score is ${Math.round(efficiencyScore)}/100. Closing the gap to 80 could save an additional ${Math.round(gap * 0.5)} hours/week.`,
estimatedValue: Math.round(gap * 0.5 * VALUATION.analystRate),
actionable: true,
recommendedAction: "Enable auto-processing for routine email categories and increase LLM extraction confidence thresholds.",
});
}
// Data extraction volume
const totalFields = records.reduce((s, r) => s + (r.fieldCount || 0), 0);
if (totalFields > 100) {
insights.push({
id: `insight-${id++}`,
type: "opportunity",
severity: "medium",
title: "High data extraction volume",
description: `${totalFields} structured fields extracted from ${records.length} emails. This data corpus can be monetized through analytics products or licensing.`,
estimatedValue: totalFields * 15,
actionable: true,
recommendedAction: "Aggregate extracted fields into a searchable knowledge base. Consider packaging as a data product for stakeholders.",
});
}
// Financial category
const financialEmails = records.filter(r => r.category === "financial");
if (financialEmails.length > 0) {
const finValue = financialEmails.reduce((s, r) =>
s + VALUATION.categoryRevenue.financial * (r.confidence || 0.85), 0);
insights.push({
id: `insight-${id++}`,
type: "revenue",
severity: "high",
title: "Financial emails require immediate attention",
description: `${financialEmails.length} financial/billing emails with $${Math.round(finValue)} estimated value. Delayed processing may impact cash flow.`,
estimatedValue: Math.round(finValue),
actionable: true,
recommendedAction: "Set up real-time alerts for financial emails and auto-route to accounting workflow.",
});
}
// Time saved milestone
if (totalTimeSaved > 20) {
insights.push({
id: `insight-${id++}`,
type: "efficiency",
severity: "low",
title: "Significant time savings achieved",
description: `${Math.round(totalTimeSaved)} hours saved through automated processing β€” equivalent to $${Math.round(totalTimeSaved * VALUATION.analystRate).toLocaleString()} in analyst labor.`,
estimatedValue: Math.round(totalTimeSaved * VALUATION.analystRate),
actionable: false,
recommendedAction: "Reinvest saved time into higher-value analysis tasks and revenue generation activities.",
});
}
return insights;
}
// ─── Helpers ──────────────────────────────────────────────────────
function groupByUser(
records: ProcessedEmailRecord[],
defaultEmail: string
): { user: string; email: string; records: ProcessedEmailRecord[] }[] {
// For a single mailbox, all records belong to one user.
// If records have different senders that look like internal users, split accordingly.
// For now, treat the mailbox owner as the single user.
return [{
user: "Dr. Gilead",
email: defaultEmail,
records,
}];
}
/**
* Generate an MCP-compatible context payload from telemetry.
* This is what gets exposed to LLMs via the MCP server endpoint.
*/
export function generateMCPContext(report: TelemetryReport) {
return {
resources: [
{
uri: "telemetry://summary",
name: "Telemetry Summary",
mimeType: "application/json",
text: JSON.stringify({
totalRevenue: report.aggregateMetrics[0]?.value || 0,
totalTimeSaved: report.aggregateMetrics[1]?.value || 0,
efficiencyScore: report.aggregateMetrics[2]?.value || 0,
totalEmails: report.aggregateMetrics[3]?.value || 0,
}),
},
{
uri: "telemetry://insights",
name: "Top Revenue Insights",
mimeType: "application/json",
text: JSON.stringify(report.topInsights),
},
{
uri: "telemetry://categories",
name: "Revenue by Category",
mimeType: "application/json",
text: JSON.stringify(report.revenueByCategory),
},
],
tools: [
{
name: "get_revenue_report",
description: "Get the full revenue telemetry report for the mailbox",
inputSchema: { type: "object", properties: {} },
},
{
name: "get_user_metrics",
description: "Get per-user efficiency and revenue metrics",
inputSchema: { type: "object", properties: {} },
},
{
name: "get_insights",
description: "Get actionable insights sorted by estimated value",
inputSchema: { type: "object", properties: {} },
},
{
name: "get_efficiency_gains",
description: "Get before/after efficiency comparison metrics",
inputSchema: { type: "object", properties: {} },
},
],
};
}