untrap-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/api-keys.d.ts +53 -0
- package/dist/auth/api-keys.d.ts.map +1 -0
- package/dist/auth/api-keys.js +115 -0
- package/dist/auth/api-keys.js.map +1 -0
- package/dist/auth/rate-limiter.d.ts +6 -0
- package/dist/auth/rate-limiter.d.ts.map +1 -0
- package/dist/auth/rate-limiter.js +77 -0
- package/dist/auth/rate-limiter.js.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +62 -0
- package/dist/config.js.map +1 -0
- package/dist/db/__tests__/assert-msp-scoped.test.d.ts +2 -0
- package/dist/db/__tests__/assert-msp-scoped.test.d.ts.map +1 -0
- package/dist/db/__tests__/assert-msp-scoped.test.js +93 -0
- package/dist/db/__tests__/assert-msp-scoped.test.js.map +1 -0
- package/dist/db/azure-openai.d.ts +24 -0
- package/dist/db/azure-openai.d.ts.map +1 -0
- package/dist/db/azure-openai.js +45 -0
- package/dist/db/azure-openai.js.map +1 -0
- package/dist/db/gateway-client.d.ts +13 -0
- package/dist/db/gateway-client.d.ts.map +1 -0
- package/dist/db/gateway-client.js +210 -0
- package/dist/db/gateway-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/logging.d.ts +16 -0
- package/dist/middleware/logging.d.ts.map +1 -0
- package/dist/middleware/logging.js +52 -0
- package/dist/middleware/logging.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +466 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/ai/explain-budget.d.ts +10 -0
- package/dist/tools/ai/explain-budget.d.ts.map +1 -0
- package/dist/tools/ai/explain-budget.js +61 -0
- package/dist/tools/ai/explain-budget.js.map +1 -0
- package/dist/tools/ai/explain-experience.d.ts +6 -0
- package/dist/tools/ai/explain-experience.d.ts.map +1 -0
- package/dist/tools/ai/explain-experience.js +62 -0
- package/dist/tools/ai/explain-experience.js.map +1 -0
- package/dist/tools/ai/explain-sla.d.ts +9 -0
- package/dist/tools/ai/explain-sla.d.ts.map +1 -0
- package/dist/tools/ai/explain-sla.js +57 -0
- package/dist/tools/ai/explain-sla.js.map +1 -0
- package/dist/tools/ai/kb-search.d.ts +17 -0
- package/dist/tools/ai/kb-search.d.ts.map +1 -0
- package/dist/tools/ai/kb-search.js +28 -0
- package/dist/tools/ai/kb-search.js.map +1 -0
- package/dist/tools/ai/root-causes.d.ts +21 -0
- package/dist/tools/ai/root-causes.d.ts.map +1 -0
- package/dist/tools/ai/root-causes.js +54 -0
- package/dist/tools/ai/root-causes.js.map +1 -0
- package/dist/tools/ai/similar-tickets.d.ts +21 -0
- package/dist/tools/ai/similar-tickets.d.ts.map +1 -0
- package/dist/tools/ai/similar-tickets.js +47 -0
- package/dist/tools/ai/similar-tickets.js.map +1 -0
- package/dist/tools/ai/suggest-improvement.d.ts +6 -0
- package/dist/tools/ai/suggest-improvement.d.ts.map +1 -0
- package/dist/tools/ai/suggest-improvement.js +75 -0
- package/dist/tools/ai/suggest-improvement.js.map +1 -0
- package/dist/tools/analytics/backlog.d.ts +15 -0
- package/dist/tools/analytics/backlog.d.ts.map +1 -0
- package/dist/tools/analytics/backlog.js +41 -0
- package/dist/tools/analytics/backlog.js.map +1 -0
- package/dist/tools/analytics/billing.d.ts +15 -0
- package/dist/tools/analytics/billing.d.ts.map +1 -0
- package/dist/tools/analytics/billing.js +24 -0
- package/dist/tools/analytics/billing.js.map +1 -0
- package/dist/tools/analytics/client-experience.d.ts +32 -0
- package/dist/tools/analytics/client-experience.d.ts.map +1 -0
- package/dist/tools/analytics/client-experience.js +34 -0
- package/dist/tools/analytics/client-experience.js.map +1 -0
- package/dist/tools/analytics/client-health.d.ts +16 -0
- package/dist/tools/analytics/client-health.d.ts.map +1 -0
- package/dist/tools/analytics/client-health.js +21 -0
- package/dist/tools/analytics/client-health.js.map +1 -0
- package/dist/tools/analytics/disengaged.d.ts +5 -0
- package/dist/tools/analytics/disengaged.d.ts.map +1 -0
- package/dist/tools/analytics/disengaged.js +63 -0
- package/dist/tools/analytics/disengaged.js.map +1 -0
- package/dist/tools/analytics/patterns.d.ts +9 -0
- package/dist/tools/analytics/patterns.d.ts.map +1 -0
- package/dist/tools/analytics/patterns.js +11 -0
- package/dist/tools/analytics/patterns.js.map +1 -0
- package/dist/tools/analytics/qc-violations.d.ts +21 -0
- package/dist/tools/analytics/qc-violations.d.ts.map +1 -0
- package/dist/tools/analytics/qc-violations.js +55 -0
- package/dist/tools/analytics/qc-violations.js.map +1 -0
- package/dist/tools/analytics/sla-breach-tickets.d.ts +21 -0
- package/dist/tools/analytics/sla-breach-tickets.d.ts.map +1 -0
- package/dist/tools/analytics/sla-breach-tickets.js +72 -0
- package/dist/tools/analytics/sla-breach-tickets.js.map +1 -0
- package/dist/tools/analytics/sla-breaches.d.ts +17 -0
- package/dist/tools/analytics/sla-breaches.d.ts.map +1 -0
- package/dist/tools/analytics/sla-breaches.js +60 -0
- package/dist/tools/analytics/sla-breaches.js.map +1 -0
- package/dist/tools/analytics/technician-perf.d.ts +10 -0
- package/dist/tools/analytics/technician-perf.d.ts.map +1 -0
- package/dist/tools/analytics/technician-perf.js +14 -0
- package/dist/tools/analytics/technician-perf.js.map +1 -0
- package/dist/tools/cfo/agreement-analysis.d.ts +12 -0
- package/dist/tools/cfo/agreement-analysis.d.ts.map +1 -0
- package/dist/tools/cfo/agreement-analysis.js +59 -0
- package/dist/tools/cfo/agreement-analysis.js.map +1 -0
- package/dist/tools/cfo/client-profitability.d.ts +25 -0
- package/dist/tools/cfo/client-profitability.d.ts.map +1 -0
- package/dist/tools/cfo/client-profitability.js +73 -0
- package/dist/tools/cfo/client-profitability.js.map +1 -0
- package/dist/tools/cfo/financial-overview.d.ts +34 -0
- package/dist/tools/cfo/financial-overview.d.ts.map +1 -0
- package/dist/tools/cfo/financial-overview.js +67 -0
- package/dist/tools/cfo/financial-overview.js.map +1 -0
- package/dist/tools/cfo/labor-cost-trend.d.ts +14 -0
- package/dist/tools/cfo/labor-cost-trend.d.ts.map +1 -0
- package/dist/tools/cfo/labor-cost-trend.js +65 -0
- package/dist/tools/cfo/labor-cost-trend.js.map +1 -0
- package/dist/tools/cfo/revenue-leakage.d.ts +22 -0
- package/dist/tools/cfo/revenue-leakage.d.ts.map +1 -0
- package/dist/tools/cfo/revenue-leakage.js +67 -0
- package/dist/tools/cfo/revenue-leakage.js.map +1 -0
- package/dist/tools/cfo/service-cost-analysis.d.ts +15 -0
- package/dist/tools/cfo/service-cost-analysis.d.ts.map +1 -0
- package/dist/tools/cfo/service-cost-analysis.js +66 -0
- package/dist/tools/cfo/service-cost-analysis.js.map +1 -0
- package/dist/tools/cfo/technician-utilization.d.ts +26 -0
- package/dist/tools/cfo/technician-utilization.d.ts.map +1 -0
- package/dist/tools/cfo/technician-utilization.js +67 -0
- package/dist/tools/cfo/technician-utilization.js.map +1 -0
- package/dist/tools/composite/client-360.d.ts +28 -0
- package/dist/tools/composite/client-360.d.ts.map +1 -0
- package/dist/tools/composite/client-360.js +67 -0
- package/dist/tools/composite/client-360.js.map +1 -0
- package/dist/tools/composite/compare-periods.d.ts +31 -0
- package/dist/tools/composite/compare-periods.d.ts.map +1 -0
- package/dist/tools/composite/compare-periods.js +94 -0
- package/dist/tools/composite/compare-periods.js.map +1 -0
- package/dist/tools/composite/draft-email.d.ts +7 -0
- package/dist/tools/composite/draft-email.d.ts.map +1 -0
- package/dist/tools/composite/draft-email.js +54 -0
- package/dist/tools/composite/draft-email.js.map +1 -0
- package/dist/tools/composite/morning-briefing.d.ts +15 -0
- package/dist/tools/composite/morning-briefing.d.ts.map +1 -0
- package/dist/tools/composite/morning-briefing.js +119 -0
- package/dist/tools/composite/morning-briefing.js.map +1 -0
- package/dist/tools/composite/technician-360.d.ts +22 -0
- package/dist/tools/composite/technician-360.d.ts.map +1 -0
- package/dist/tools/composite/technician-360.js +55 -0
- package/dist/tools/composite/technician-360.js.map +1 -0
- package/dist/tools/composite/ticket-deep-dive.d.ts +24 -0
- package/dist/tools/composite/ticket-deep-dive.d.ts.map +1 -0
- package/dist/tools/composite/ticket-deep-dive.js +49 -0
- package/dist/tools/composite/ticket-deep-dive.js.map +1 -0
- package/dist/tools/config/msp-context.d.ts +26 -0
- package/dist/tools/config/msp-context.d.ts.map +1 -0
- package/dist/tools/config/msp-context.js +41 -0
- package/dist/tools/config/msp-context.js.map +1 -0
- package/dist/tools/qbr/client-detail.d.ts +26 -0
- package/dist/tools/qbr/client-detail.d.ts.map +1 -0
- package/dist/tools/qbr/client-detail.js +72 -0
- package/dist/tools/qbr/client-detail.js.map +1 -0
- package/dist/tools/qbr/client-health.d.ts +11 -0
- package/dist/tools/qbr/client-health.d.ts.map +1 -0
- package/dist/tools/qbr/client-health.js +48 -0
- package/dist/tools/qbr/client-health.js.map +1 -0
- package/dist/tools/qbr/executive-summary.d.ts +8 -0
- package/dist/tools/qbr/executive-summary.d.ts.map +1 -0
- package/dist/tools/qbr/executive-summary.js +83 -0
- package/dist/tools/qbr/executive-summary.js.map +1 -0
- package/dist/tools/qbr/financial-summary.d.ts +19 -0
- package/dist/tools/qbr/financial-summary.d.ts.map +1 -0
- package/dist/tools/qbr/financial-summary.js +64 -0
- package/dist/tools/qbr/financial-summary.js.map +1 -0
- package/dist/tools/qbr/recommendations.d.ts +7 -0
- package/dist/tools/qbr/recommendations.d.ts.map +1 -0
- package/dist/tools/qbr/recommendations.js +80 -0
- package/dist/tools/qbr/recommendations.js.map +1 -0
- package/dist/tools/qbr/sla-performance.d.ts +12 -0
- package/dist/tools/qbr/sla-performance.d.ts.map +1 -0
- package/dist/tools/qbr/sla-performance.js +68 -0
- package/dist/tools/qbr/sla-performance.js.map +1 -0
- package/dist/tools/qbr/technician-scorecard.d.ts +12 -0
- package/dist/tools/qbr/technician-scorecard.d.ts.map +1 -0
- package/dist/tools/qbr/technician-scorecard.js +69 -0
- package/dist/tools/qbr/technician-scorecard.js.map +1 -0
- package/dist/tools/qbr/ticket-trends.d.ts +14 -0
- package/dist/tools/qbr/ticket-trends.d.ts.map +1 -0
- package/dist/tools/qbr/ticket-trends.js +57 -0
- package/dist/tools/qbr/ticket-trends.js.map +1 -0
- package/dist/tools/qbr/top-issues.d.ts +12 -0
- package/dist/tools/qbr/top-issues.d.ts.map +1 -0
- package/dist/tools/qbr/top-issues.js +39 -0
- package/dist/tools/qbr/top-issues.js.map +1 -0
- package/dist/tools/query/data-query.d.ts +24 -0
- package/dist/tools/query/data-query.d.ts.map +1 -0
- package/dist/tools/query/data-query.js +160 -0
- package/dist/tools/query/data-query.js.map +1 -0
- package/dist/types/database.d.ts +137 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/database.js +3 -0
- package/dist/types/database.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
import { chatCompletion } from "../../db/azure-openai.js";
|
|
3
|
+
export async function explainExperienceScore(mspId, params) {
|
|
4
|
+
const [metrics, sentiment, slaBreaches] = await Promise.all([
|
|
5
|
+
queryRLS(`SELECT company_name, ticket_count, avg_response_minutes, avg_resolution_minutes,
|
|
6
|
+
avg_sentiment_score, health_score, total_cost, sla_breach_count
|
|
7
|
+
FROM analytics.client_experience_chat_mv
|
|
8
|
+
WHERE msp_id = $1 AND LOWER(company_name) = LOWER($2)
|
|
9
|
+
AND period_start >= CURRENT_DATE - INTERVAL '90 days'
|
|
10
|
+
ORDER BY period_start DESC
|
|
11
|
+
LIMIT 1`, [mspId, params.clientName], mspId),
|
|
12
|
+
queryRLS(`SELECT AVG(sentiment_score)::numeric as avg_sentiment,
|
|
13
|
+
COUNT(*) FILTER (WHERE sentiment_score < -0.3)::int as negative_notes,
|
|
14
|
+
COUNT(*)::int as total_notes
|
|
15
|
+
FROM ticket_notes_sentiment tns
|
|
16
|
+
JOIN ticket_lifecycle tl ON tl.msp_id = tns.msp_id AND tl.ticket_id = tns.ticket_id
|
|
17
|
+
WHERE tns.msp_id = $1 AND LOWER(tl.company_name) = LOWER($2)
|
|
18
|
+
AND tl.responded_date >= CURRENT_DATE - INTERVAL '90 days'`, [mspId, params.clientName], mspId),
|
|
19
|
+
queryRLS(`SELECT COUNT(*)::int as breach_count,
|
|
20
|
+
AVG(resolution_minutes)::numeric as avg_breach_resolution_min
|
|
21
|
+
FROM ticket_lifecycle
|
|
22
|
+
WHERE msp_id = $1 AND LOWER(company_name) = LOWER($2)
|
|
23
|
+
AND sla_status = 'breached'
|
|
24
|
+
AND responded_date >= CURRENT_DATE - INTERVAL '90 days'`, [mspId, params.clientName], mspId),
|
|
25
|
+
]);
|
|
26
|
+
if (metrics.length === 0) {
|
|
27
|
+
return { found: false, message: `No data found for client "${params.clientName}"` };
|
|
28
|
+
}
|
|
29
|
+
const m = metrics[0];
|
|
30
|
+
const s = sentiment[0] ?? {};
|
|
31
|
+
const b = slaBreaches[0] ?? {};
|
|
32
|
+
const result = await chatCompletion({
|
|
33
|
+
messages: [
|
|
34
|
+
{
|
|
35
|
+
role: "system",
|
|
36
|
+
content: `You are an MSP client experience analyst. Break down what's driving a client's experience score. Return JSON with "score" (0-100), "breakdown" (object with sentiment, documentation, resolution_time, response_speed, consistency each 0-100), and "explanation" (2-3 paragraph narrative). Only return valid JSON.`,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
role: "user",
|
|
40
|
+
content: `Client: ${params.clientName}
|
|
41
|
+
Health score: ${m.health_score}
|
|
42
|
+
Tickets (90d): ${m.ticket_count}
|
|
43
|
+
Avg response: ${m.avg_response_minutes} min
|
|
44
|
+
Avg resolution: ${m.avg_resolution_minutes} min
|
|
45
|
+
Avg sentiment: ${s.avg_sentiment} (${s.negative_notes} negative out of ${s.total_notes} notes)
|
|
46
|
+
SLA breaches: ${b.breach_count} (avg ${b.avg_breach_resolution_min} min to resolve)
|
|
47
|
+
Total cost: $${m.total_cost}
|
|
48
|
+
|
|
49
|
+
What's driving this client's experience score? Break it down.`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
maxTokens: 600,
|
|
53
|
+
temperature: 0.6,
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
return { found: true, ...JSON.parse(result.content) };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { found: true, score: m.health_score, explanation: result.content };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=explain-experience.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-experience.js","sourceRoot":"","sources":["../../../src/tools/ai/explain-experience.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAM1D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,KAAa,EACb,MAAwB;IAExB,MAAM,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1D,QAAQ,CACN;;;;;;eAMS,EACT,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAC1B,KAAK,CACN;QACD,QAAQ,CACN;;;;;;oEAM8D,EAC9D,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAC1B,KAAK,CACN;QACD,QAAQ,CACN;;;;;iEAK2D,EAC3D,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,EAC1B,KAAK,CACN;KACF,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,6BAA6B,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;IACtF,CAAC;IAED,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,sTAAsT;aAChU;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,WAAW,MAAM,CAAC,UAAU;gBAC7B,CAAC,CAAC,YAAY;iBACb,CAAC,CAAC,YAAY;gBACf,CAAC,CAAC,oBAAoB;kBACpB,CAAC,CAAC,sBAAsB;iBACzB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,cAAc,oBAAoB,CAAC,CAAC,WAAW;gBACtE,CAAC,CAAC,YAAY,SAAS,CAAC,CAAC,yBAAyB;eACnD,CAAC,CAAC,UAAU;;8DAEmC;aACvD;SACF;QACD,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAC7E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-sla.d.ts","sourceRoot":"","sources":["../../../src/tools/ai/explain-sla.ts"],"names":[],"mappings":"AAGA,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,gBAAgB;;;GAiEzB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
import { chatCompletion } from "../../db/azure-openai.js";
|
|
3
|
+
export async function explainSlaVariance(mspId, params) {
|
|
4
|
+
const [ticket, timeEntries] = await Promise.all([
|
|
5
|
+
queryRLS(`SELECT ticket_id, summary, priority_name, owner_name, company_name,
|
|
6
|
+
board_name, status, response_minutes, resolution_minutes,
|
|
7
|
+
sla_status, entered_date::text, responded_date::text, closed_date::text
|
|
8
|
+
FROM ticket_lifecycle
|
|
9
|
+
WHERE msp_id = $1 AND ticket_id = $2`, [mspId, params.ticketId], mspId),
|
|
10
|
+
queryRLS(`SELECT member_name, actual_hours, date_worked::text, notes_text
|
|
11
|
+
FROM time_entries
|
|
12
|
+
WHERE msp_id = $1 AND ticket_id = $2
|
|
13
|
+
ORDER BY date_worked ASC`, [mspId, params.ticketId], mspId),
|
|
14
|
+
]);
|
|
15
|
+
if (ticket.length === 0) {
|
|
16
|
+
return { explanation: "Ticket not found.", factors: [] };
|
|
17
|
+
}
|
|
18
|
+
const t = ticket[0];
|
|
19
|
+
const timeLog = timeEntries
|
|
20
|
+
.map((te) => `${te.date_worked}: ${te.member_name} (${te.actual_hours}h) - ${te.notes_text?.substring(0, 100) || "no notes"}`)
|
|
21
|
+
.join("\n");
|
|
22
|
+
const result = await chatCompletion({
|
|
23
|
+
messages: [
|
|
24
|
+
{
|
|
25
|
+
role: "system",
|
|
26
|
+
content: `You are an MSP SLA analyst. Explain why a ticket missed its SLA target. Return a JSON object with "explanation" (2-3 sentences) and "factors" (array of strings naming specific delay causes). Only return valid JSON.`,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
role: "user",
|
|
30
|
+
content: `Ticket #${t.ticket_id}: "${t.summary}"
|
|
31
|
+
Priority: ${t.priority_name}, Status: ${t.status}, SLA: ${t.sla_status}
|
|
32
|
+
Client: ${t.company_name}, Board: ${t.board_name}
|
|
33
|
+
Entered: ${t.entered_date}, Responded: ${t.responded_date}, Closed: ${t.closed_date}
|
|
34
|
+
Response time: ${t.response_minutes} min, Resolution time: ${t.resolution_minutes} min
|
|
35
|
+
Technician: ${t.owner_name}
|
|
36
|
+
|
|
37
|
+
Time log:
|
|
38
|
+
${timeLog || "No time entries"}
|
|
39
|
+
|
|
40
|
+
Why did this ticket miss SLA?`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
maxTokens: 400,
|
|
44
|
+
temperature: 0.5,
|
|
45
|
+
});
|
|
46
|
+
try {
|
|
47
|
+
const parsed = JSON.parse(result.content);
|
|
48
|
+
return {
|
|
49
|
+
explanation: parsed.explanation || result.content,
|
|
50
|
+
factors: parsed.factors || [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return { explanation: result.content, factors: [] };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=explain-sla.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain-sla.js","sourceRoot":"","sources":["../../../src/tools/ai/explain-sla.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAM1D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,MAAwB;IAExB,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC9C,QAAQ,CACN;;;;4CAIsC,EACtC,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,EACxB,KAAK,CACN;QACD,QAAQ,CACN;;;gCAG0B,EAC1B,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,EACxB,KAAK,CACN;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,WAAW;SACxB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,KAAK,EAAE,CAAC,WAAW,KAAK,EAAE,CAAC,YAAY,QAAS,EAAE,CAAC,UAAqB,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;SACzI,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,wNAAwN;aAClO;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,CAAC,OAAO;YAC1C,CAAC,CAAC,aAAa,aAAa,CAAC,CAAC,MAAM,UAAU,CAAC,CAAC,UAAU;UAC5D,CAAC,CAAC,YAAY,YAAY,CAAC,CAAC,UAAU;WACrC,CAAC,CAAC,YAAY,gBAAgB,CAAC,CAAC,cAAc,aAAa,CAAC,CAAC,WAAW;iBAClE,CAAC,CAAC,gBAAgB,0BAA0B,CAAC,CAAC,kBAAkB;cACnE,CAAC,CAAC,UAAU;;;EAGxB,OAAO,IAAI,iBAAiB;;8BAEA;aACvB;SACF;QACD,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO;YACL,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,OAAO;YACjD,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;SAC9B,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface KBSearchParams {
|
|
2
|
+
query: string;
|
|
3
|
+
}
|
|
4
|
+
export declare function searchKnowledgeBase(mspId: string, params: KBSearchParams): Promise<{
|
|
5
|
+
query: string;
|
|
6
|
+
results_count: number;
|
|
7
|
+
articles: {
|
|
8
|
+
id: unknown;
|
|
9
|
+
title: unknown;
|
|
10
|
+
content: string;
|
|
11
|
+
keywords: unknown;
|
|
12
|
+
source_tickets: unknown;
|
|
13
|
+
updated_at: unknown;
|
|
14
|
+
}[];
|
|
15
|
+
}>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=kb-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kb-search.d.ts","sourceRoot":"","sources":["../../../src/tools/ai/kb-search.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,cAAc;;;;;;;;;;;GA+BvB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
export async function searchKnowledgeBase(mspId, params) {
|
|
3
|
+
// Search by keyword match across title, content, and keywords
|
|
4
|
+
const articles = await queryRLS(`SELECT id, title, content_md, keywords, source_ticket_ids,
|
|
5
|
+
created_at::text, updated_at::text
|
|
6
|
+
FROM kb_articles
|
|
7
|
+
WHERE msp_id = $1
|
|
8
|
+
AND (
|
|
9
|
+
LOWER(title) LIKE '%' || LOWER($2) || '%'
|
|
10
|
+
OR LOWER(content_md) LIKE '%' || LOWER($2) || '%'
|
|
11
|
+
OR LOWER(keywords::text) LIKE '%' || LOWER($2) || '%'
|
|
12
|
+
)
|
|
13
|
+
ORDER BY updated_at DESC
|
|
14
|
+
LIMIT 10`, [mspId, params.query], mspId);
|
|
15
|
+
return {
|
|
16
|
+
query: params.query,
|
|
17
|
+
results_count: articles.length,
|
|
18
|
+
articles: articles.map((a) => ({
|
|
19
|
+
id: a.id,
|
|
20
|
+
title: a.title,
|
|
21
|
+
content: a.content_md?.substring(0, 500),
|
|
22
|
+
keywords: a.keywords,
|
|
23
|
+
source_tickets: a.source_ticket_ids,
|
|
24
|
+
updated_at: a.updated_at,
|
|
25
|
+
})),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=kb-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kb-search.js","sourceRoot":"","sources":["../../../src/tools/ai/kb-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAMtD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAAa,EACb,MAAsB;IAEtB,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAC7B;;;;;;;;;;cAUU,EACV,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EACrB,KAAK,CACN,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,aAAa,EAAE,QAAQ,CAAC,MAAM;QAC9B,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,OAAO,EAAG,CAAC,CAAC,UAAqB,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;YACpD,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,cAAc,EAAE,CAAC,CAAC,iBAAiB;YACnC,UAAU,EAAE,CAAC,CAAC,UAAU;SACzB,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface RootCauseParams {
|
|
2
|
+
fromDate?: string;
|
|
3
|
+
toDate?: string;
|
|
4
|
+
category?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function analyzeRootCauses(mspId: string, params: RootCauseParams): Promise<{
|
|
7
|
+
breakdown: never[];
|
|
8
|
+
ai_analysis: string;
|
|
9
|
+
period?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
breakdown: {
|
|
12
|
+
percentage: number;
|
|
13
|
+
}[];
|
|
14
|
+
period: {
|
|
15
|
+
from: string;
|
|
16
|
+
to: string;
|
|
17
|
+
};
|
|
18
|
+
ai_analysis: string;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=root-causes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-causes.d.ts","sourceRoot":"","sources":["../../../src/tools/ai/root-causes.ts"],"names":[],"mappings":"AAGA,UAAU,eAAe;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,eAAe;;;;;;;;;;;;;GA8DxB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
import { chatCompletion } from "../../db/azure-openai.js";
|
|
3
|
+
export async function analyzeRootCauses(mspId, params) {
|
|
4
|
+
const fromDate = params.fromDate ?? new Date(Date.now() - 90 * 86400000).toISOString().split("T")[0];
|
|
5
|
+
const toDate = params.toDate ?? new Date().toISOString().split("T")[0];
|
|
6
|
+
let categoryFilter = "";
|
|
7
|
+
const queryParams = [mspId];
|
|
8
|
+
if (params.category) {
|
|
9
|
+
categoryFilter = ` AND LOWER(rc.root_cause_category) = LOWER($2)`;
|
|
10
|
+
queryParams.push(params.category);
|
|
11
|
+
}
|
|
12
|
+
const rawBreakdown = await queryRLS(`SELECT rc.root_cause_category as category,
|
|
13
|
+
COUNT(*)::int as count
|
|
14
|
+
FROM root_cause_ticket_classifier rc
|
|
15
|
+
WHERE rc.msp_id = $1
|
|
16
|
+
AND rc.root_cause_category IS NOT NULL
|
|
17
|
+
${categoryFilter}
|
|
18
|
+
GROUP BY rc.root_cause_category
|
|
19
|
+
ORDER BY count DESC
|
|
20
|
+
LIMIT 15`, queryParams, mspId);
|
|
21
|
+
const total = rawBreakdown.reduce((sum, r) => sum + Number(r.count), 0);
|
|
22
|
+
const breakdown = rawBreakdown.map((r) => ({
|
|
23
|
+
...r,
|
|
24
|
+
percentage: total > 0 ? Math.round((Number(r.count) / total) * 1000) / 10 : 0,
|
|
25
|
+
}));
|
|
26
|
+
if (breakdown.length === 0) {
|
|
27
|
+
return { breakdown: [], ai_analysis: "No root cause data available for this period." };
|
|
28
|
+
}
|
|
29
|
+
// Get AI analysis of the top categories
|
|
30
|
+
const topCategories = breakdown
|
|
31
|
+
.slice(0, 5)
|
|
32
|
+
.map((b) => `${b.category}: ${b.count} tickets (${b.percentage}%)`)
|
|
33
|
+
.join("\n");
|
|
34
|
+
const result = await chatCompletion({
|
|
35
|
+
messages: [
|
|
36
|
+
{
|
|
37
|
+
role: "system",
|
|
38
|
+
content: `You are an MSP operations consultant. Analyze the root cause breakdown and provide actionable recommendations. For each top category: explain what's likely causing it, the business impact, and one specific action to reduce it. Keep it under 200 words total.`,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
role: "user",
|
|
42
|
+
content: `Root cause breakdown (${fromDate} to ${toDate}):\n${topCategories}\n\nAnalyze these patterns and recommend actions.`,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
maxTokens: 400,
|
|
46
|
+
temperature: 0.6,
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
breakdown,
|
|
50
|
+
period: { from: fromDate, to: toDate },
|
|
51
|
+
ai_analysis: result.content,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=root-causes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"root-causes.js","sourceRoot":"","sources":["../../../src/tools/ai/root-causes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAQ1D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,MAAuB;IAEvB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvE,IAAI,cAAc,GAAG,EAAE,CAAC;IACxB,MAAM,WAAW,GAAc,CAAC,KAAK,CAAC,CAAC;IAEvC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,cAAc,GAAG,gDAAgD,CAAC;QAClE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CACjC;;;;;SAKK,cAAc;;;cAGT,EACV,WAAW,EACX,KAAK,CACN,CAAC;IACF,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzC,GAAG,CAAC;QACJ,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;KAC9E,CAAC,CAAC,CAAC;IAEJ,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,+CAA+C,EAAE,CAAC;IACzF,CAAC;IAED,wCAAwC;IACxC,MAAM,aAAa,GAAG,SAAS;SAC5B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAI,CAA6B,CAAC,QAAQ,KAAM,CAA6B,CAAC,KAAK,aAAa,CAAC,CAAC,UAAU,IAAI,CAAC;SAC5H,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,mQAAmQ;aAC7Q;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,yBAAyB,QAAQ,OAAO,MAAM,OAAO,aAAa,mDAAmD;aAC/H;SACF;QACD,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,OAAO;QACL,SAAS;QACT,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE;QACtC,WAAW,EAAE,MAAM,CAAC,OAAO;KAC5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface SimilarParams {
|
|
2
|
+
ticketId: number;
|
|
3
|
+
limit?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function findSimilarTickets(mspId: string, params: SimilarParams): Promise<{
|
|
6
|
+
found: boolean;
|
|
7
|
+
message: string;
|
|
8
|
+
source_ticket?: undefined;
|
|
9
|
+
source_summary?: undefined;
|
|
10
|
+
similar?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
found: boolean;
|
|
13
|
+
source_ticket: number;
|
|
14
|
+
source_summary: string;
|
|
15
|
+
similar: {
|
|
16
|
+
similarity_score: number;
|
|
17
|
+
}[];
|
|
18
|
+
message?: undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=similar-tickets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similar-tickets.d.ts","sourceRoot":"","sources":["../../../src/tools/ai/similar-tickets.ts"],"names":[],"mappings":"AAEA,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa;;;;;;;;;;;;;;GAyDtB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
export async function findSimilarTickets(mspId, params) {
|
|
3
|
+
const limit = params.limit ?? 5;
|
|
4
|
+
// Get the source ticket's embedding
|
|
5
|
+
const source = await queryRLS(`SELECT problem_embedding, ai_summary
|
|
6
|
+
FROM ticket_embeddings
|
|
7
|
+
WHERE msp_id = $1 AND ticket_id = $2`, [mspId, params.ticketId], mspId);
|
|
8
|
+
if (source.length === 0 || !source[0].problem_embedding) {
|
|
9
|
+
return {
|
|
10
|
+
found: false,
|
|
11
|
+
message: `No embedding found for ticket #${params.ticketId}. The ticket may not have been processed by the AI pipeline yet.`,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
// Find similar tickets using cosine similarity on problem_embedding
|
|
15
|
+
const similar = await queryRLS(`SELECT te.ticket_id,
|
|
16
|
+
1 - (te.problem_embedding <=> (
|
|
17
|
+
SELECT problem_embedding FROM ticket_embeddings
|
|
18
|
+
WHERE msp_id = $1 AND ticket_id = $2
|
|
19
|
+
)) as similarity_score,
|
|
20
|
+
te.ai_summary as problem_summary,
|
|
21
|
+
te.root_cause as root_cause,
|
|
22
|
+
te.ticket_classification as classification,
|
|
23
|
+
tl.company_name,
|
|
24
|
+
tl.owner_name,
|
|
25
|
+
tl.status,
|
|
26
|
+
tl.responded_date::text
|
|
27
|
+
FROM ticket_embeddings te
|
|
28
|
+
JOIN ticket_lifecycle tl ON tl.msp_id = te.msp_id AND tl.ticket_id = te.ticket_id
|
|
29
|
+
WHERE te.msp_id = $1
|
|
30
|
+
AND te.ticket_id != $2
|
|
31
|
+
AND te.problem_embedding IS NOT NULL
|
|
32
|
+
ORDER BY te.problem_embedding <=> (
|
|
33
|
+
SELECT problem_embedding FROM ticket_embeddings
|
|
34
|
+
WHERE msp_id = $1 AND ticket_id = $2
|
|
35
|
+
)
|
|
36
|
+
LIMIT $3`, [mspId, params.ticketId, limit], mspId);
|
|
37
|
+
return {
|
|
38
|
+
found: true,
|
|
39
|
+
source_ticket: params.ticketId,
|
|
40
|
+
source_summary: source[0].ai_summary,
|
|
41
|
+
similar: similar.map((s) => ({
|
|
42
|
+
...s,
|
|
43
|
+
similarity_score: Math.round(Number(s.similarity_score) * 1000) / 1000,
|
|
44
|
+
})),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=similar-tickets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similar-tickets.js","sourceRoot":"","sources":["../../../src/tools/ai/similar-tickets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAOtD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,MAAqB;IAErB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;IAEhC,oCAAoC;IACpC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B;;0CAEsC,EACtC,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,EACxB,KAAK,CACN,CAAC;IAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAiB,EAAE,CAAC;QACxD,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE,kCAAkC,MAAM,CAAC,QAAQ,kEAAkE;SAC7H,CAAC;IACJ,CAAC;IAED,oEAAoE;IACpE,MAAM,OAAO,GAAG,MAAM,QAAQ,CAC5B;;;;;;;;;;;;;;;;;;;;;cAqBU,EACV,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,EAC/B,KAAK,CACN,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,IAAI;QACX,aAAa,EAAE,MAAM,CAAC,QAAQ;QAC9B,cAAc,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU;QACpC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,GAAG,CAAC;YACJ,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI;SACvE,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggest-improvement.d.ts","sourceRoot":"","sources":["../../../src/tools/ai/suggest-improvement.ts"],"names":[],"mappings":"AAGA,UAAU,aAAa;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa,gBAuFtB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
import { chatCompletion } from "../../db/azure-openai.js";
|
|
3
|
+
export async function suggestTechnicianImprovement(mspId, params) {
|
|
4
|
+
const [dqScore, recentNotes, profile] = await Promise.all([
|
|
5
|
+
queryRLS(`SELECT technician_name, quality_points, completeness_points,
|
|
6
|
+
accuracy_points, timeliness_points, detail_quality_points,
|
|
7
|
+
unique_tickets, total_notes, avg_note_length
|
|
8
|
+
FROM analytics.technician_dq_leaderboard_daily
|
|
9
|
+
WHERE msp_id = $1 AND LOWER(technician_name) = LOWER($2)
|
|
10
|
+
ORDER BY calculation_date DESC
|
|
11
|
+
LIMIT 1`, [mspId, params.technicianName], mspId),
|
|
12
|
+
queryRLS(`SELECT tns.text, tns.sentiment_score
|
|
13
|
+
FROM ticket_notes_sentiment tns
|
|
14
|
+
JOIN ticket_lifecycle tl ON tl.msp_id = tns.msp_id AND tl.ticket_id = tns.ticket_id
|
|
15
|
+
WHERE tns.msp_id = $1 AND LOWER(tl.owner_name) = LOWER($2)
|
|
16
|
+
AND tl.responded_date >= CURRENT_DATE - INTERVAL '30 days'
|
|
17
|
+
ORDER BY tns.created_at DESC
|
|
18
|
+
LIMIT 5`, [mspId, params.technicianName], mspId),
|
|
19
|
+
queryRLS(`SELECT technician_name, level, hourly_rate
|
|
20
|
+
FROM technicians
|
|
21
|
+
WHERE msp_id = $1 AND LOWER(technician_name) = LOWER($2)
|
|
22
|
+
LIMIT 1`, [mspId, params.technicianName], mspId),
|
|
23
|
+
]);
|
|
24
|
+
if (dqScore.length === 0) {
|
|
25
|
+
return { found: false, message: `No performance data for "${params.technicianName}"` };
|
|
26
|
+
}
|
|
27
|
+
const dq = dqScore[0];
|
|
28
|
+
const sampleNotes = recentNotes
|
|
29
|
+
.map((n) => `- "${n.text?.substring(0, 150)}..." (sentiment: ${n.sentiment_score})`)
|
|
30
|
+
.join("\n");
|
|
31
|
+
const result = await chatCompletion({
|
|
32
|
+
messages: [
|
|
33
|
+
{
|
|
34
|
+
role: "system",
|
|
35
|
+
content: `You are an MSP service desk coach. Create a personalized coaching plan for a technician based on their documentation quality scores and sample notes. Return JSON with "strengths" (string[]), "improvement_areas" (string[]), "action_plan" (30-day coaching plan as string), and "example_transformations" (array of objects with "before" and "after" note examples). Only return valid JSON.`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
role: "user",
|
|
39
|
+
content: `Technician: ${dq.technician_name} (Level: ${profile[0]?.level || "unknown"})
|
|
40
|
+
DQ Score: ${dq.quality_points}/100
|
|
41
|
+
- Completeness: ${dq.completeness_points}
|
|
42
|
+
- Accuracy: ${dq.accuracy_points}
|
|
43
|
+
- Timeliness: ${dq.timeliness_points}
|
|
44
|
+
- Detail Quality: ${dq.detail_quality_points}
|
|
45
|
+
Tickets: ${dq.unique_tickets}, Notes: ${dq.total_notes}, Avg length: ${dq.avg_note_length} chars
|
|
46
|
+
|
|
47
|
+
Recent note samples:
|
|
48
|
+
${sampleNotes || "No recent notes available"}
|
|
49
|
+
|
|
50
|
+
Create a coaching plan for this technician.`,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
maxTokens: 800,
|
|
54
|
+
temperature: 0.6,
|
|
55
|
+
});
|
|
56
|
+
try {
|
|
57
|
+
const parsed = JSON.parse(result.content);
|
|
58
|
+
return {
|
|
59
|
+
found: true,
|
|
60
|
+
current_score: dq.quality_points,
|
|
61
|
+
level: profile[0]?.level ?? null,
|
|
62
|
+
...parsed,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return {
|
|
67
|
+
found: true,
|
|
68
|
+
current_score: dq.quality_points,
|
|
69
|
+
action_plan: result.content,
|
|
70
|
+
strengths: [],
|
|
71
|
+
improvement_areas: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=suggest-improvement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggest-improvement.js","sourceRoot":"","sources":["../../../src/tools/ai/suggest-improvement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAM1D,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,KAAa,EACb,MAAqB;IAErB,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACxD,QAAQ,CACN;;;;;;eAMS,EACT,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,EAC9B,KAAK,CACN;QACD,QAAQ,CACN;;;;;;eAMS,EACT,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,EAC9B,KAAK,CACN;QACD,QAAQ,CACN;;;eAGS,EACT,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC,EAC9B,KAAK,CACN;KACF,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,4BAA4B,MAAM,CAAC,cAAc,GAAG,EAAE,CAAC;IACzF,CAAC;IAED,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,WAAW,GAAG,WAAW;SAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAO,CAAC,CAAC,IAAe,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,oBAAoB,CAAC,CAAC,eAAe,GAAG,CAAC;SAC/F,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,kYAAkY;aAC5Y;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,eAAe,EAAE,CAAC,eAAe,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,SAAS;YAChF,EAAE,CAAC,cAAc;kBACX,EAAE,CAAC,mBAAmB;cAC1B,EAAE,CAAC,eAAe;gBAChB,EAAE,CAAC,iBAAiB;oBAChB,EAAE,CAAC,qBAAqB;WACjC,EAAE,CAAC,cAAc,YAAY,EAAE,CAAC,WAAW,iBAAiB,EAAE,CAAC,eAAe;;;EAGvF,WAAW,IAAI,2BAA2B;;4CAEA;aACrC;SACF;QACD,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO;YACL,KAAK,EAAE,IAAI;YACX,aAAa,EAAE,EAAE,CAAC,cAAc;YAChC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI;YAChC,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,KAAK,EAAE,IAAI;YACX,aAAa,EAAE,EAAE,CAAC,cAAc;YAChC,WAAW,EAAE,MAAM,CAAC,OAAO;YAC3B,SAAS,EAAE,EAAE;YACb,iBAAiB,EAAE,EAAE;SACtB,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function getBacklogPressure(mspId: string): Promise<{
|
|
2
|
+
by_priority: {
|
|
3
|
+
priority_name: string;
|
|
4
|
+
green: number;
|
|
5
|
+
yellow: number;
|
|
6
|
+
red: number;
|
|
7
|
+
total: number;
|
|
8
|
+
}[];
|
|
9
|
+
summary: {
|
|
10
|
+
total_open: number;
|
|
11
|
+
critical_aging: number;
|
|
12
|
+
pct_red: number;
|
|
13
|
+
};
|
|
14
|
+
}>;
|
|
15
|
+
//# sourceMappingURL=backlog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.d.ts","sourceRoot":"","sources":["../../../src/tools/analytics/backlog.ts"],"names":[],"mappings":"AAGA,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM;;uBAkBjC,MAAM;eAAS,MAAM;gBAAU,MAAM;aAAO,MAAM;eAAS,MAAM;;;;;;;GA+BrF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
export async function getBacklogPressure(mspId) {
|
|
3
|
+
const rows = await queryRLS(`SELECT priority_name, age_bucket, ticket_count, ticket_ids
|
|
4
|
+
FROM analytics.backlog_pressure_daily
|
|
5
|
+
WHERE msp_id = $1
|
|
6
|
+
AND snapshot_date = (
|
|
7
|
+
SELECT MAX(snapshot_date)
|
|
8
|
+
FROM analytics.backlog_pressure_daily
|
|
9
|
+
WHERE msp_id = $1
|
|
10
|
+
)
|
|
11
|
+
ORDER BY priority_name, age_bucket`, [mspId], mspId);
|
|
12
|
+
// Pivot into per-priority summary
|
|
13
|
+
const byPriority = {};
|
|
14
|
+
for (const row of rows) {
|
|
15
|
+
if (!byPriority[row.priority_name]) {
|
|
16
|
+
byPriority[row.priority_name] = {
|
|
17
|
+
priority_name: row.priority_name,
|
|
18
|
+
green: 0,
|
|
19
|
+
yellow: 0,
|
|
20
|
+
red: 0,
|
|
21
|
+
total: 0,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const entry = byPriority[row.priority_name];
|
|
25
|
+
const count = Number(row.ticket_count) || 0;
|
|
26
|
+
entry[row.age_bucket] = count;
|
|
27
|
+
entry.total += count;
|
|
28
|
+
}
|
|
29
|
+
const priorities = Object.values(byPriority);
|
|
30
|
+
const totalOpen = priorities.reduce((sum, p) => sum + p.total, 0);
|
|
31
|
+
const totalRed = priorities.reduce((sum, p) => sum + p.red, 0);
|
|
32
|
+
return {
|
|
33
|
+
by_priority: priorities,
|
|
34
|
+
summary: {
|
|
35
|
+
total_open: totalOpen,
|
|
36
|
+
critical_aging: totalRed,
|
|
37
|
+
pct_red: totalOpen > 0 ? Math.round((totalRed / totalOpen) * 100) : 0,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=backlog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backlog.js","sourceRoot":"","sources":["../../../src/tools/analytics/backlog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAGtD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAa;IACpD,MAAM,IAAI,GAAG,MAAM,QAAQ,CACzB;;;;;;;;wCAQoC,EACpC,CAAC,KAAK,CAAC,EACP,KAAK,CACN,CAAC;IAEF,kCAAkC;IAClC,MAAM,UAAU,GAGZ,EAAE,CAAC;IAEP,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YACnC,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG;gBAC9B,aAAa,EAAE,GAAG,CAAC,aAAa;gBAChC,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,CAAC;gBACT,GAAG,EAAE,CAAC;gBACN,KAAK,EAAE,CAAC;aACT,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5C,KAAK,CAAC,GAAG,CAAC,UAAwC,CAAC,GAAG,KAAK,CAAC;QAC5D,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;IACvB,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAE/D,OAAO;QACL,WAAW,EAAE,UAAU;QACvB,OAAO,EAAE;YACP,UAAU,EAAE,SAAS;YACrB,cAAc,EAAE,QAAQ;YACxB,OAAO,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SACtE;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { BillingClassification } from "../../types/database.js";
|
|
2
|
+
interface BillingParams {
|
|
3
|
+
fromDate?: string;
|
|
4
|
+
toDate?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function getBillingOpportunities(mspId: string, params: BillingParams): Promise<{
|
|
7
|
+
summary: {
|
|
8
|
+
total_tickets: number;
|
|
9
|
+
total_dollars: number;
|
|
10
|
+
avg_per_ticket: number;
|
|
11
|
+
};
|
|
12
|
+
tickets: BillingClassification[];
|
|
13
|
+
}>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=billing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../../src/tools/analytics/billing.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,aAAa;;;;;;;GA6BtB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { queryRLS } from "../../db/gateway-client.js";
|
|
2
|
+
export async function getBillingOpportunities(mspId, params) {
|
|
3
|
+
const fromDate = params.fromDate ?? new Date(Date.now() - 30 * 86400000).toISOString().split("T")[0];
|
|
4
|
+
const toDate = params.toDate ?? new Date().toISOString().split("T")[0];
|
|
5
|
+
const rows = await queryRLS(`SELECT bc.ticket_id, bc.company_name, bc.classification,
|
|
6
|
+
bc.billable_amount, bc.resolved_date::text
|
|
7
|
+
FROM agents.billing_classifications bc
|
|
8
|
+
WHERE bc.msp_id::uuid = $1::uuid
|
|
9
|
+
AND bc.classification = 'out_of_scope'
|
|
10
|
+
AND bc.resolved_date >= $2::date
|
|
11
|
+
AND bc.resolved_date <= $3::date
|
|
12
|
+
AND bc.billable_amount > 0
|
|
13
|
+
ORDER BY bc.billable_amount DESC`, [mspId, fromDate, toDate], mspId);
|
|
14
|
+
const totalDollars = rows.reduce((sum, r) => sum + (r.billable_amount || 0), 0);
|
|
15
|
+
return {
|
|
16
|
+
summary: {
|
|
17
|
+
total_tickets: rows.length,
|
|
18
|
+
total_dollars: Math.round(totalDollars * 100) / 100,
|
|
19
|
+
avg_per_ticket: rows.length > 0 ? Math.round((totalDollars / rows.length) * 100) / 100 : 0,
|
|
20
|
+
},
|
|
21
|
+
tickets: rows,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../../../src/tools/analytics/billing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAQtD,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,KAAa,EACb,MAAqB;IAErB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvE,MAAM,IAAI,GAAG,MAAM,QAAQ,CACzB;;;;;;;;sCAQkC,EAClC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EACzB,KAAK,CACN,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEhF,OAAO;QACL,OAAO,EAAE;YACP,aAAa,EAAE,IAAI,CAAC,MAAM;YAC1B,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC,GAAG,GAAG;YACnD,cAAc,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;SAC3F;QACD,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
interface ClientExpParams {
|
|
2
|
+
clientName: string;
|
|
3
|
+
daysBack?: number;
|
|
4
|
+
}
|
|
5
|
+
interface ClientExpRow {
|
|
6
|
+
company_name: string;
|
|
7
|
+
ticket_count: number;
|
|
8
|
+
avg_response_minutes: number;
|
|
9
|
+
avg_resolution_minutes: number;
|
|
10
|
+
avg_sentiment_score: number;
|
|
11
|
+
health_score: number;
|
|
12
|
+
total_cost: number;
|
|
13
|
+
sla_breach_count: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function getClientExperience(mspId: string, params: ClientExpParams): Promise<{
|
|
16
|
+
found: boolean;
|
|
17
|
+
message: string;
|
|
18
|
+
metrics?: undefined;
|
|
19
|
+
top_patterns?: undefined;
|
|
20
|
+
days_analyzed?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
found: boolean;
|
|
23
|
+
metrics: ClientExpRow;
|
|
24
|
+
top_patterns: {
|
|
25
|
+
pattern_name: string;
|
|
26
|
+
ticket_count: number;
|
|
27
|
+
}[];
|
|
28
|
+
days_analyzed: number;
|
|
29
|
+
message?: undefined;
|
|
30
|
+
}>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=client-experience.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-experience.d.ts","sourceRoot":"","sources":["../../../src/tools/analytics/client-experience.ts"],"names":[],"mappings":"AAEA,UAAU,eAAe;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,eAAe;;;;;;;;;;sBA2ByB,MAAM;sBAAgB,MAAM;;;;GAiB7E"}
|