@contractspec/lib.support-bot 1.44.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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +49 -0
  3. package/dist/ai-agent/src/agent/agent-factory.d.ts +7 -0
  4. package/dist/ai-agent/src/agent/contract-spec-agent.d.ts +5 -0
  5. package/dist/ai-agent/src/agent/index.d.ts +2 -0
  6. package/dist/ai-agent/src/approval/index.d.ts +1 -0
  7. package/dist/ai-agent/src/approval/workflow.d.ts +1 -0
  8. package/dist/ai-agent/src/index.d.ts +11 -0
  9. package/dist/ai-agent/src/knowledge/index.d.ts +1 -0
  10. package/dist/ai-agent/src/knowledge/injector.d.ts +1 -0
  11. package/dist/ai-agent/src/schema/index.d.ts +2 -0
  12. package/dist/ai-agent/src/schema/json-schema-to-zod.d.ts +1 -0
  13. package/dist/ai-agent/src/schema/schema-output.d.ts +2 -0
  14. package/dist/ai-agent/src/session/index.d.ts +1 -0
  15. package/dist/ai-agent/src/session/store.d.ts +2 -0
  16. package/dist/ai-agent/src/spec/index.d.ts +2 -0
  17. package/dist/ai-agent/src/spec/registry.d.ts +1 -0
  18. package/dist/ai-agent/src/spec/spec.d.ts +115 -0
  19. package/dist/ai-agent/src/spec/spec.d.ts.map +1 -0
  20. package/dist/ai-agent/src/telemetry/adapter.d.ts +1 -0
  21. package/dist/ai-agent/src/telemetry/index.d.ts +1 -0
  22. package/dist/ai-agent/src/tools/index.d.ts +4 -0
  23. package/dist/ai-agent/src/tools/knowledge-tool.d.ts +2 -0
  24. package/dist/ai-agent/src/tools/mcp-client.d.ts +1 -0
  25. package/dist/ai-agent/src/tools/mcp-server.d.ts +3 -0
  26. package/dist/ai-agent/src/tools/tool-adapter.d.ts +3 -0
  27. package/dist/ai-agent/src/types.d.ts +1 -0
  28. package/dist/bot/auto-responder.d.ts +26 -0
  29. package/dist/bot/auto-responder.d.ts.map +1 -0
  30. package/dist/bot/auto-responder.js +84 -0
  31. package/dist/bot/auto-responder.js.map +1 -0
  32. package/dist/bot/feedback-loop.d.ts +20 -0
  33. package/dist/bot/feedback-loop.d.ts.map +1 -0
  34. package/dist/bot/feedback-loop.js +35 -0
  35. package/dist/bot/feedback-loop.js.map +1 -0
  36. package/dist/bot/index.d.ts +4 -0
  37. package/dist/bot/index.js +5 -0
  38. package/dist/bot/tools.d.ts +15 -0
  39. package/dist/bot/tools.d.ts.map +1 -0
  40. package/dist/bot/tools.js +137 -0
  41. package/dist/bot/tools.js.map +1 -0
  42. package/dist/contracts/src/docs/accessibility_wcag_compliance_specs.docblock.d.ts +1 -0
  43. package/dist/contracts/src/docs/index.d.ts +25 -0
  44. package/dist/contracts/src/docs/presentations.d.ts +2 -0
  45. package/dist/contracts/src/docs/registry.d.ts +10 -0
  46. package/dist/contracts/src/docs/registry.d.ts.map +1 -0
  47. package/dist/contracts/src/docs/tech/auth/better-auth-nextjs.docblock.d.ts +1 -0
  48. package/dist/contracts/src/docs/tech/contracts/openapi-export.docblock.d.ts +1 -0
  49. package/dist/contracts/src/docs/tech/contracts/openapi-import.docblock.d.ts +1 -0
  50. package/dist/contracts/src/docs/tech/lifecycle-stage-system.docblock.d.ts +1 -0
  51. package/dist/contracts/src/docs/tech/llm/llm-integration.docblock.d.ts +1 -0
  52. package/dist/contracts/src/docs/tech/mcp-endpoints.docblock.d.ts +1 -0
  53. package/dist/contracts/src/docs/tech/presentation-runtime.docblock.d.ts +1 -0
  54. package/dist/contracts/src/docs/tech/schema/README.docblock.d.ts +1 -0
  55. package/dist/contracts/src/docs/tech/studio/learning-events.docblock.d.ts +1 -0
  56. package/dist/contracts/src/docs/tech/studio/learning-journeys.docblock.d.ts +1 -0
  57. package/dist/contracts/src/docs/tech/studio/platform-admin-panel.docblock.d.ts +1 -0
  58. package/dist/contracts/src/docs/tech/studio/project-access-teams.docblock.d.ts +1 -0
  59. package/dist/contracts/src/docs/tech/studio/project-routing.docblock.d.ts +1 -0
  60. package/dist/contracts/src/docs/tech/studio/sandbox-unlogged.docblock.d.ts +1 -0
  61. package/dist/contracts/src/docs/tech/studio/team-invitations.docblock.d.ts +1 -0
  62. package/dist/contracts/src/docs/tech/studio/workspace-ops.docblock.d.ts +1 -0
  63. package/dist/contracts/src/docs/tech/studio/workspaces.docblock.d.ts +1 -0
  64. package/dist/contracts/src/docs/tech/telemetry-ingest.docblock.d.ts +1 -0
  65. package/dist/contracts/src/docs/tech/templates/runtime.docblock.d.ts +1 -0
  66. package/dist/contracts/src/docs/tech/vscode-extension.docblock.d.ts +1 -0
  67. package/dist/contracts/src/integrations/providers/llm.d.ts +83 -0
  68. package/dist/contracts/src/integrations/providers/llm.d.ts.map +1 -0
  69. package/dist/contracts/src/knowledge/spec.d.ts +8 -0
  70. package/dist/contracts/src/knowledge/spec.d.ts.map +1 -0
  71. package/dist/contracts/src/ownership.d.ts +61 -0
  72. package/dist/contracts/src/ownership.d.ts.map +1 -0
  73. package/dist/contracts/src/policy/spec.d.ts +11 -0
  74. package/dist/contracts/src/policy/spec.d.ts.map +1 -0
  75. package/dist/contracts/src/presentations/presentations.d.ts +2 -0
  76. package/dist/contracts/src/workflow/overview.docblock.d.ts +1 -0
  77. package/dist/contracts/src/workspace-config/workspace-config.docblock.d.ts +1 -0
  78. package/dist/index.d.ts +11 -0
  79. package/dist/index.js +9 -0
  80. package/dist/rag/index.d.ts +2 -0
  81. package/dist/rag/index.js +3 -0
  82. package/dist/rag/ticket-resolver.d.ts +25 -0
  83. package/dist/rag/ticket-resolver.d.ts.map +1 -0
  84. package/dist/rag/ticket-resolver.js +64 -0
  85. package/dist/rag/ticket-resolver.js.map +1 -0
  86. package/dist/schema/src/EnumType.d.ts +2 -0
  87. package/dist/schema/src/FieldType.d.ts +2 -0
  88. package/dist/schema/src/GraphQLSchemaType.d.ts +2 -0
  89. package/dist/schema/src/JsonSchemaType.d.ts +2 -0
  90. package/dist/schema/src/ScalarTypeEnum.d.ts +1 -0
  91. package/dist/schema/src/SchemaModel.d.ts +4 -0
  92. package/dist/schema/src/SchemaModelType.d.ts +1 -0
  93. package/dist/schema/src/ZodSchemaType.d.ts +2 -0
  94. package/dist/schema/src/entity/defineEntity.d.ts +1 -0
  95. package/dist/schema/src/entity/generator.d.ts +1 -0
  96. package/dist/schema/src/entity/index.d.ts +3 -0
  97. package/dist/schema/src/entity/types.d.ts +1 -0
  98. package/dist/schema/src/index.d.ts +9 -0
  99. package/dist/spec.d.ts +14 -0
  100. package/dist/spec.d.ts.map +1 -0
  101. package/dist/spec.js +35 -0
  102. package/dist/spec.js.map +1 -0
  103. package/dist/tickets/classifier.d.ts +25 -0
  104. package/dist/tickets/classifier.d.ts.map +1 -0
  105. package/dist/tickets/classifier.js +199 -0
  106. package/dist/tickets/classifier.js.map +1 -0
  107. package/dist/tickets/index.d.ts +2 -0
  108. package/dist/tickets/index.js +3 -0
  109. package/dist/types.d.ts +77 -0
  110. package/dist/types.d.ts.map +1 -0
  111. package/dist/types.js +0 -0
  112. package/package.json +76 -0
@@ -0,0 +1 @@
1
+ import "./types.js";
@@ -0,0 +1 @@
1
+ import "./types.js";
@@ -0,0 +1,3 @@
1
+ import "./types.js";
2
+ import "./defineEntity.js";
3
+ import "./generator.js";
@@ -0,0 +1 @@
1
+ import "zod";
@@ -0,0 +1,9 @@
1
+ import "./FieldType.js";
2
+ import "./ScalarTypeEnum.js";
3
+ import "./EnumType.js";
4
+ import "./SchemaModelType.js";
5
+ import "./SchemaModel.js";
6
+ import "./entity/index.js";
7
+ import "./ZodSchemaType.js";
8
+ import "./JsonSchemaType.js";
9
+ import "./GraphQLSchemaType.js";
package/dist/spec.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { AgentSpec, AgentToolConfig } from "./ai-agent/src/spec/spec.js";
2
+ import "./ai-agent/src/index.js";
3
+ import { SupportBotSpec } from "./types.js";
4
+
5
+ //#region src/spec.d.ts
6
+ interface SupportBotDefinition {
7
+ base: AgentSpec;
8
+ tools?: AgentToolConfig[];
9
+ autoEscalateThreshold?: number;
10
+ }
11
+ declare function defineSupportBot(definition: SupportBotDefinition): SupportBotSpec;
12
+ //#endregion
13
+ export { SupportBotDefinition, defineSupportBot };
14
+ //# sourceMappingURL=spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.d.ts","names":[],"sources":["../src/spec.ts"],"sourcesContent":[],"mappings":";;;;;UAIiB,oBAAA;QACT;UACE;EAFO,qBAAA,CAAA,EAAoB,MAAA;AAMrC;iBAAgB,gBAAA,aACF,uBACX"}
package/dist/spec.js ADDED
@@ -0,0 +1,35 @@
1
+ import { defineAgent } from "@contractspec/lib.ai-agent";
2
+
3
+ //#region src/spec.ts
4
+ function defineSupportBot(definition) {
5
+ return {
6
+ ...defineAgent({
7
+ ...definition.base,
8
+ policy: {
9
+ ...definition.base.policy,
10
+ confidence: {
11
+ min: definition.base.policy?.confidence?.min ?? .7,
12
+ default: definition.base.policy?.confidence?.default ?? .6
13
+ },
14
+ escalation: {
15
+ confidenceThreshold: definition.autoEscalateThreshold ?? definition.base.policy?.escalation?.confidenceThreshold ?? definition.base.policy?.confidence?.min ?? .7,
16
+ ...definition.base.policy?.escalation
17
+ }
18
+ },
19
+ memory: definition.base.memory ?? {
20
+ maxEntries: 120,
21
+ ttlMinutes: 120
22
+ },
23
+ tools: definition.tools ?? definition.base.tools,
24
+ instructions: `${definition.base.instructions}\n\nAlways cite support knowledge sources and flag compliance/billing issues for human review when unsure.`
25
+ }),
26
+ thresholds: {
27
+ autoResolveMinConfidence: definition.autoEscalateThreshold ?? .75,
28
+ maxIterations: 6
29
+ }
30
+ };
31
+ }
32
+
33
+ //#endregion
34
+ export { defineSupportBot };
35
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","names":[],"sources":["../src/spec.ts"],"sourcesContent":["import type { AgentSpec, AgentToolConfig } from '@contractspec/lib.ai-agent';\nimport { defineAgent } from '@contractspec/lib.ai-agent';\nimport type { SupportBotSpec } from './types';\n\nexport interface SupportBotDefinition {\n base: AgentSpec;\n tools?: AgentToolConfig[];\n autoEscalateThreshold?: number;\n}\n\nexport function defineSupportBot(\n definition: SupportBotDefinition\n): SupportBotSpec {\n const base = defineAgent({\n ...definition.base,\n policy: {\n ...definition.base.policy,\n confidence: {\n min: definition.base.policy?.confidence?.min ?? 0.7,\n default: definition.base.policy?.confidence?.default ?? 0.6,\n },\n escalation: {\n confidenceThreshold:\n definition.autoEscalateThreshold ??\n definition.base.policy?.escalation?.confidenceThreshold ??\n definition.base.policy?.confidence?.min ??\n 0.7,\n ...definition.base.policy?.escalation,\n },\n },\n memory: definition.base.memory ?? { maxEntries: 120, ttlMinutes: 120 },\n tools: definition.tools ?? definition.base.tools,\n instructions: `${definition.base.instructions}\\n\\nAlways cite support knowledge sources and flag compliance/billing issues for human review when unsure.`,\n });\n\n return {\n ...base,\n thresholds: {\n autoResolveMinConfidence: definition.autoEscalateThreshold ?? 0.75,\n maxIterations: 6,\n },\n };\n}\n"],"mappings":";;;AAUA,SAAgB,iBACd,YACgB;AAuBhB,QAAO;EACL,GAvBW,YAAY;GACvB,GAAG,WAAW;GACd,QAAQ;IACN,GAAG,WAAW,KAAK;IACnB,YAAY;KACV,KAAK,WAAW,KAAK,QAAQ,YAAY,OAAO;KAChD,SAAS,WAAW,KAAK,QAAQ,YAAY,WAAW;KACzD;IACD,YAAY;KACV,qBACE,WAAW,yBACX,WAAW,KAAK,QAAQ,YAAY,uBACpC,WAAW,KAAK,QAAQ,YAAY,OACpC;KACF,GAAG,WAAW,KAAK,QAAQ;KAC5B;IACF;GACD,QAAQ,WAAW,KAAK,UAAU;IAAE,YAAY;IAAK,YAAY;IAAK;GACtE,OAAO,WAAW,SAAS,WAAW,KAAK;GAC3C,cAAc,GAAG,WAAW,KAAK,aAAa;GAC/C,CAAC;EAIA,YAAY;GACV,0BAA0B,WAAW,yBAAyB;GAC9D,eAAe;GAChB;EACF"}
@@ -0,0 +1,25 @@
1
+ import { LLMProvider } from "../contracts/src/integrations/providers/llm.js";
2
+ import { SupportTicket, TicketCategory, TicketClassification } from "../types.js";
3
+
4
+ //#region src/tickets/classifier.d.ts
5
+ interface TicketClassifierOptions {
6
+ keywords?: Partial<Record<TicketCategory, string[]>>;
7
+ llm?: LLMProvider;
8
+ llmModel?: string;
9
+ }
10
+ declare class TicketClassifier {
11
+ private readonly keywords;
12
+ private readonly llm?;
13
+ private readonly llmModel?;
14
+ constructor(options?: TicketClassifierOptions);
15
+ classify(ticket: SupportTicket): Promise<TicketClassification>;
16
+ private heuristicClassification;
17
+ private detectCategory;
18
+ private detectPriority;
19
+ private detectSentiment;
20
+ private extractIntents;
21
+ private estimateConfidence;
22
+ }
23
+ //#endregion
24
+ export { TicketClassifier, TicketClassifierOptions };
25
+ //# sourceMappingURL=classifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.d.ts","names":[],"sources":["../../src/tickets/classifier.ts"],"sourcesContent":[],"mappings":";;;;UAgCiB,uBAAA;aACJ,QAAQ,OAAO;EADX,GAAA,CAAA,EAET,WAFS;EACW,QAAA,CAAA,EAAA,MAAA;;AAAf,cAKA,gBAAA,CALA;EACL,iBAAA,QAAA;EAAW,iBAAA,GAAA;EAIN,iBAAA,QAAgB;EAKL,WAAA,CAAA,OAAA,CAAA,EAAA,uBAAA;EASC,QAAA,CAAA,MAAA,EAAA,aAAA,CAAA,EAAgB,OAAhB,CAAwB,oBAAxB,CAAA;EAAwB,QAAA,uBAAA;EAAR,QAAA,cAAA;EAAO,QAAA,cAAA"}
@@ -0,0 +1,199 @@
1
+ //#region src/tickets/classifier.ts
2
+ const CATEGORY_KEYWORDS = {
3
+ billing: [
4
+ "invoice",
5
+ "payout",
6
+ "refund",
7
+ "charge",
8
+ "billing",
9
+ "payment"
10
+ ],
11
+ technical: [
12
+ "bug",
13
+ "error",
14
+ "crash",
15
+ "issue",
16
+ "failed",
17
+ "timeout"
18
+ ],
19
+ product: [
20
+ "feature",
21
+ "roadmap",
22
+ "idea",
23
+ "request",
24
+ "feedback"
25
+ ],
26
+ account: [
27
+ "login",
28
+ "password",
29
+ "2fa",
30
+ "account",
31
+ "profile",
32
+ "email change"
33
+ ],
34
+ compliance: [
35
+ "kyc",
36
+ "aml",
37
+ "compliance",
38
+ "regulation",
39
+ "gdpr"
40
+ ],
41
+ other: []
42
+ };
43
+ const PRIORITY_HINTS = {
44
+ urgent: [
45
+ "urgent",
46
+ "asap",
47
+ "immediately",
48
+ "today",
49
+ "right away"
50
+ ],
51
+ high: [
52
+ "high priority",
53
+ "blocking",
54
+ "major",
55
+ "critical"
56
+ ],
57
+ medium: ["soon", "next few days"],
58
+ low: [
59
+ "nice to have",
60
+ "when possible",
61
+ "later"
62
+ ]
63
+ };
64
+ const SENTIMENT_HINTS = {
65
+ positive: [
66
+ "love",
67
+ "great",
68
+ "awesome",
69
+ "thank you"
70
+ ],
71
+ neutral: [
72
+ "question",
73
+ "wonder",
74
+ "curious"
75
+ ],
76
+ negative: [
77
+ "unhappy",
78
+ "bad",
79
+ "terrible",
80
+ "awful",
81
+ "angry"
82
+ ],
83
+ frustrated: [
84
+ "furious",
85
+ "frustrated",
86
+ "fed up",
87
+ "ridiculous"
88
+ ]
89
+ };
90
+ var TicketClassifier = class {
91
+ keywords;
92
+ llm;
93
+ llmModel;
94
+ constructor(options) {
95
+ this.keywords = {
96
+ ...CATEGORY_KEYWORDS,
97
+ ...options?.keywords ?? {}
98
+ };
99
+ this.llm = options?.llm;
100
+ this.llmModel = options?.llmModel;
101
+ }
102
+ async classify(ticket) {
103
+ const heuristics = this.heuristicClassification(ticket);
104
+ if (!this.llm) return heuristics;
105
+ try {
106
+ const content = (await this.llm.chat([{
107
+ role: "system",
108
+ content: [{
109
+ type: "text",
110
+ text: "Classify the support ticket."
111
+ }]
112
+ }, {
113
+ role: "user",
114
+ content: [{
115
+ type: "text",
116
+ text: JSON.stringify({
117
+ subject: ticket.subject,
118
+ body: ticket.body,
119
+ channel: ticket.channel
120
+ })
121
+ }]
122
+ }], {
123
+ responseFormat: "json",
124
+ model: this.llmModel
125
+ })).message.content.find((part) => "text" in part);
126
+ if (content && "text" in content) {
127
+ const parsed = JSON.parse(content.text);
128
+ return {
129
+ ...heuristics,
130
+ ...parsed,
131
+ intents: parsed.intents ?? heuristics.intents,
132
+ tags: parsed.tags ?? heuristics.tags
133
+ };
134
+ }
135
+ } catch {}
136
+ return heuristics;
137
+ }
138
+ heuristicClassification(ticket) {
139
+ const text = `${ticket.subject}\n${ticket.body}`.toLowerCase();
140
+ const category = this.detectCategory(text);
141
+ const priority = this.detectPriority(text);
142
+ const sentiment = this.detectSentiment(text);
143
+ const intents = this.extractIntents(text);
144
+ const tags = intents.slice(0, 3);
145
+ const confidence = this.estimateConfidence(category, priority, sentiment);
146
+ return {
147
+ ticketId: ticket.id,
148
+ category,
149
+ priority,
150
+ sentiment,
151
+ intents,
152
+ tags,
153
+ confidence,
154
+ escalationRequired: priority === "urgent" || category === "compliance"
155
+ };
156
+ }
157
+ detectCategory(text) {
158
+ for (const [category, keywords] of Object.entries(this.keywords)) if (keywords.some((keyword) => text.includes(keyword))) return category;
159
+ return "other";
160
+ }
161
+ detectPriority(text) {
162
+ for (const priority of [
163
+ "urgent",
164
+ "high",
165
+ "medium",
166
+ "low"
167
+ ]) if (PRIORITY_HINTS[priority].some((word) => text.includes(word))) return priority;
168
+ return "medium";
169
+ }
170
+ detectSentiment(text) {
171
+ for (const sentiment of [
172
+ "frustrated",
173
+ "negative",
174
+ "neutral",
175
+ "positive"
176
+ ]) if (SENTIMENT_HINTS[sentiment].some((word) => text.includes(word))) return sentiment;
177
+ return "neutral";
178
+ }
179
+ extractIntents(text) {
180
+ const intents = [];
181
+ if (text.includes("refund") || text.includes("chargeback")) intents.push("refund");
182
+ if (text.includes("payout")) intents.push("payout");
183
+ if (text.includes("login")) intents.push("login-help");
184
+ if (text.includes("feature")) intents.push("feature-request");
185
+ if (text.includes("bug") || text.includes("error")) intents.push("bug-report");
186
+ return intents.length ? intents : ["general"];
187
+ }
188
+ estimateConfidence(category, priority, sentiment) {
189
+ let base = .6;
190
+ if (category !== "other") base += .1;
191
+ if (priority === "urgent" || priority === "low") base += .05;
192
+ if (sentiment === "frustrated") base -= .05;
193
+ return Math.min(.95, Math.max(.4, Number(base.toFixed(2))));
194
+ }
195
+ };
196
+
197
+ //#endregion
198
+ export { TicketClassifier };
199
+ //# sourceMappingURL=classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.js","names":["CATEGORY_KEYWORDS: Record<TicketCategory, string[]>","PRIORITY_HINTS: Record<TicketPriority, string[]>","SENTIMENT_HINTS: Record<TicketSentiment, string[]>","intents: string[]"],"sources":["../../src/tickets/classifier.ts"],"sourcesContent":["import type { LLMProvider } from '@contractspec/lib.contracts/integrations/providers/llm';\nimport type {\n SupportTicket,\n TicketCategory,\n TicketPriority,\n TicketSentiment,\n TicketClassification,\n} from '../types';\n\nconst CATEGORY_KEYWORDS: Record<TicketCategory, string[]> = {\n billing: ['invoice', 'payout', 'refund', 'charge', 'billing', 'payment'],\n technical: ['bug', 'error', 'crash', 'issue', 'failed', 'timeout'],\n product: ['feature', 'roadmap', 'idea', 'request', 'feedback'],\n account: ['login', 'password', '2fa', 'account', 'profile', 'email change'],\n compliance: ['kyc', 'aml', 'compliance', 'regulation', 'gdpr'],\n other: [],\n};\n\nconst PRIORITY_HINTS: Record<TicketPriority, string[]> = {\n urgent: ['urgent', 'asap', 'immediately', 'today', 'right away'],\n high: ['high priority', 'blocking', 'major', 'critical'],\n medium: ['soon', 'next few days'],\n low: ['nice to have', 'when possible', 'later'],\n};\n\nconst SENTIMENT_HINTS: Record<TicketSentiment, string[]> = {\n positive: ['love', 'great', 'awesome', 'thank you'],\n neutral: ['question', 'wonder', 'curious'],\n negative: ['unhappy', 'bad', 'terrible', 'awful', 'angry'],\n frustrated: ['furious', 'frustrated', 'fed up', 'ridiculous'],\n};\n\nexport interface TicketClassifierOptions {\n keywords?: Partial<Record<TicketCategory, string[]>>;\n llm?: LLMProvider;\n llmModel?: string;\n}\n\nexport class TicketClassifier {\n private readonly keywords: Record<TicketCategory, string[]>;\n private readonly llm?: LLMProvider;\n private readonly llmModel?: string;\n\n constructor(options?: TicketClassifierOptions) {\n this.keywords = {\n ...CATEGORY_KEYWORDS,\n ...(options?.keywords ?? {}),\n } as Record<TicketCategory, string[]>;\n this.llm = options?.llm;\n this.llmModel = options?.llmModel;\n }\n\n async classify(ticket: SupportTicket): Promise<TicketClassification> {\n const heuristics = this.heuristicClassification(ticket);\n if (!this.llm) return heuristics;\n\n try {\n const llmResult = await this.llm.chat(\n [\n {\n role: 'system',\n content: [{ type: 'text', text: 'Classify the support ticket.' }],\n },\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n subject: ticket.subject,\n body: ticket.body,\n channel: ticket.channel,\n }),\n },\n ],\n },\n ],\n {\n responseFormat: 'json',\n model: this.llmModel,\n }\n );\n const content = llmResult.message.content.find((part) => 'text' in part);\n if (content && 'text' in content) {\n const parsed = JSON.parse(\n content.text\n ) as Partial<TicketClassification>;\n return {\n ...heuristics,\n ...parsed,\n intents: parsed.intents ?? heuristics.intents,\n tags: parsed.tags ?? heuristics.tags,\n };\n }\n } catch {\n // fallback to heuristics\n }\n\n return heuristics;\n }\n\n private heuristicClassification(ticket: SupportTicket): TicketClassification {\n const text = `${ticket.subject}\\n${ticket.body}`.toLowerCase();\n const category = this.detectCategory(text);\n const priority = this.detectPriority(text);\n const sentiment = this.detectSentiment(text);\n const intents = this.extractIntents(text);\n const tags = intents.slice(0, 3);\n const confidence = this.estimateConfidence(category, priority, sentiment);\n\n return {\n ticketId: ticket.id,\n category,\n priority,\n sentiment,\n intents,\n tags,\n confidence,\n escalationRequired: priority === 'urgent' || category === 'compliance',\n };\n }\n\n private detectCategory(text: string): TicketCategory {\n for (const [category, keywords] of Object.entries(this.keywords) as [\n TicketCategory,\n string[],\n ][]) {\n if (keywords.some((keyword) => text.includes(keyword))) {\n return category;\n }\n }\n return 'other';\n }\n\n private detectPriority(text: string): TicketPriority {\n for (const priority of [\n 'urgent',\n 'high',\n 'medium',\n 'low',\n ] as TicketPriority[]) {\n if (PRIORITY_HINTS[priority].some((word) => text.includes(word))) {\n return priority;\n }\n }\n return 'medium';\n }\n\n private detectSentiment(text: string): TicketSentiment {\n for (const sentiment of [\n 'frustrated',\n 'negative',\n 'neutral',\n 'positive',\n ] as TicketSentiment[]) {\n if (SENTIMENT_HINTS[sentiment].some((word) => text.includes(word))) {\n return sentiment;\n }\n }\n return 'neutral';\n }\n\n private extractIntents(text: string): string[] {\n const intents: string[] = [];\n if (text.includes('refund') || text.includes('chargeback'))\n intents.push('refund');\n if (text.includes('payout')) intents.push('payout');\n if (text.includes('login')) intents.push('login-help');\n if (text.includes('feature')) intents.push('feature-request');\n if (text.includes('bug') || text.includes('error'))\n intents.push('bug-report');\n return intents.length ? intents : ['general'];\n }\n\n private estimateConfidence(\n category: TicketCategory,\n priority: TicketPriority,\n sentiment: TicketSentiment\n ): number {\n let base = 0.6;\n if (category !== 'other') base += 0.1;\n if (priority === 'urgent' || priority === 'low') base += 0.05;\n if (sentiment === 'frustrated') base -= 0.05;\n return Math.min(0.95, Math.max(0.4, Number(base.toFixed(2))));\n }\n}\n"],"mappings":";AASA,MAAMA,oBAAsD;CAC1D,SAAS;EAAC;EAAW;EAAU;EAAU;EAAU;EAAW;EAAU;CACxE,WAAW;EAAC;EAAO;EAAS;EAAS;EAAS;EAAU;EAAU;CAClE,SAAS;EAAC;EAAW;EAAW;EAAQ;EAAW;EAAW;CAC9D,SAAS;EAAC;EAAS;EAAY;EAAO;EAAW;EAAW;EAAe;CAC3E,YAAY;EAAC;EAAO;EAAO;EAAc;EAAc;EAAO;CAC9D,OAAO,EAAE;CACV;AAED,MAAMC,iBAAmD;CACvD,QAAQ;EAAC;EAAU;EAAQ;EAAe;EAAS;EAAa;CAChE,MAAM;EAAC;EAAiB;EAAY;EAAS;EAAW;CACxD,QAAQ,CAAC,QAAQ,gBAAgB;CACjC,KAAK;EAAC;EAAgB;EAAiB;EAAQ;CAChD;AAED,MAAMC,kBAAqD;CACzD,UAAU;EAAC;EAAQ;EAAS;EAAW;EAAY;CACnD,SAAS;EAAC;EAAY;EAAU;EAAU;CAC1C,UAAU;EAAC;EAAW;EAAO;EAAY;EAAS;EAAQ;CAC1D,YAAY;EAAC;EAAW;EAAc;EAAU;EAAa;CAC9D;AAQD,IAAa,mBAAb,MAA8B;CAC5B,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,SAAmC;AAC7C,OAAK,WAAW;GACd,GAAG;GACH,GAAI,SAAS,YAAY,EAAE;GAC5B;AACD,OAAK,MAAM,SAAS;AACpB,OAAK,WAAW,SAAS;;CAG3B,MAAM,SAAS,QAAsD;EACnE,MAAM,aAAa,KAAK,wBAAwB,OAAO;AACvD,MAAI,CAAC,KAAK,IAAK,QAAO;AAEtB,MAAI;GA0BF,MAAM,WAzBY,MAAM,KAAK,IAAI,KAC/B,CACE;IACE,MAAM;IACN,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM;KAAgC,CAAC;IAClE,EACD;IACE,MAAM;IACN,SAAS,CACP;KACE,MAAM;KACN,MAAM,KAAK,UAAU;MACnB,SAAS,OAAO;MAChB,MAAM,OAAO;MACb,SAAS,OAAO;MACjB,CAAC;KACH,CACF;IACF,CACF,EACD;IACE,gBAAgB;IAChB,OAAO,KAAK;IACb,CACF,EACyB,QAAQ,QAAQ,MAAM,SAAS,UAAU,KAAK;AACxE,OAAI,WAAW,UAAU,SAAS;IAChC,MAAM,SAAS,KAAK,MAClB,QAAQ,KACT;AACD,WAAO;KACL,GAAG;KACH,GAAG;KACH,SAAS,OAAO,WAAW,WAAW;KACtC,MAAM,OAAO,QAAQ,WAAW;KACjC;;UAEG;AAIR,SAAO;;CAGT,AAAQ,wBAAwB,QAA6C;EAC3E,MAAM,OAAO,GAAG,OAAO,QAAQ,IAAI,OAAO,OAAO,aAAa;EAC9D,MAAM,WAAW,KAAK,eAAe,KAAK;EAC1C,MAAM,WAAW,KAAK,eAAe,KAAK;EAC1C,MAAM,YAAY,KAAK,gBAAgB,KAAK;EAC5C,MAAM,UAAU,KAAK,eAAe,KAAK;EACzC,MAAM,OAAO,QAAQ,MAAM,GAAG,EAAE;EAChC,MAAM,aAAa,KAAK,mBAAmB,UAAU,UAAU,UAAU;AAEzE,SAAO;GACL,UAAU,OAAO;GACjB;GACA;GACA;GACA;GACA;GACA;GACA,oBAAoB,aAAa,YAAY,aAAa;GAC3D;;CAGH,AAAQ,eAAe,MAA8B;AACnD,OAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,KAAK,SAAS,CAI9D,KAAI,SAAS,MAAM,YAAY,KAAK,SAAS,QAAQ,CAAC,CACpD,QAAO;AAGX,SAAO;;CAGT,AAAQ,eAAe,MAA8B;AACnD,OAAK,MAAM,YAAY;GACrB;GACA;GACA;GACA;GACD,CACC,KAAI,eAAe,UAAU,MAAM,SAAS,KAAK,SAAS,KAAK,CAAC,CAC9D,QAAO;AAGX,SAAO;;CAGT,AAAQ,gBAAgB,MAA+B;AACrD,OAAK,MAAM,aAAa;GACtB;GACA;GACA;GACA;GACD,CACC,KAAI,gBAAgB,WAAW,MAAM,SAAS,KAAK,SAAS,KAAK,CAAC,CAChE,QAAO;AAGX,SAAO;;CAGT,AAAQ,eAAe,MAAwB;EAC7C,MAAMC,UAAoB,EAAE;AAC5B,MAAI,KAAK,SAAS,SAAS,IAAI,KAAK,SAAS,aAAa,CACxD,SAAQ,KAAK,SAAS;AACxB,MAAI,KAAK,SAAS,SAAS,CAAE,SAAQ,KAAK,SAAS;AACnD,MAAI,KAAK,SAAS,QAAQ,CAAE,SAAQ,KAAK,aAAa;AACtD,MAAI,KAAK,SAAS,UAAU,CAAE,SAAQ,KAAK,kBAAkB;AAC7D,MAAI,KAAK,SAAS,MAAM,IAAI,KAAK,SAAS,QAAQ,CAChD,SAAQ,KAAK,aAAa;AAC5B,SAAO,QAAQ,SAAS,UAAU,CAAC,UAAU;;CAG/C,AAAQ,mBACN,UACA,UACA,WACQ;EACR,IAAI,OAAO;AACX,MAAI,aAAa,QAAS,SAAQ;AAClC,MAAI,aAAa,YAAY,aAAa,MAAO,SAAQ;AACzD,MAAI,cAAc,aAAc,SAAQ;AACxC,SAAO,KAAK,IAAI,KAAM,KAAK,IAAI,IAAK,OAAO,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { TicketClassifier, TicketClassifierOptions } from "./classifier.js";
2
+ export { TicketClassifier, TicketClassifierOptions };
@@ -0,0 +1,3 @@
1
+ import { TicketClassifier } from "./classifier.js";
2
+
3
+ export { TicketClassifier };
@@ -0,0 +1,77 @@
1
+ import { AgentSpec } from "./ai-agent/src/spec/spec.js";
2
+ import "./ai-agent/src/index.js";
3
+
4
+ //#region src/types.d.ts
5
+ type TicketPriority = 'low' | 'medium' | 'high' | 'urgent';
6
+ type TicketCategory = 'billing' | 'technical' | 'product' | 'account' | 'compliance' | 'other';
7
+ type TicketChannel = 'email' | 'chat' | 'phone' | 'portal';
8
+ type TicketSentiment = 'positive' | 'neutral' | 'negative' | 'frustrated';
9
+ interface SupportTicket {
10
+ id: string;
11
+ subject: string;
12
+ body: string;
13
+ channel: TicketChannel;
14
+ locale?: string;
15
+ customerEmail?: string;
16
+ customerName?: string;
17
+ metadata?: Record<string, string>;
18
+ }
19
+ interface TicketClassification {
20
+ ticketId: string;
21
+ category: TicketCategory;
22
+ priority: TicketPriority;
23
+ sentiment: TicketSentiment;
24
+ intents: string[];
25
+ tags: string[];
26
+ confidence: number;
27
+ escalationRequired?: boolean;
28
+ }
29
+ interface SupportCitation {
30
+ label: string;
31
+ url?: string;
32
+ snippet?: string;
33
+ score?: number;
34
+ }
35
+ interface SupportAction {
36
+ type: 'respond' | 'escalate' | 'refund' | 'manual';
37
+ label: string;
38
+ payload?: Record<string, string>;
39
+ }
40
+ interface SupportResolution {
41
+ ticketId: string;
42
+ answer: string;
43
+ confidence: number;
44
+ citations: SupportCitation[];
45
+ actions: SupportAction[];
46
+ escalationReason?: string;
47
+ knowledgeUpdates?: string[];
48
+ }
49
+ interface SupportResponseDraft {
50
+ ticketId: string;
51
+ subject: string;
52
+ body: string;
53
+ confidence: number;
54
+ requiresEscalation: boolean;
55
+ citations: SupportCitation[];
56
+ }
57
+ interface SupportBotSpec extends AgentSpec {
58
+ thresholds?: {
59
+ autoResolveMinConfidence?: number;
60
+ maxIterations?: number;
61
+ };
62
+ review?: {
63
+ queueName?: string;
64
+ approvalWorkflow?: string;
65
+ };
66
+ }
67
+ interface ClassificationResultPayload {
68
+ ticket: SupportTicket;
69
+ classification: TicketClassification;
70
+ }
71
+ interface ResolutionResultPayload extends ClassificationResultPayload {
72
+ resolution: SupportResolution;
73
+ draft: SupportResponseDraft;
74
+ }
75
+ //#endregion
76
+ export { ClassificationResultPayload, ResolutionResultPayload, SupportAction, SupportBotSpec, SupportCitation, SupportResolution, SupportResponseDraft, SupportTicket, TicketCategory, TicketChannel, TicketClassification, TicketPriority, TicketSentiment };
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;;KAEY,cAAA;KACA,cAAA;KAOA,aAAA;AARA,KASA,eAAA,GATc,UAAA,GAAA,SAAA,GAAA,UAAA,GAAA,YAAA;AACd,UAcK,aAAA,CAdS;EAOd,EAAA,EAAA,MAAA;EACA,OAAA,EAAA,MAAA;EAMK,IAAA,EAAA,MAAA;EAWA,OAAA,EAPN,aAOM;EAEL,MAAA,CAAA,EAAA,MAAA;EACA,aAAA,CAAA,EAAA,MAAA;EACC,YAAA,CAAA,EAAA,MAAA;EAAe,QAAA,CAAA,EAPf,MAOe,CAAA,MAAA,EAAA,MAAA,CAAA;AAO5B;AAOiB,UAlBA,oBAAA,CAqBC;EAGD,QAAA,EAAA,MAAA;EAUA,QAAA,EAhCL,cAgCyB;EASpB,QAAA,EAxCL,cAwCoB;EAWf,SAAA,EAlDJ,eAkDI;EAKA,OAAA,EAAA,MAAA,EAAA;EACH,IAAA,EAAA,MAAA,EAAA;EACL,UAAA,EAAA,MAAA;EAFwC,kBAAA,CAAA,EAAA,OAAA;;UAhDhC,eAAA;;;;;;UAOA,aAAA;;;YAGL;;UAGK,iBAAA;;;;aAIJ;WACF;;;;UAKM,oBAAA;;;;;;aAMJ;;UAGI,cAAA,SAAuB;;;;;;;;;;UAWvB,2BAAA;UACP;kBACQ;;UAGD,uBAAA,SAAgC;cACnC;SACL"}
package/dist/types.js ADDED
File without changes
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@contractspec/lib.support-bot",
3
+ "version": "1.44.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "scripts": {
13
+ "publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
14
+ "publish:pkg:canary": "bun publish:pkg --tag canary",
15
+ "build": "bun build:types && bun build:bundle",
16
+ "build:bundle": "tsdown",
17
+ "build:types": "tsc --noEmit",
18
+ "dev": "bun build:bundle --watch",
19
+ "clean": "rimraf dist .turbo",
20
+ "lint": "bun lint:fix",
21
+ "lint:fix": "eslint src --fix",
22
+ "lint:check": "eslint src",
23
+ "test": "bun run"
24
+ },
25
+ "dependencies": {
26
+ "@contractspec/lib.ai-agent": "1.44.0",
27
+ "@contractspec/lib.contracts": "1.44.0",
28
+ "@contractspec/lib.knowledge": "1.44.0",
29
+ "@contractspec/lib.schema": "1.44.0"
30
+ },
31
+ "devDependencies": {
32
+ "@contractspec/tool.tsdown": "1.44.0",
33
+ "@contractspec/tool.typescript": "1.44.0",
34
+ "tsdown": "^0.18.3",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "exports": {
38
+ ".": "./dist/index.js",
39
+ "./bot": "./dist/bot/index.js",
40
+ "./bot/auto-responder": "./dist/bot/auto-responder.js",
41
+ "./bot/feedback-loop": "./dist/bot/feedback-loop.js",
42
+ "./bot/tools": "./dist/bot/tools.js",
43
+ "./rag": "./dist/rag/index.js",
44
+ "./rag/ticket-resolver": "./dist/rag/ticket-resolver.js",
45
+ "./spec": "./dist/spec.js",
46
+ "./tickets": "./dist/tickets/index.js",
47
+ "./tickets/classifier": "./dist/tickets/classifier.js",
48
+ "./types": "./dist/types.js",
49
+ "./*": "./*"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "exports": {
54
+ ".": "./dist/index.js",
55
+ "./bot": "./dist/bot/index.js",
56
+ "./bot/auto-responder": "./dist/bot/auto-responder.js",
57
+ "./bot/feedback-loop": "./dist/bot/feedback-loop.js",
58
+ "./bot/tools": "./dist/bot/tools.js",
59
+ "./rag": "./dist/rag/index.js",
60
+ "./rag/ticket-resolver": "./dist/rag/ticket-resolver.js",
61
+ "./spec": "./dist/spec.js",
62
+ "./tickets": "./dist/tickets/index.js",
63
+ "./tickets/classifier": "./dist/tickets/classifier.js",
64
+ "./types": "./dist/types.js",
65
+ "./*": "./*"
66
+ },
67
+ "registry": "https://registry.npmjs.org/"
68
+ },
69
+ "license": "MIT",
70
+ "repository": {
71
+ "type": "git",
72
+ "url": "https://github.com/lssm-tech/contractspec.git",
73
+ "directory": "packages/libs/support-bot"
74
+ },
75
+ "homepage": "https://contractspec.io"
76
+ }