@lssm/lib.support-bot 0.4.0 → 0.4.1
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/ai-agent/dist/spec.js +1 -2
- package/dist/bot/auto-responder.d.ts +1 -2
- package/dist/bot/auto-responder.js +1 -2
- package/dist/bot/feedback-loop.d.ts +1 -2
- package/dist/bot/feedback-loop.js +1 -2
- package/dist/bot/tools.d.ts +1 -2
- package/dist/bot/tools.js +1 -2
- package/dist/rag/ticket-resolver.d.ts +1 -2
- package/dist/rag/ticket-resolver.js +1 -2
- package/dist/spec.d.ts +1 -2
- package/dist/spec.js +1 -2
- package/dist/tickets/classifier.d.ts +1 -2
- package/dist/tickets/classifier.js +1 -2
- package/dist/types.d.ts +1 -2
- package/package.json +5 -5
- package/dist/ai-agent/dist/spec.js.map +0 -1
- package/dist/bot/auto-responder.d.ts.map +0 -1
- package/dist/bot/auto-responder.js.map +0 -1
- package/dist/bot/feedback-loop.d.ts.map +0 -1
- package/dist/bot/feedback-loop.js.map +0 -1
- package/dist/bot/tools.d.ts.map +0 -1
- package/dist/bot/tools.js.map +0 -1
- package/dist/rag/ticket-resolver.d.ts.map +0 -1
- package/dist/rag/ticket-resolver.js.map +0 -1
- package/dist/spec.d.ts.map +0 -1
- package/dist/spec.js.map +0 -1
- package/dist/tickets/classifier.d.ts.map +0 -1
- package/dist/tickets/classifier.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
|
@@ -1,2 +1 @@
|
|
|
1
|
-
function e(e){if(!e.meta?.name)throw Error(`Agent name is required`);if(!Number.isFinite(e.meta.version))throw Error(`Agent ${e.meta.name} is missing a numeric version`);if(!e.instructions?.trim())throw Error(`Agent ${e.meta.name} requires instructions`);if(!e.tools?.length)throw Error(`Agent ${e.meta.name} must expose at least one tool`);return Object.freeze(e)}export{e as t};
|
|
2
|
-
//# sourceMappingURL=spec.js.map
|
|
1
|
+
function e(e){if(!e.meta?.name)throw Error(`Agent name is required`);if(!Number.isFinite(e.meta.version))throw Error(`Agent ${e.meta.name} is missing a numeric version`);if(!e.instructions?.trim())throw Error(`Agent ${e.meta.name} requires instructions`);if(!e.tools?.length)throw Error(`Agent ${e.meta.name} must expose at least one tool`);return Object.freeze(e)}export{e as t};
|
|
@@ -15,5 +15,4 @@ ${this.renderCitations(t)}
|
|
|
15
15
|
${this.closing}
|
|
16
16
|
|
|
17
17
|
— ContractSpec Support`;return this.buildDraft(e,t,n,r)}buildDraft(e,t,n,r){return{ticketId:e.id,subject:e.subject.startsWith(`Re:`)?e.subject:`Re: ${e.subject}`,body:r,confidence:Math.min(t.confidence,n.confidence),requiresEscalation:t.actions.some(e=>e.type===`escalate`)||!!n.escalationRequired,citations:t.citations}}renderCategoryIntro(e){switch(e.category){case`billing`:return`I understand billing issues can be stressful, so let me clarify the situation.`;case`technical`:return`I see you encountered a technical issue. Here is what happened and how to fix it.`;case`product`:return`Thanks for sharing feedback about the product. Here are the next steps.`;case`account`:return`Account access is critical, so let me walk you through the resolution.`;case`compliance`:return`Compliance questions require precision. See the policy-aligned answer below.`;default:return`Here is what we found after reviewing your request.`}}renderCitations(e){return e.citations.length?`References:\n${e.citations.map((e,t)=>`- ${e.label||`Source ${t+1}`}${e.url?` (${e.url})`:``}`).join(`
|
|
18
|
-
`)}`:``}};export{e as AutoResponder};
|
|
19
|
-
//# sourceMappingURL=auto-responder.js.map
|
|
18
|
+
`)}`:``}};export{e as AutoResponder};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
var e=class{history=[];responseTimes=new Map;recordResolution(e,t){this.history.push(e),t!=null&&this.responseTimes.set(e.ticket.id,t)}metrics(){let e=this.history.length,t=this.history.filter(e=>!e.resolution.actions.some(e=>e.type===`escalate`)).length,n=e-t,r=e===0?0:this.history.reduce((e,t)=>e+t.resolution.confidence,0)/e,i=this.responseTimes.size===0?0:[...this.responseTimes.values()].reduce((e,t)=>e+t,0)/this.responseTimes.size;return{totalTickets:e,autoResolved:t,escalated:n,avgConfidence:Number(r.toFixed(2)),avgResponseTimeMs:Math.round(i)}}feedbackSummary(e=5){let t=this.history.slice(-e);return t.length?t.map(e=>{let t=e.resolution.actions.some(e=>e.type===`escalate`)?`Escalated`:`Auto-resolved`;return`${e.ticket.subject} – ${t} (confidence: ${e.resolution.confidence})`}).join(`
|
|
2
|
-
`):`No feedback recorded yet.`}};export{e as SupportFeedbackLoop};
|
|
3
|
-
//# sourceMappingURL=feedback-loop.js.map
|
|
2
|
+
`):`No feedback recorded yet.`}};export{e as SupportFeedbackLoop};
|
package/dist/bot/tools.d.ts
CHANGED
|
@@ -11,5 +11,4 @@ interface SupportToolsetOptions {
|
|
|
11
11
|
}
|
|
12
12
|
declare function createSupportTools(options: SupportToolsetOptions): AgentToolDefinitionWithHandler[];
|
|
13
13
|
//#endregion
|
|
14
|
-
export { SupportToolsetOptions, createSupportTools };
|
|
15
|
-
//# sourceMappingURL=tools.d.ts.map
|
|
14
|
+
export { SupportToolsetOptions, createSupportTools };
|
package/dist/bot/tools.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
function e(e){return[{definition:{name:`support_classify_ticket`,description:`Classify a ticket for priority, sentiment, and category`,inputSchema:{type:`object`,required:[`ticket`],properties:{ticket:t}}},handler:async t=>{let r=n(t),i=await e.classifier.classify(r);return{content:JSON.stringify(i),metadata:{ticketId:r.id}}}},{definition:{name:`support_resolve_ticket`,description:`Generate a knowledge-grounded resolution for a ticket`,inputSchema:{type:`object`,required:[`ticket`],properties:{ticket:t}}},handler:async t=>{let r=n(t),i=await e.resolver.resolve(r);return{content:JSON.stringify(i),metadata:{ticketId:r.id}}}},{definition:{name:`support_draft_response`,description:`Draft a user-facing reply based on resolution + classification`,inputSchema:{type:`object`,required:[`ticket`,`resolution`,`classification`],properties:{ticket:t,resolution:{type:`object`},classification:{type:`object`}}}},handler:async t=>{let a=n(t),o=r(t),s=i(t);if(!o||!s)throw Error(`resolution and classification are required`);let c=await e.responder.draft(a,o,s);return{content:JSON.stringify(c),metadata:{ticketId:a.id}}}}]}const t={type:`object`,required:[`id`,`subject`,`body`,`channel`],properties:{id:{type:`string`},subject:{type:`string`},body:{type:`string`},channel:{type:`string`,enum:[`email`,`chat`,`phone`,`portal`]},customerName:{type:`string`},customerEmail:{type:`string`},metadata:{type:`object`}}};function n(e){if(!e||typeof e!=`object`||!(`ticket`in e))throw Error(`Input must include ticket`);let t=e.ticket;if(!t?.id)throw Error(`Ticket is missing id`);return t}function r(e){if(!(!e||typeof e!=`object`||!(`resolution`in e)))return e.resolution}function i(e){if(!(!e||typeof e!=`object`||!(`classification`in e)))return e.classification}export{e as createSupportTools};
|
|
2
|
-
//# sourceMappingURL=tools.js.map
|
|
1
|
+
function e(e){return[{definition:{name:`support_classify_ticket`,description:`Classify a ticket for priority, sentiment, and category`,inputSchema:{type:`object`,required:[`ticket`],properties:{ticket:t}}},handler:async t=>{let r=n(t),i=await e.classifier.classify(r);return{content:JSON.stringify(i),metadata:{ticketId:r.id}}}},{definition:{name:`support_resolve_ticket`,description:`Generate a knowledge-grounded resolution for a ticket`,inputSchema:{type:`object`,required:[`ticket`],properties:{ticket:t}}},handler:async t=>{let r=n(t),i=await e.resolver.resolve(r);return{content:JSON.stringify(i),metadata:{ticketId:r.id}}}},{definition:{name:`support_draft_response`,description:`Draft a user-facing reply based on resolution + classification`,inputSchema:{type:`object`,required:[`ticket`,`resolution`,`classification`],properties:{ticket:t,resolution:{type:`object`},classification:{type:`object`}}}},handler:async t=>{let a=n(t),o=r(t),s=i(t);if(!o||!s)throw Error(`resolution and classification are required`);let c=await e.responder.draft(a,o,s);return{content:JSON.stringify(c),metadata:{ticketId:a.id}}}}]}const t={type:`object`,required:[`id`,`subject`,`body`,`channel`],properties:{id:{type:`string`},subject:{type:`string`},body:{type:`string`},channel:{type:`string`,enum:[`email`,`chat`,`phone`,`portal`]},customerName:{type:`string`},customerEmail:{type:`string`},metadata:{type:`object`}}};function n(e){if(!e||typeof e!=`object`||!(`ticket`in e))throw Error(`Input must include ticket`);let t=e.ticket;if(!t?.id)throw Error(`Ticket is missing id`);return t}function r(e){if(!(!e||typeof e!=`object`||!(`resolution`in e)))return e.resolution}function i(e){if(!(!e||typeof e!=`object`||!(`classification`in e)))return e.classification}export{e as createSupportTools};
|
|
@@ -21,5 +21,4 @@ declare class TicketResolver {
|
|
|
21
21
|
private deriveConfidence;
|
|
22
22
|
}
|
|
23
23
|
//#endregion
|
|
24
|
-
export { KnowledgeRetriever, TicketResolver, TicketResolverOptions };
|
|
25
|
-
//# sourceMappingURL=ticket-resolver.d.ts.map
|
|
24
|
+
export { KnowledgeRetriever, TicketResolver, TicketResolverOptions };
|
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
var e=class{knowledge;minConfidence;prependPrompt;constructor(e){this.knowledge=e.knowledge,this.minConfidence=e.minConfidence??.65,this.prependPrompt=e.prependPrompt}async resolve(e){let t=this.buildQuestion(e),n=await this.knowledge.query(t);return this.toResolution(e,n)}buildQuestion(e){let t=[`Subject: ${e.subject}`,`Channel: ${e.channel}`];return e.customerName&&t.push(`Customer: ${e.customerName}`),[this.prependPrompt,t.join(`
|
|
2
2
|
`),`---`,e.body].filter(Boolean).join(`
|
|
3
|
-
`)}toResolution(e,t){let n=t.references.map(e=>({label:typeof e.payload?.title==`string`?e.payload.title:typeof e.payload?.documentId==`string`?e.payload.documentId:e.id,url:typeof e.payload?.url==`string`?e.payload.url:void 0,snippet:typeof e.payload?.text==`string`?e.payload.text.slice(0,280):void 0,score:e.score})),r=this.deriveConfidence(t),i=r<this.minConfidence||n.length===0;return{ticketId:e.id,answer:t.answer,confidence:r,citations:n,actions:[i?{type:`escalate`,label:`Escalate for human review`}:{type:`respond`,label:`Send automated response`}],escalationReason:i?`Insufficient confidence or missing knowledge references`:void 0,knowledgeUpdates:i?[e.body.slice(0,200)]:void 0}}deriveConfidence(e){if(!e.references.length)return .3;let t=e.references[0]?.score??.4,n=Math.min(1,Math.max(0,t)),r=e.usage?.completionTokens?Math.min(e.usage.completionTokens/1e3,.2):0;return Number((n-r).toFixed(2))}};export{e as TicketResolver};
|
|
4
|
-
//# sourceMappingURL=ticket-resolver.js.map
|
|
3
|
+
`)}toResolution(e,t){let n=t.references.map(e=>({label:typeof e.payload?.title==`string`?e.payload.title:typeof e.payload?.documentId==`string`?e.payload.documentId:e.id,url:typeof e.payload?.url==`string`?e.payload.url:void 0,snippet:typeof e.payload?.text==`string`?e.payload.text.slice(0,280):void 0,score:e.score})),r=this.deriveConfidence(t),i=r<this.minConfidence||n.length===0;return{ticketId:e.id,answer:t.answer,confidence:r,citations:n,actions:[i?{type:`escalate`,label:`Escalate for human review`}:{type:`respond`,label:`Send automated response`}],escalationReason:i?`Insufficient confidence or missing knowledge references`:void 0,knowledgeUpdates:i?[e.body.slice(0,200)]:void 0}}deriveConfidence(e){if(!e.references.length)return .3;let t=e.references[0]?.score??.4,n=Math.min(1,Math.max(0,t)),r=e.usage?.completionTokens?Math.min(e.usage.completionTokens/1e3,.2):0;return Number((n-r).toFixed(2))}};export{e as TicketResolver};
|
package/dist/spec.d.ts
CHANGED
|
@@ -9,5 +9,4 @@ interface SupportBotDefinition {
|
|
|
9
9
|
}
|
|
10
10
|
declare function defineSupportBot(definition: SupportBotDefinition): SupportBotSpec;
|
|
11
11
|
//#endregion
|
|
12
|
-
export { SupportBotDefinition, defineSupportBot };
|
|
13
|
-
//# sourceMappingURL=spec.d.ts.map
|
|
12
|
+
export { SupportBotDefinition, defineSupportBot };
|
package/dist/spec.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
import{t as e}from"./ai-agent/dist/spec.js";import"./ai-agent/dist/index.js";function t(t){return{...e({...t.base,policy:{...t.base.policy,confidence:{min:t.base.policy?.confidence?.min??.7,default:t.base.policy?.confidence?.default??.6},escalation:{confidenceThreshold:t.autoEscalateThreshold??t.base.policy?.escalation?.confidenceThreshold??t.base.policy?.confidence?.min??.7,...t.base.policy?.escalation}},memory:t.base.memory??{maxEntries:120,ttlMinutes:120},tools:t.tools??t.base.tools,instructions:`${t.base.instructions}\n\nAlways cite support knowledge sources and flag compliance/billing issues for human review when unsure.`}),thresholds:{autoResolveMinConfidence:t.autoEscalateThreshold??.75,maxIterations:6}}}export{t as defineSupportBot};
|
|
2
|
-
//# sourceMappingURL=spec.js.map
|
|
1
|
+
import{t as e}from"./ai-agent/dist/spec.js";import"./ai-agent/dist/index.js";function t(t){return{...e({...t.base,policy:{...t.base.policy,confidence:{min:t.base.policy?.confidence?.min??.7,default:t.base.policy?.confidence?.default??.6},escalation:{confidenceThreshold:t.autoEscalateThreshold??t.base.policy?.escalation?.confidenceThreshold??t.base.policy?.confidence?.min??.7,...t.base.policy?.escalation}},memory:t.base.memory??{maxEntries:120,ttlMinutes:120},tools:t.tools??t.base.tools,instructions:`${t.base.instructions}\n\nAlways cite support knowledge sources and flag compliance/billing issues for human review when unsure.`}),thresholds:{autoResolveMinConfidence:t.autoEscalateThreshold??.75,maxIterations:6}}}export{t as defineSupportBot};
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
const e={billing:[`invoice`,`payout`,`refund`,`charge`,`billing`,`payment`],technical:[`bug`,`error`,`crash`,`issue`,`failed`,`timeout`],product:[`feature`,`roadmap`,`idea`,`request`,`feedback`],account:[`login`,`password`,`2fa`,`account`,`profile`,`email change`],compliance:[`kyc`,`aml`,`compliance`,`regulation`,`gdpr`],other:[]},t={urgent:[`urgent`,`asap`,`immediately`,`today`,`right away`],high:[`high priority`,`blocking`,`major`,`critical`],medium:[`soon`,`next few days`],low:[`nice to have`,`when possible`,`later`]},n={positive:[`love`,`great`,`awesome`,`thank you`],neutral:[`question`,`wonder`,`curious`],negative:[`unhappy`,`bad`,`terrible`,`awful`,`angry`],frustrated:[`furious`,`frustrated`,`fed up`,`ridiculous`]};var r=class{keywords;llm;llmModel;constructor(t){this.keywords={...e,...t?.keywords??{}},this.llm=t?.llm,this.llmModel=t?.llmModel}async classify(e){let t=this.heuristicClassification(e);if(!this.llm)return t;try{let n=(await this.llm.chat([{role:`system`,content:[{type:`text`,text:`Classify the support ticket.`}]},{role:`user`,content:[{type:`text`,text:JSON.stringify({subject:e.subject,body:e.body,channel:e.channel})}]}],{responseFormat:`json`,model:this.llmModel})).message.content.find(e=>`text`in e);if(n&&`text`in n){let e=JSON.parse(n.text);return{...t,...e,intents:e.intents??t.intents,tags:e.tags??t.tags}}}catch{}return t}heuristicClassification(e){let t=`${e.subject}\n${e.body}`.toLowerCase(),n=this.detectCategory(t),r=this.detectPriority(t),i=this.detectSentiment(t),a=this.extractIntents(t),o=a.slice(0,3),s=this.estimateConfidence(n,r,i);return{ticketId:e.id,category:n,priority:r,sentiment:i,intents:a,tags:o,confidence:s,escalationRequired:r===`urgent`||n===`compliance`}}detectCategory(e){for(let[t,n]of Object.entries(this.keywords))if(n.some(t=>e.includes(t)))return t;return`other`}detectPriority(e){for(let n of[`urgent`,`high`,`medium`,`low`])if(t[n].some(t=>e.includes(t)))return n;return`medium`}detectSentiment(e){for(let t of[`frustrated`,`negative`,`neutral`,`positive`])if(n[t].some(t=>e.includes(t)))return t;return`neutral`}extractIntents(e){let t=[];return(e.includes(`refund`)||e.includes(`chargeback`))&&t.push(`refund`),e.includes(`payout`)&&t.push(`payout`),e.includes(`login`)&&t.push(`login-help`),e.includes(`feature`)&&t.push(`feature-request`),(e.includes(`bug`)||e.includes(`error`))&&t.push(`bug-report`),t.length?t:[`general`]}estimateConfidence(e,t,n){let r=.6;return e!==`other`&&(r+=.1),(t===`urgent`||t===`low`)&&(r+=.05),n===`frustrated`&&(r-=.05),Math.min(.95,Math.max(.4,Number(r.toFixed(2))))}};export{r as TicketClassifier};
|
|
2
|
-
//# sourceMappingURL=classifier.js.map
|
|
1
|
+
const e={billing:[`invoice`,`payout`,`refund`,`charge`,`billing`,`payment`],technical:[`bug`,`error`,`crash`,`issue`,`failed`,`timeout`],product:[`feature`,`roadmap`,`idea`,`request`,`feedback`],account:[`login`,`password`,`2fa`,`account`,`profile`,`email change`],compliance:[`kyc`,`aml`,`compliance`,`regulation`,`gdpr`],other:[]},t={urgent:[`urgent`,`asap`,`immediately`,`today`,`right away`],high:[`high priority`,`blocking`,`major`,`critical`],medium:[`soon`,`next few days`],low:[`nice to have`,`when possible`,`later`]},n={positive:[`love`,`great`,`awesome`,`thank you`],neutral:[`question`,`wonder`,`curious`],negative:[`unhappy`,`bad`,`terrible`,`awful`,`angry`],frustrated:[`furious`,`frustrated`,`fed up`,`ridiculous`]};var r=class{keywords;llm;llmModel;constructor(t){this.keywords={...e,...t?.keywords??{}},this.llm=t?.llm,this.llmModel=t?.llmModel}async classify(e){let t=this.heuristicClassification(e);if(!this.llm)return t;try{let n=(await this.llm.chat([{role:`system`,content:[{type:`text`,text:`Classify the support ticket.`}]},{role:`user`,content:[{type:`text`,text:JSON.stringify({subject:e.subject,body:e.body,channel:e.channel})}]}],{responseFormat:`json`,model:this.llmModel})).message.content.find(e=>`text`in e);if(n&&`text`in n){let e=JSON.parse(n.text);return{...t,...e,intents:e.intents??t.intents,tags:e.tags??t.tags}}}catch{}return t}heuristicClassification(e){let t=`${e.subject}\n${e.body}`.toLowerCase(),n=this.detectCategory(t),r=this.detectPriority(t),i=this.detectSentiment(t),a=this.extractIntents(t),o=a.slice(0,3),s=this.estimateConfidence(n,r,i);return{ticketId:e.id,category:n,priority:r,sentiment:i,intents:a,tags:o,confidence:s,escalationRequired:r===`urgent`||n===`compliance`}}detectCategory(e){for(let[t,n]of Object.entries(this.keywords))if(n.some(t=>e.includes(t)))return t;return`other`}detectPriority(e){for(let n of[`urgent`,`high`,`medium`,`low`])if(t[n].some(t=>e.includes(t)))return n;return`medium`}detectSentiment(e){for(let t of[`frustrated`,`negative`,`neutral`,`positive`])if(n[t].some(t=>e.includes(t)))return t;return`neutral`}extractIntents(e){let t=[];return(e.includes(`refund`)||e.includes(`chargeback`))&&t.push(`refund`),e.includes(`payout`)&&t.push(`payout`),e.includes(`login`)&&t.push(`login-help`),e.includes(`feature`)&&t.push(`feature-request`),(e.includes(`bug`)||e.includes(`error`))&&t.push(`bug-report`),t.length?t:[`general`]}estimateConfidence(e,t,n){let r=.6;return e!==`other`&&(r+=.1),(t===`urgent`||t===`low`)&&(r+=.05),n===`frustrated`&&(r-=.05),Math.min(.95,Math.max(.4,Number(r.toFixed(2))))}};export{r as TicketClassifier};
|
package/dist/types.d.ts
CHANGED
|
@@ -72,5 +72,4 @@ interface ResolutionResultPayload extends ClassificationResultPayload {
|
|
|
72
72
|
draft: SupportResponseDraft;
|
|
73
73
|
}
|
|
74
74
|
//#endregion
|
|
75
|
-
export { ClassificationResultPayload, ResolutionResultPayload, SupportAction, SupportBotSpec, SupportCitation, SupportResolution, SupportResponseDraft, SupportTicket, TicketCategory, TicketChannel, TicketClassification, TicketPriority, TicketSentiment };
|
|
76
|
-
//# sourceMappingURL=types.d.ts.map
|
|
75
|
+
export { ClassificationResultPayload, ResolutionResultPayload, SupportAction, SupportBotSpec, SupportCitation, SupportResolution, SupportResponseDraft, SupportTicket, TicketCategory, TicketChannel, TicketClassification, TicketPriority, TicketSentiment };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/lib.support-bot",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
"test": "bun run"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@lssm/lib.ai-agent": "^0.4.
|
|
26
|
-
"@lssm/lib.contracts": "^1.11.
|
|
25
|
+
"@lssm/lib.ai-agent": "^0.4.1",
|
|
26
|
+
"@lssm/lib.contracts": "^1.11.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@lssm/tool.tsdown": "0.12.
|
|
30
|
-
"@lssm/tool.typescript": "0.11.
|
|
29
|
+
"@lssm/tool.tsdown": "0.12.1",
|
|
30
|
+
"@lssm/tool.typescript": "0.11.1",
|
|
31
31
|
"tsdown": "^0.16.6",
|
|
32
32
|
"typescript": "^5.9.3"
|
|
33
33
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","names":[],"sources":["../../../../ai-agent/dist/spec.js"],"sourcesContent":["const e=e=>`${e.name}.v${e.version}`;function t(e){if(!e.meta?.name)throw Error(`Agent name is required`);if(!Number.isFinite(e.meta.version))throw Error(`Agent ${e.meta.name} is missing a numeric version`);if(!e.instructions?.trim())throw Error(`Agent ${e.meta.name} requires instructions`);if(!e.tools?.length)throw Error(`Agent ${e.meta.name} must expose at least one tool`);return Object.freeze(e)}var n=class{specs=new Map;register(t){let n=e(t.meta);if(this.specs.has(n))throw Error(`Duplicate agent spec registered for ${n}`);return this.specs.set(n,t),this}list(){return[...this.specs.values()]}get(e,t){if(t!=null)return this.specs.get(`${e}.v${t}`);let n,r=-1/0;for(let t of this.specs.values())t.meta.name===e&&t.meta.version>r&&(n=t,r=t.meta.version);return n}require(e,t){let n=this.get(e,t);if(!n)throw Error(`Agent spec not found for ${e}${t?`.v${t}`:``}`);return n}};export{n as AgentRegistry,t as defineAgent};\n//# sourceMappingURL=spec.js.map"],"mappings":"AAAqC,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,KAAK,MAAM,MAAM,yBAAyB,CAAC,GAAG,CAAC,OAAO,SAAS,EAAE,KAAK,QAAQ,CAAC,MAAM,MAAM,SAAS,EAAE,KAAK,KAAK,+BAA+B,CAAC,GAAG,CAAC,EAAE,cAAc,MAAM,CAAC,MAAM,MAAM,SAAS,EAAE,KAAK,KAAK,wBAAwB,CAAC,GAAG,CAAC,EAAE,OAAO,OAAO,MAAM,MAAM,SAAS,EAAE,KAAK,KAAK,gCAAgC,CAAC,OAAO,OAAO,OAAO,EAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-responder.d.ts","names":[],"sources":["../../src/bot/auto-responder.ts"],"sourcesContent":[],"mappings":";;;;UAQiB,oBAAA;QACT;EADS,KAAA,CAAA,EAAA,MAAA;EAOJ,IAAA,CAAA,EAAA,UAAa,GAAA,QAAA;EAMF,OAAA,CAAA,EAAA,MAAA;;AAaR,cAnBH,aAAA,CAmBG;EACI,iBAAA,GAAA;EACP,iBAAA,KAAA;EAAR,iBAAA,IAAA;EAAO,iBAAA,OAAA;wBAfY;gBAYZ,2BACI,mCACI,uBACf,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-responder.js","names":[],"sources":["../../src/bot/auto-responder.ts"],"sourcesContent":["import type { LLMProvider } from '@lssm/lib.contracts/integrations/providers/llm';\nimport type {\n SupportResponseDraft,\n SupportResolution,\n SupportTicket,\n TicketClassification,\n} from '../types';\n\nexport interface AutoResponderOptions {\n llm?: LLMProvider;\n model?: string;\n tone?: 'friendly' | 'formal';\n closing?: string;\n}\n\nexport class AutoResponder {\n private readonly llm?: LLMProvider;\n private readonly model?: string;\n private readonly tone: 'friendly' | 'formal';\n private readonly closing: string;\n\n constructor(options?: AutoResponderOptions) {\n this.llm = options?.llm;\n this.model = options?.model;\n this.tone = options?.tone ?? 'friendly';\n this.closing =\n options?.closing ??\n (this.tone === 'friendly'\n ? 'We remain available if you need anything else.'\n : 'Please let us know if you require additional assistance.');\n }\n\n async draft(\n ticket: SupportTicket,\n resolution: SupportResolution,\n classification: TicketClassification\n ): Promise<SupportResponseDraft> {\n if (this.llm) {\n return this.generateWithLLM(ticket, resolution, classification);\n }\n return this.generateTemplate(ticket, resolution, classification);\n }\n\n private async generateWithLLM(\n ticket: SupportTicket,\n resolution: SupportResolution,\n classification: TicketClassification\n ): Promise<SupportResponseDraft> {\n const prompt = `You are a ${this.tone} support agent. Draft an email response.\nTicket Subject: ${ticket.subject}\nTicket Body: ${ticket.body}\nDetected Category: ${classification.category}\nDetected Priority: ${classification.priority}\nResolution:\n${resolution.answer}\nCitations: ${resolution.citations.map((c) => c.label).join(', ')}`;\n\n const response = await this.llm!.chat(\n [\n {\n role: 'system',\n content: [\n {\n type: 'text',\n text: 'Write empathetic, accurate support replies that cite sources when relevant.',\n },\n ],\n },\n {\n role: 'user',\n content: [{ type: 'text', text: prompt }],\n },\n ],\n { model: this.model }\n );\n\n const body = response.message.content\n .map((part) => ('text' in part ? part.text : ''))\n .join('')\n .trim();\n\n return this.buildDraft(ticket, resolution, classification, body);\n }\n\n private generateTemplate(\n ticket: SupportTicket,\n resolution: SupportResolution,\n classification: TicketClassification\n ): SupportResponseDraft {\n const greeting = ticket.customerName\n ? `Hi ${ticket.customerName},`\n : 'Hi there,';\n const body = `${greeting}\n\nThanks for contacting us about \"${ticket.subject}\". ${this.renderCategoryIntro(\n classification\n )}\n\n${resolution.answer}\n\n${this.renderCitations(resolution)}\n${this.closing}\n\n— ContractSpec Support`;\n\n return this.buildDraft(ticket, resolution, classification, body);\n }\n\n private buildDraft(\n ticket: SupportTicket,\n resolution: SupportResolution,\n classification: TicketClassification,\n body: string\n ): SupportResponseDraft {\n return {\n ticketId: ticket.id,\n subject: ticket.subject.startsWith('Re:')\n ? ticket.subject\n : `Re: ${ticket.subject}`,\n body,\n confidence: Math.min(resolution.confidence, classification.confidence),\n requiresEscalation:\n resolution.actions.some((action) => action.type === 'escalate') ||\n Boolean(classification.escalationRequired),\n citations: resolution.citations,\n };\n }\n\n private renderCategoryIntro(classification: TicketClassification) {\n switch (classification.category) {\n case 'billing':\n return 'I understand billing issues can be stressful, so let me clarify the situation.';\n case 'technical':\n return 'I see you encountered a technical issue. Here is what happened and how to fix it.';\n case 'product':\n return 'Thanks for sharing feedback about the product. Here are the next steps.';\n case 'account':\n return 'Account access is critical, so let me walk you through the resolution.';\n case 'compliance':\n return 'Compliance questions require precision. See the policy-aligned answer below.';\n default:\n return 'Here is what we found after reviewing your request.';\n }\n }\n\n private renderCitations(resolution: SupportResolution) {\n if (!resolution.citations.length) return '';\n const lines = resolution.citations.map((citation, index) => {\n const label = citation.label || `Source ${index + 1}`;\n const link = citation.url ? ` (${citation.url})` : '';\n return `- ${label}${link}`;\n });\n return `References:\\n${lines.join('\\n')}`;\n }\n}\n"],"mappings":"AAeA,IAAa,EAAb,KAA2B,CACzB,IACA,MACA,KACA,QAEA,YAAY,EAAgC,CAC1C,KAAK,IAAM,GAAS,IACpB,KAAK,MAAQ,GAAS,MACtB,KAAK,KAAO,GAAS,MAAQ,WAC7B,KAAK,QACH,GAAS,UACR,KAAK,OAAS,WACX,iDACA,4DAGR,MAAM,MACJ,EACA,EACA,EAC+B,CAI/B,OAHI,KAAK,IACA,KAAK,gBAAgB,EAAQ,EAAY,EAAe,CAE1D,KAAK,iBAAiB,EAAQ,EAAY,EAAe,CAGlE,MAAc,gBACZ,EACA,EACA,EAC+B,CAC/B,IAAM,EAAS,aAAa,KAAK,KAAK;kBACxB,EAAO,QAAQ;eAClB,EAAO,KAAK;qBACN,EAAe,SAAS;qBACxB,EAAe,SAAS;;EAE3C,EAAW,OAAO;aACP,EAAW,UAAU,IAAK,GAAM,EAAE,MAAM,CAAC,KAAK,KAAK,GAqBtD,GAnBW,MAAM,KAAK,IAAK,KAC/B,CACE,CACE,KAAM,SACN,QAAS,CACP,CACE,KAAM,OACN,KAAM,8EACP,CACF,CACF,CACD,CACE,KAAM,OACN,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAQ,CAAC,CAC1C,CACF,CACD,CAAE,MAAO,KAAK,MAAO,CACtB,EAEqB,QAAQ,QAC3B,IAAK,GAAU,SAAU,EAAO,EAAK,KAAO,GAAI,CAChD,KAAK,GAAG,CACR,MAAM,CAET,OAAO,KAAK,WAAW,EAAQ,EAAY,EAAgB,EAAK,CAGlE,iBACE,EACA,EACA,EACsB,CAItB,IAAM,EAAO,GAHI,EAAO,aACpB,MAAM,EAAO,aAAa,GAC1B,YACqB;;kCAEK,EAAO,QAAQ,KAAK,KAAK,oBACrD,EACD,CAAC;;EAEJ,EAAW,OAAO;;EAElB,KAAK,gBAAgB,EAAW,CAAC;EACjC,KAAK,QAAQ;;wBAIX,OAAO,KAAK,WAAW,EAAQ,EAAY,EAAgB,EAAK,CAGlE,WACE,EACA,EACA,EACA,EACsB,CACtB,MAAO,CACL,SAAU,EAAO,GACjB,QAAS,EAAO,QAAQ,WAAW,MAAM,CACrC,EAAO,QACP,OAAO,EAAO,UAClB,OACA,WAAY,KAAK,IAAI,EAAW,WAAY,EAAe,WAAW,CACtE,mBACE,EAAW,QAAQ,KAAM,GAAW,EAAO,OAAS,WAAW,EAC/D,EAAQ,EAAe,mBACzB,UAAW,EAAW,UACvB,CAGH,oBAA4B,EAAsC,CAChE,OAAQ,EAAe,SAAvB,CACE,IAAK,UACH,MAAO,iFACT,IAAK,YACH,MAAO,oFACT,IAAK,UACH,MAAO,0EACT,IAAK,UACH,MAAO,yEACT,IAAK,aACH,MAAO,+EACT,QACE,MAAO,uDAIb,gBAAwB,EAA+B,CAOrD,OANK,EAAW,UAAU,OAMnB,gBALO,EAAW,UAAU,KAAK,EAAU,IAGzC,KAFO,EAAS,OAAS,UAAU,EAAQ,MACrC,EAAS,IAAM,KAAK,EAAS,IAAI,GAAK,KAEnD,CAC2B,KAAK;EAAK,GANE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"feedback-loop.d.ts","names":[],"sources":["../../src/bot/feedback-loop.ts"],"sourcesContent":[],"mappings":";;;UAEiB,eAAA;;EAAA,YAAA,EAAA,MAAe;EAQnB,SAAA,EAAA,MAAA;;;;cAAA,mBAAA;;;4BAIe;aAOf"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"feedback-loop.js","names":[],"sources":["../../src/bot/feedback-loop.ts"],"sourcesContent":["import type { ResolutionResultPayload } from '../types';\n\nexport interface FeedbackMetrics {\n totalTickets: number;\n autoResolved: number;\n escalated: number;\n avgConfidence: number;\n avgResponseTimeMs: number;\n}\n\nexport class SupportFeedbackLoop {\n private readonly history: ResolutionResultPayload[] = [];\n private readonly responseTimes = new Map<string, number>();\n\n recordResolution(payload: ResolutionResultPayload, responseTimeMs?: number) {\n this.history.push(payload);\n if (responseTimeMs != null) {\n this.responseTimes.set(payload.ticket.id, responseTimeMs);\n }\n }\n\n metrics(): FeedbackMetrics {\n const total = this.history.length;\n const autoResolved = this.history.filter(\n (entry) =>\n !entry.resolution.actions.some((action) => action.type === 'escalate')\n ).length;\n const escalated = total - autoResolved;\n const avgConfidence =\n total === 0\n ? 0\n : this.history.reduce(\n (sum, entry) => sum + entry.resolution.confidence,\n 0\n ) / total;\n const avgResponseTimeMs =\n this.responseTimes.size === 0\n ? 0\n : [...this.responseTimes.values()].reduce((a, b) => a + b, 0) /\n this.responseTimes.size;\n\n return {\n totalTickets: total,\n autoResolved,\n escalated,\n avgConfidence: Number(avgConfidence.toFixed(2)),\n avgResponseTimeMs: Math.round(avgResponseTimeMs),\n };\n }\n\n feedbackSummary(limit = 5): string {\n const recent = this.history.slice(-limit);\n if (!recent.length) return 'No feedback recorded yet.';\n return recent\n .map((entry) => {\n const status = entry.resolution.actions.some(\n (action) => action.type === 'escalate'\n )\n ? 'Escalated'\n : 'Auto-resolved';\n return `${entry.ticket.subject} – ${status} (confidence: ${entry.resolution.confidence})`;\n })\n .join('\\n');\n }\n}\n"],"mappings":"AAUA,IAAa,EAAb,KAAiC,CAC/B,QAAsD,EAAE,CACxD,cAAiC,IAAI,IAErC,iBAAiB,EAAkC,EAAyB,CAC1E,KAAK,QAAQ,KAAK,EAAQ,CACtB,GAAkB,MACpB,KAAK,cAAc,IAAI,EAAQ,OAAO,GAAI,EAAe,CAI7D,SAA2B,CACzB,IAAM,EAAQ,KAAK,QAAQ,OACrB,EAAe,KAAK,QAAQ,OAC/B,GACC,CAAC,EAAM,WAAW,QAAQ,KAAM,GAAW,EAAO,OAAS,WAAW,CACzE,CAAC,OACI,EAAY,EAAQ,EACpB,EACJ,IAAU,EACN,EACA,KAAK,QAAQ,QACV,EAAK,IAAU,EAAM,EAAM,WAAW,WACvC,EACD,CAAG,EACJ,EACJ,KAAK,cAAc,OAAS,EACxB,EACA,CAAC,GAAG,KAAK,cAAc,QAAQ,CAAC,CAAC,QAAQ,EAAG,IAAM,EAAI,EAAG,EAAE,CAC3D,KAAK,cAAc,KAEzB,MAAO,CACL,aAAc,EACd,eACA,YACA,cAAe,OAAO,EAAc,QAAQ,EAAE,CAAC,CAC/C,kBAAmB,KAAK,MAAM,EAAkB,CACjD,CAGH,gBAAgB,EAAQ,EAAW,CACjC,IAAM,EAAS,KAAK,QAAQ,MAAM,CAAC,EAAM,CAEzC,OADK,EAAO,OACL,EACJ,IAAK,GAAU,CACd,IAAM,EAAS,EAAM,WAAW,QAAQ,KACrC,GAAW,EAAO,OAAS,WAC7B,CACG,YACA,gBACJ,MAAO,GAAG,EAAM,OAAO,QAAQ,KAAK,EAAO,gBAAgB,EAAM,WAAW,WAAW,IACvF,CACD,KAAK;EAAK,CAVc"}
|
package/dist/bot/tools.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","names":[],"sources":["../../src/bot/tools.ts"],"sourcesContent":[],"mappings":";;;;;;UAUiB,qBAAA;YACL;EADK,UAAA,EAEH,gBAFwB;EAC1B,SAAA,EAEC,aAFD;;AAEC,iBAGG,kBAAA,CAHH,OAAA,EAIF,qBAJE,CAAA,EAKV,8BALU,EAAA"}
|
package/dist/bot/tools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","names":[],"sources":["../../src/bot/tools.ts"],"sourcesContent":["import type { AgentToolDefinitionWithHandler } from '@lssm/lib.ai-agent';\nimport type { TicketResolver } from '../rag/ticket-resolver';\nimport type { TicketClassifier } from '../tickets/classifier';\nimport type { AutoResponder } from './auto-responder';\nimport type {\n SupportTicket,\n SupportResolution,\n TicketClassification,\n} from '../types';\n\nexport interface SupportToolsetOptions {\n resolver: TicketResolver;\n classifier: TicketClassifier;\n responder: AutoResponder;\n}\n\nexport function createSupportTools(\n options: SupportToolsetOptions\n): AgentToolDefinitionWithHandler[] {\n const classifyTool: AgentToolDefinitionWithHandler = {\n definition: {\n name: 'support_classify_ticket',\n description: 'Classify a ticket for priority, sentiment, and category',\n inputSchema: {\n type: 'object',\n required: ['ticket'],\n properties: {\n ticket: ticketSchema,\n },\n },\n },\n handler: async (input: unknown) => {\n const ticket = ensureTicket(input);\n const classification = await options.classifier.classify(ticket);\n return {\n content: JSON.stringify(classification),\n metadata: { ticketId: ticket.id },\n };\n },\n };\n\n const resolveTool: AgentToolDefinitionWithHandler = {\n definition: {\n name: 'support_resolve_ticket',\n description: 'Generate a knowledge-grounded resolution for a ticket',\n inputSchema: {\n type: 'object',\n required: ['ticket'],\n properties: {\n ticket: ticketSchema,\n },\n },\n },\n handler: async (input: unknown) => {\n const ticket = ensureTicket(input);\n const resolution = await options.resolver.resolve(ticket);\n return {\n content: JSON.stringify(resolution),\n metadata: { ticketId: ticket.id },\n };\n },\n };\n\n const responderTool: AgentToolDefinitionWithHandler = {\n definition: {\n name: 'support_draft_response',\n description:\n 'Draft a user-facing reply based on resolution + classification',\n inputSchema: {\n type: 'object',\n required: ['ticket', 'resolution', 'classification'],\n properties: {\n ticket: ticketSchema,\n resolution: { type: 'object' },\n classification: { type: 'object' },\n },\n },\n },\n handler: async (input: unknown) => {\n const ticket = ensureTicket(input);\n const resolution = extractResolution(input);\n const classification = extractClassification(input);\n if (!resolution || !classification) {\n throw new Error('resolution and classification are required');\n }\n const draft = await options.responder.draft(\n ticket,\n resolution,\n classification\n );\n return {\n content: JSON.stringify(draft),\n metadata: { ticketId: ticket.id },\n };\n },\n };\n\n return [classifyTool, resolveTool, responderTool];\n}\n\nconst ticketSchema = {\n type: 'object',\n required: ['id', 'subject', 'body', 'channel'],\n properties: {\n id: { type: 'string' },\n subject: { type: 'string' },\n body: { type: 'string' },\n channel: { type: 'string', enum: ['email', 'chat', 'phone', 'portal'] },\n customerName: { type: 'string' },\n customerEmail: { type: 'string' },\n metadata: { type: 'object' },\n },\n};\n\nfunction ensureTicket(input: unknown): SupportTicket {\n if (!input || typeof input !== 'object' || !('ticket' in input)) {\n throw new Error('Input must include ticket');\n }\n const ticket = (input as { ticket: SupportTicket }).ticket;\n if (!ticket?.id) throw new Error('Ticket is missing id');\n return ticket;\n}\n\nfunction extractResolution(input: unknown): SupportResolution | undefined {\n if (!input || typeof input !== 'object' || !('resolution' in input))\n return undefined;\n return (input as { resolution?: SupportResolution }).resolution;\n}\n\nfunction extractClassification(\n input: unknown\n): TicketClassification | undefined {\n if (!input || typeof input !== 'object' || !('classification' in input))\n return undefined;\n return (input as { classification?: TicketClassification }).classification;\n}\n"],"mappings":"AAgBA,SAAgB,EACd,EACkC,CA+ElC,MAAO,CA9E8C,CACnD,WAAY,CACV,KAAM,0BACN,YAAa,0DACb,YAAa,CACX,KAAM,SACN,SAAU,CAAC,SAAS,CACpB,WAAY,CACV,OAAQ,EACT,CACF,CACF,CACD,QAAS,KAAO,IAAmB,CACjC,IAAM,EAAS,EAAa,EAAM,CAC5B,EAAiB,MAAM,EAAQ,WAAW,SAAS,EAAO,CAChE,MAAO,CACL,QAAS,KAAK,UAAU,EAAe,CACvC,SAAU,CAAE,SAAU,EAAO,GAAI,CAClC,EAEJ,CAEmD,CAClD,WAAY,CACV,KAAM,yBACN,YAAa,wDACb,YAAa,CACX,KAAM,SACN,SAAU,CAAC,SAAS,CACpB,WAAY,CACV,OAAQ,EACT,CACF,CACF,CACD,QAAS,KAAO,IAAmB,CACjC,IAAM,EAAS,EAAa,EAAM,CAC5B,EAAa,MAAM,EAAQ,SAAS,QAAQ,EAAO,CACzD,MAAO,CACL,QAAS,KAAK,UAAU,EAAW,CACnC,SAAU,CAAE,SAAU,EAAO,GAAI,CAClC,EAEJ,CAEqD,CACpD,WAAY,CACV,KAAM,yBACN,YACE,iEACF,YAAa,CACX,KAAM,SACN,SAAU,CAAC,SAAU,aAAc,iBAAiB,CACpD,WAAY,CACV,OAAQ,EACR,WAAY,CAAE,KAAM,SAAU,CAC9B,eAAgB,CAAE,KAAM,SAAU,CACnC,CACF,CACF,CACD,QAAS,KAAO,IAAmB,CACjC,IAAM,EAAS,EAAa,EAAM,CAC5B,EAAa,EAAkB,EAAM,CACrC,EAAiB,EAAsB,EAAM,CACnD,GAAI,CAAC,GAAc,CAAC,EAClB,MAAU,MAAM,6CAA6C,CAE/D,IAAM,EAAQ,MAAM,EAAQ,UAAU,MACpC,EACA,EACA,EACD,CACD,MAAO,CACL,QAAS,KAAK,UAAU,EAAM,CAC9B,SAAU,CAAE,SAAU,EAAO,GAAI,CAClC,EAEJ,CAEgD,CAGnD,MAAM,EAAe,CACnB,KAAM,SACN,SAAU,CAAC,KAAM,UAAW,OAAQ,UAAU,CAC9C,WAAY,CACV,GAAI,CAAE,KAAM,SAAU,CACtB,QAAS,CAAE,KAAM,SAAU,CAC3B,KAAM,CAAE,KAAM,SAAU,CACxB,QAAS,CAAE,KAAM,SAAU,KAAM,CAAC,QAAS,OAAQ,QAAS,SAAS,CAAE,CACvE,aAAc,CAAE,KAAM,SAAU,CAChC,cAAe,CAAE,KAAM,SAAU,CACjC,SAAU,CAAE,KAAM,SAAU,CAC7B,CACF,CAED,SAAS,EAAa,EAA+B,CACnD,GAAI,CAAC,GAAS,OAAO,GAAU,UAAY,EAAE,WAAY,GACvD,MAAU,MAAM,4BAA4B,CAE9C,IAAM,EAAU,EAAoC,OACpD,GAAI,CAAC,GAAQ,GAAI,MAAU,MAAM,uBAAuB,CACxD,OAAO,EAGT,SAAS,EAAkB,EAA+C,CACpE,MAAC,GAAS,OAAO,GAAU,UAAY,EAAE,eAAgB,IAE7D,OAAQ,EAA6C,WAGvD,SAAS,EACP,EACkC,CAC9B,MAAC,GAAS,OAAO,GAAU,UAAY,EAAE,mBAAoB,IAEjE,OAAQ,EAAoD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ticket-resolver.d.ts","names":[],"sources":["../../src/rag/ticket-resolver.ts"],"sourcesContent":[],"mappings":";;;;UAGiB,kBAAA;2BACU,QAAQ;AADnC;AAIiB,UAAA,qBAAA,CAAqB;EAMzB,SAAA,EALA,kBAKc;EAKJ,aAAA,CAAA,EAAA,MAAA;EAMC,aAAA,CAAA,EAAA,MAAA;;AAAgB,cAX3B,cAAA,CAW2B;EAAO,iBAAA,SAAA;;;uBANxB;kBAMC,gBAAgB,QAAQ"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ticket-resolver.js","names":[],"sources":["../../src/rag/ticket-resolver.ts"],"sourcesContent":["import type { KnowledgeAnswer } from '@lssm/lib.contracts/knowledge/query/service';\nimport type { SupportResolution, SupportTicket } from '../types';\n\nexport interface KnowledgeRetriever {\n query(question: string): Promise<KnowledgeAnswer>;\n}\n\nexport interface TicketResolverOptions {\n knowledge: KnowledgeRetriever;\n minConfidence?: number;\n prependPrompt?: string;\n}\n\nexport class TicketResolver {\n private readonly knowledge: KnowledgeRetriever;\n private readonly minConfidence: number;\n private readonly prependPrompt?: string;\n\n constructor(options: TicketResolverOptions) {\n this.knowledge = options.knowledge;\n this.minConfidence = options.minConfidence ?? 0.65;\n this.prependPrompt = options.prependPrompt;\n }\n\n async resolve(ticket: SupportTicket): Promise<SupportResolution> {\n const question = this.buildQuestion(ticket);\n const answer = await this.knowledge.query(question);\n return this.toResolution(ticket, answer);\n }\n\n private buildQuestion(ticket: SupportTicket): string {\n const header = [`Subject: ${ticket.subject}`, `Channel: ${ticket.channel}`];\n if (ticket.customerName) header.push(`Customer: ${ticket.customerName}`);\n const sections = [\n this.prependPrompt,\n header.join('\\n'),\n '---',\n ticket.body,\n ].filter(Boolean);\n return sections.join('\\n');\n }\n\n private toResolution(\n ticket: SupportTicket,\n answer: KnowledgeAnswer\n ): SupportResolution {\n const citations = answer.references.map((ref) => {\n const label =\n typeof ref.payload?.title === 'string'\n ? ref.payload.title\n : typeof ref.payload?.documentId === 'string'\n ? ref.payload.documentId\n : ref.id;\n return {\n label,\n url: typeof ref.payload?.url === 'string' ? ref.payload.url : undefined,\n snippet:\n typeof ref.payload?.text === 'string'\n ? ref.payload.text.slice(0, 280)\n : undefined,\n score: ref.score,\n };\n });\n\n const confidence = this.deriveConfidence(answer);\n const escalate = confidence < this.minConfidence || citations.length === 0;\n\n return {\n ticketId: ticket.id,\n answer: answer.answer,\n confidence,\n citations,\n actions: [\n escalate\n ? { type: 'escalate', label: 'Escalate for human review' }\n : { type: 'respond', label: 'Send automated response' },\n ],\n escalationReason: escalate\n ? 'Insufficient confidence or missing knowledge references'\n : undefined,\n knowledgeUpdates: escalate ? [ticket.body.slice(0, 200)] : undefined,\n };\n }\n\n private deriveConfidence(answer: KnowledgeAnswer): number {\n if (!answer.references.length) return 0.3;\n const topScore = answer.references[0]?.score ?? 0.4;\n const normalized = Math.min(1, Math.max(0, topScore));\n const tokenPenalty = answer.usage?.completionTokens\n ? Math.min(answer.usage.completionTokens / 1000, 0.2)\n : 0;\n return Number((normalized - tokenPenalty).toFixed(2));\n }\n}\n"],"mappings":"AAaA,IAAa,EAAb,KAA4B,CAC1B,UACA,cACA,cAEA,YAAY,EAAgC,CAC1C,KAAK,UAAY,EAAQ,UACzB,KAAK,cAAgB,EAAQ,eAAiB,IAC9C,KAAK,cAAgB,EAAQ,cAG/B,MAAM,QAAQ,EAAmD,CAC/D,IAAM,EAAW,KAAK,cAAc,EAAO,CACrC,EAAS,MAAM,KAAK,UAAU,MAAM,EAAS,CACnD,OAAO,KAAK,aAAa,EAAQ,EAAO,CAG1C,cAAsB,EAA+B,CACnD,IAAM,EAAS,CAAC,YAAY,EAAO,UAAW,YAAY,EAAO,UAAU,CAQ3E,OAPI,EAAO,cAAc,EAAO,KAAK,aAAa,EAAO,eAAe,CACvD,CACf,KAAK,cACL,EAAO,KAAK;EAAK,CACjB,MACA,EAAO,KACR,CAAC,OAAO,QAAQ,CACD,KAAK;EAAK,CAG5B,aACE,EACA,EACmB,CACnB,IAAM,EAAY,EAAO,WAAW,IAAK,IAOhC,CACL,MANA,OAAO,EAAI,SAAS,OAAU,SAC1B,EAAI,QAAQ,MACZ,OAAO,EAAI,SAAS,YAAe,SACjC,EAAI,QAAQ,WACZ,EAAI,GAGV,IAAK,OAAO,EAAI,SAAS,KAAQ,SAAW,EAAI,QAAQ,IAAM,IAAA,GAC9D,QACE,OAAO,EAAI,SAAS,MAAS,SACzB,EAAI,QAAQ,KAAK,MAAM,EAAG,IAAI,CAC9B,IAAA,GACN,MAAO,EAAI,MACZ,EACD,CAEI,EAAa,KAAK,iBAAiB,EAAO,CAC1C,EAAW,EAAa,KAAK,eAAiB,EAAU,SAAW,EAEzE,MAAO,CACL,SAAU,EAAO,GACjB,OAAQ,EAAO,OACf,aACA,YACA,QAAS,CACP,EACI,CAAE,KAAM,WAAY,MAAO,4BAA6B,CACxD,CAAE,KAAM,UAAW,MAAO,0BAA2B,CAC1D,CACD,iBAAkB,EACd,0DACA,IAAA,GACJ,iBAAkB,EAAW,CAAC,EAAO,KAAK,MAAM,EAAG,IAAI,CAAC,CAAG,IAAA,GAC5D,CAGH,iBAAyB,EAAiC,CACxD,GAAI,CAAC,EAAO,WAAW,OAAQ,MAAO,IACtC,IAAM,EAAW,EAAO,WAAW,IAAI,OAAS,GAC1C,EAAa,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,EAAS,CAAC,CAC/C,EAAe,EAAO,OAAO,iBAC/B,KAAK,IAAI,EAAO,MAAM,iBAAmB,IAAM,GAAI,CACnD,EACJ,OAAO,QAAQ,EAAa,GAAc,QAAQ,EAAE,CAAC"}
|
package/dist/spec.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","names":[],"sources":["../src/spec.ts"],"sourcesContent":[],"mappings":";;;;UAIiB,oBAAA;QACT;EADS,KAAA,CAAA,EAEP,eAF2B,EAAA;EAMrB,qBAAgB,CAAA,EAAA,MAClB;;iBADE,gBAAA,aACF,uBACX"}
|
package/dist/spec.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"spec.js","names":["defineAgent"],"sources":["../src/spec.ts"],"sourcesContent":["import type { AgentSpec, AgentToolConfig } from '@lssm/lib.ai-agent';\nimport { defineAgent } from '@lssm/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":"6EAUA,SAAgB,EACd,EACgB,CAuBhB,MAAO,CACL,GAvBWA,EAAY,CACvB,GAAG,EAAW,KACd,OAAQ,CACN,GAAG,EAAW,KAAK,OACnB,WAAY,CACV,IAAK,EAAW,KAAK,QAAQ,YAAY,KAAO,GAChD,QAAS,EAAW,KAAK,QAAQ,YAAY,SAAW,GACzD,CACD,WAAY,CACV,oBACE,EAAW,uBACX,EAAW,KAAK,QAAQ,YAAY,qBACpC,EAAW,KAAK,QAAQ,YAAY,KACpC,GACF,GAAG,EAAW,KAAK,QAAQ,WAC5B,CACF,CACD,OAAQ,EAAW,KAAK,QAAU,CAAE,WAAY,IAAK,WAAY,IAAK,CACtE,MAAO,EAAW,OAAS,EAAW,KAAK,MAC3C,aAAc,GAAG,EAAW,KAAK,aAAa,4GAC/C,CAAC,CAIA,WAAY,CACV,yBAA0B,EAAW,uBAAyB,IAC9D,cAAe,EAChB,CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1 +0,0 @@
|
|
|
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 '@lssm/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":"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"}
|
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../src/types.ts"],"sourcesContent":[],"mappings":";;;KAEY,cAAA;KACA,cAAA;AADA,KAQA,aAAA,GARc,OAAA,GAAA,MAAA,GAAA,OAAA,GAAA,QAAA;AACd,KAQA,eAAA,GARc,UAAA,GAAA,SAAA,GAAA,UAAA,GAAA,YAAA;AAOd,UAOK,aAAA,CAPQ;EACb,EAAA,EAAA,MAAA;EAMK,OAAA,EAAA,MAAA;EAWA,IAAA,EAAA,MAAA;EAEL,OAAA,EATD,aASC;EACA,MAAA,CAAA,EAAA,MAAA;EACC,aAAA,CAAA,EAAA,MAAA;EAAe,YAAA,CAAA,EAAA,MAAA;EAOX,QAAA,CAAA,EAdJ,MAcI,CAAe,MAAA,EAAA,MAAA,CAAA;AAOhC;AAMiB,UAxBA,oBAAA,CA4BJ;EAMI,QAAA,EAAA,MAAA;EASA,QAAA,EAzCL,cAyCoB;EAWf,QAAA,EAnDL,cAmDK;EAKA,SAAA,EAvDJ,eAuD4B;EAC3B,OAAA,EAAA,MAAA,EAAA;EACL,IAAA,EAAA,MAAA,EAAA;EAFwC,UAAA,EAAA,MAAA;EAA2B,kBAAA,CAAA,EAAA,OAAA;;UAhD3D,eAAA;;;;;;UAOA,aAAA;;;YAGL;;UAGK,iBAAA;;;;aAIJ;WACF;;;;UAKM,oBAAA;;;;;;aAMJ;;UAGI,cAAA,SAAuB;;;;;;;;;;UAWvB,2BAAA;UACP;kBACQ;;UAGD,uBAAA,SAAgC;cACnC;SACL"}
|