@ddse/acm-examples 0.5.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/LICENSE +21 -0
- package/README.md +113 -0
- package/bin/acm-demo.ts +495 -0
- package/data/coaching/agents.json +16 -0
- package/data/coaching/transcripts.json +37 -0
- package/data/documents.json +72 -0
- package/data/entitlement/customers.json +38 -0
- package/data/entitlement/policies.json +38 -0
- package/data/incidents/incidents.json +30 -0
- package/data/incidents/routing_rules.json +36 -0
- package/data/invoices/invoices.json +38 -0
- package/data/invoices/purchase-orders.json +38 -0
- package/data/issues.json +99 -0
- package/data/knowledge/docs/kb-001.md +7 -0
- package/data/knowledge/docs/kb-002.md +7 -0
- package/data/knowledge/docs/kb-003.md +9 -0
- package/data/knowledge/index.json +25 -0
- package/data/orders.json +106 -0
- package/dist/bin/acm-demo.d.ts +3 -0
- package/dist/bin/acm-demo.d.ts.map +1 -0
- package/dist/bin/acm-demo.js +392 -0
- package/dist/bin/acm-demo.js.map +1 -0
- package/dist/src/context/directives.d.ts +3 -0
- package/dist/src/context/directives.d.ts.map +1 -0
- package/dist/src/context/directives.js +325 -0
- package/dist/src/context/directives.js.map +1 -0
- package/dist/src/context/index.d.ts +2 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +2 -0
- package/dist/src/context/index.js.map +1 -0
- package/dist/src/data/coaching.d.ts +19 -0
- package/dist/src/data/coaching.d.ts.map +1 -0
- package/dist/src/data/coaching.js +22 -0
- package/dist/src/data/coaching.js.map +1 -0
- package/dist/src/data/entitlement.d.ts +25 -0
- package/dist/src/data/entitlement.d.ts.map +1 -0
- package/dist/src/data/entitlement.js +26 -0
- package/dist/src/data/entitlement.js.map +1 -0
- package/dist/src/data/incidents.d.ts +23 -0
- package/dist/src/data/incidents.d.ts.map +1 -0
- package/dist/src/data/incidents.js +37 -0
- package/dist/src/data/incidents.js.map +1 -0
- package/dist/src/data/invoices.d.ts +34 -0
- package/dist/src/data/invoices.d.ts.map +1 -0
- package/dist/src/data/invoices.js +49 -0
- package/dist/src/data/invoices.js.map +1 -0
- package/dist/src/data/knowledge.d.ts +11 -0
- package/dist/src/data/knowledge.d.ts.map +1 -0
- package/dist/src/data/knowledge.js +57 -0
- package/dist/src/data/knowledge.js.map +1 -0
- package/dist/src/data/loader.d.ts +4 -0
- package/dist/src/data/loader.d.ts.map +1 -0
- package/dist/src/data/loader.js +69 -0
- package/dist/src/data/loader.js.map +1 -0
- package/dist/src/examples/scenarios.d.ts +23 -0
- package/dist/src/examples/scenarios.d.ts.map +1 -0
- package/dist/src/examples/scenarios.js +609 -0
- package/dist/src/examples/scenarios.js.map +1 -0
- package/dist/src/goals/index.d.ts +8 -0
- package/dist/src/goals/index.d.ts.map +1 -0
- package/dist/src/goals/index.js +12 -0
- package/dist/src/goals/index.js.map +1 -0
- package/dist/src/policy.d.ts +5 -0
- package/dist/src/policy.d.ts.map +1 -0
- package/dist/src/policy.js +24 -0
- package/dist/src/policy.js.map +1 -0
- package/dist/src/registries.d.ts +18 -0
- package/dist/src/registries.d.ts.map +1 -0
- package/dist/src/registries.js +38 -0
- package/dist/src/registries.js.map +1 -0
- package/dist/src/renderer.d.ts +9 -0
- package/dist/src/renderer.d.ts.map +1 -0
- package/dist/src/renderer.js +76 -0
- package/dist/src/renderer.js.map +1 -0
- package/dist/src/search/bm25.d.ts +68 -0
- package/dist/src/search/bm25.d.ts.map +1 -0
- package/dist/src/search/bm25.js +131 -0
- package/dist/src/search/bm25.js.map +1 -0
- package/dist/src/search/index.d.ts +2 -0
- package/dist/src/search/index.d.ts.map +1 -0
- package/dist/src/search/index.js +3 -0
- package/dist/src/search/index.js.map +1 -0
- package/dist/src/tasks/coaching.d.ts +30 -0
- package/dist/src/tasks/coaching.d.ts.map +1 -0
- package/dist/src/tasks/coaching.js +143 -0
- package/dist/src/tasks/coaching.js.map +1 -0
- package/dist/src/tasks/entitlement.d.ts +29 -0
- package/dist/src/tasks/entitlement.d.ts.map +1 -0
- package/dist/src/tasks/entitlement.js +135 -0
- package/dist/src/tasks/entitlement.js.map +1 -0
- package/dist/src/tasks/incidents.d.ts +42 -0
- package/dist/src/tasks/incidents.d.ts.map +1 -0
- package/dist/src/tasks/incidents.js +189 -0
- package/dist/src/tasks/incidents.js.map +1 -0
- package/dist/src/tasks/index.d.ts +7 -0
- package/dist/src/tasks/index.d.ts.map +1 -0
- package/dist/src/tasks/index.js +7 -0
- package/dist/src/tasks/index.js.map +1 -0
- package/dist/src/tasks/invoices.d.ts +40 -0
- package/dist/src/tasks/invoices.d.ts.map +1 -0
- package/dist/src/tasks/invoices.js +180 -0
- package/dist/src/tasks/invoices.js.map +1 -0
- package/dist/src/tasks/knowledge.d.ts +23 -0
- package/dist/src/tasks/knowledge.d.ts.map +1 -0
- package/dist/src/tasks/knowledge.js +115 -0
- package/dist/src/tasks/knowledge.js.map +1 -0
- package/dist/src/tasks/legacy.d.ts +50 -0
- package/dist/src/tasks/legacy.d.ts.map +1 -0
- package/dist/src/tasks/legacy.js +85 -0
- package/dist/src/tasks/legacy.js.map +1 -0
- package/dist/src/tools/coaching/index.d.ts +49 -0
- package/dist/src/tools/coaching/index.d.ts.map +1 -0
- package/dist/src/tools/coaching/index.js +119 -0
- package/dist/src/tools/coaching/index.js.map +1 -0
- package/dist/src/tools/entitlement/index.d.ts +52 -0
- package/dist/src/tools/entitlement/index.d.ts.map +1 -0
- package/dist/src/tools/entitlement/index.js +120 -0
- package/dist/src/tools/entitlement/index.js.map +1 -0
- package/dist/src/tools/incidents/index.d.ts +55 -0
- package/dist/src/tools/incidents/index.d.ts.map +1 -0
- package/dist/src/tools/incidents/index.js +109 -0
- package/dist/src/tools/incidents/index.js.map +1 -0
- package/dist/src/tools/index.d.ts +90 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +109 -0
- package/dist/src/tools/index.js.map +1 -0
- package/dist/src/tools/invoices/index.d.ts +56 -0
- package/dist/src/tools/invoices/index.d.ts.map +1 -0
- package/dist/src/tools/invoices/index.js +85 -0
- package/dist/src/tools/invoices/index.js.map +1 -0
- package/dist/src/tools/knowledge/index.d.ts +52 -0
- package/dist/src/tools/knowledge/index.d.ts.map +1 -0
- package/dist/src/tools/knowledge/index.js +120 -0
- package/dist/src/tools/knowledge/index.js.map +1 -0
- package/dist/tests/bm25.test.d.ts +2 -0
- package/dist/tests/bm25.test.d.ts.map +1 -0
- package/dist/tests/bm25.test.js +98 -0
- package/dist/tests/bm25.test.js.map +1 -0
- package/dist/tests/integration.test.d.ts +2 -0
- package/dist/tests/integration.test.d.ts.map +1 -0
- package/dist/tests/integration.test.js +126 -0
- package/dist/tests/integration.test.js.map +1 -0
- package/dist/tests/plan-hydration.test.d.ts +2 -0
- package/dist/tests/plan-hydration.test.d.ts.map +1 -0
- package/dist/tests/plan-hydration.test.js +28 -0
- package/dist/tests/plan-hydration.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/examples-architecture.md +144 -0
- package/docs/successrun.md +1022 -0
- package/package.json +33 -0
- package/src/context/directives.ts +366 -0
- package/src/context/index.ts +1 -0
- package/src/data/coaching.ts +50 -0
- package/src/data/entitlement.ts +60 -0
- package/src/data/incidents.ts +78 -0
- package/src/data/invoices.ts +103 -0
- package/src/data/knowledge.ts +77 -0
- package/src/data/loader.ts +80 -0
- package/src/examples/scenarios.ts +724 -0
- package/src/goals/index.ts +18 -0
- package/src/policy.ts +30 -0
- package/src/registries.ts +48 -0
- package/src/renderer.ts +82 -0
- package/src/search/bm25.ts +173 -0
- package/src/search/index.ts +2 -0
- package/src/tasks/coaching.ts +217 -0
- package/src/tasks/entitlement.ts +197 -0
- package/src/tasks/incidents.ts +277 -0
- package/src/tasks/index.ts +6 -0
- package/src/tasks/invoices.ts +269 -0
- package/src/tasks/knowledge.ts +169 -0
- package/src/tasks/legacy.ts +112 -0
- package/src/tools/coaching/index.ts +197 -0
- package/src/tools/entitlement/index.ts +199 -0
- package/src/tools/incidents/index.ts +185 -0
- package/src/tools/index.ts +192 -0
- package/src/tools/invoices/index.ts +165 -0
- package/src/tools/knowledge/index.ts +203 -0
- package/tests/bm25.test.ts +129 -0
- package/tests/integration.test.ts +163 -0
- package/tests/plan-hydration.test.ts +33 -0
- package/tsconfig.json +18 -0
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddse/acm-examples",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "ACM v0.5 Examples - CLI demo and sample implementations",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"acm-demo": "./dist/bin/acm-demo.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@ddse/acm-framework": "0.5.0",
|
|
11
|
+
"@ddse/acm-sdk": "0.5.0",
|
|
12
|
+
"@ddse/acm-planner": "0.5.0",
|
|
13
|
+
"@ddse/acm-runtime": "0.5.0",
|
|
14
|
+
"@ddse/acm-mcp": "0.5.0",
|
|
15
|
+
"@ddse/acm-llm": "0.5.0",
|
|
16
|
+
"@ddse/acm-adapters": "0.5.0",
|
|
17
|
+
"@ddse/acm-replay": "0.5.0"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"acm",
|
|
21
|
+
"examples",
|
|
22
|
+
"cli"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"clean": "rm -rf dist",
|
|
28
|
+
"dev": "tsc --watch",
|
|
29
|
+
"demo": "node ./dist/bin/acm-demo.js",
|
|
30
|
+
"test": "node ./dist/tests/integration.test.js && node ./dist/tests/plan-hydration.test.js",
|
|
31
|
+
"test:bm25": "node ./dist/tests/bm25.test.js"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { ExternalContextProviderAdapter, Tool, type ContextRetrievalArtifact } from '@ddse/acm-sdk';
|
|
2
|
+
import { getCustomerProfile, getPolicy } from '../data/entitlement.js';
|
|
3
|
+
import { getSnippetMeta, loadSnippetContent } from '../data/knowledge.js';
|
|
4
|
+
import { getIncident, findRoutingRule } from '../data/incidents.js';
|
|
5
|
+
import { getInvoice, getPurchaseOrder } from '../data/invoices.js';
|
|
6
|
+
import { getTranscript, getAgent } from '../data/coaching.js';
|
|
7
|
+
|
|
8
|
+
function extractPayload(directive: string): string | Record<string, any> | undefined {
|
|
9
|
+
const separator = directive.indexOf(':');
|
|
10
|
+
if (separator < 0) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const raw = directive.slice(separator + 1).trim();
|
|
15
|
+
if (!raw) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (raw.startsWith('{')) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return raw;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
abstract class ContextTool<I> extends Tool<I, ContextRetrievalArtifact[]> {
|
|
31
|
+
async call(input: I): Promise<ContextRetrievalArtifact[]> {
|
|
32
|
+
const artifacts = await this.produceArtifacts(input);
|
|
33
|
+
return Array.isArray(artifacts) ? artifacts : [artifacts];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected abstract produceArtifacts(input: I): Promise<ContextRetrievalArtifact | ContextRetrievalArtifact[]>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class CustomerContextTool extends ContextTool<{ customerId: string }> {
|
|
40
|
+
name(): string {
|
|
41
|
+
return 'crm';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected async produceArtifacts(input: { customerId: string }): Promise<ContextRetrievalArtifact> {
|
|
45
|
+
const customer = await getCustomerProfile(input.customerId);
|
|
46
|
+
if (!customer) {
|
|
47
|
+
throw new Error(`Customer ${input.customerId} not found`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
type: 'crm.customer',
|
|
52
|
+
content: customer,
|
|
53
|
+
promote: true,
|
|
54
|
+
provenance: {
|
|
55
|
+
tool: this.name(),
|
|
56
|
+
customerId: input.customerId,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
class PolicyContextTool extends ContextTool<{ benefitCode: string }> {
|
|
63
|
+
name(): string {
|
|
64
|
+
return 'policy';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected async produceArtifacts(input: { benefitCode: string }): Promise<ContextRetrievalArtifact> {
|
|
68
|
+
const policy = await getPolicy(input.benefitCode);
|
|
69
|
+
if (!policy) {
|
|
70
|
+
throw new Error(`Policy ${input.benefitCode} not found`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
type: 'crm.policy',
|
|
75
|
+
content: policy,
|
|
76
|
+
promote: true,
|
|
77
|
+
provenance: {
|
|
78
|
+
tool: this.name(),
|
|
79
|
+
benefitCode: input.benefitCode,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class KnowledgeContextTool extends ContextTool<{ docId: string }> {
|
|
86
|
+
name(): string {
|
|
87
|
+
return 'kb';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
protected async produceArtifacts(input: { docId: string }): Promise<ContextRetrievalArtifact[]> {
|
|
91
|
+
const [meta, content] = await Promise.all([
|
|
92
|
+
getSnippetMeta(input.docId),
|
|
93
|
+
loadSnippetContent(input.docId),
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
if (!meta || !content) {
|
|
97
|
+
throw new Error(`Knowledge doc ${input.docId} not found`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
type: 'kb.meta',
|
|
103
|
+
content: meta,
|
|
104
|
+
promote: true,
|
|
105
|
+
provenance: {
|
|
106
|
+
tool: this.name(),
|
|
107
|
+
docId: input.docId,
|
|
108
|
+
stage: 'metadata',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
type: 'kb.content',
|
|
113
|
+
content: content,
|
|
114
|
+
promote: false,
|
|
115
|
+
provenance: {
|
|
116
|
+
tool: this.name(),
|
|
117
|
+
docId: input.docId,
|
|
118
|
+
stage: 'content',
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
class IncidentContextTool extends ContextTool<{ incidentId: string }> {
|
|
126
|
+
name(): string {
|
|
127
|
+
return 'inc';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
protected async produceArtifacts(input: { incidentId: string }): Promise<ContextRetrievalArtifact> {
|
|
131
|
+
const incident = await getIncident(input.incidentId);
|
|
132
|
+
if (!incident) {
|
|
133
|
+
throw new Error(`Incident ${input.incidentId} not found`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
type: 'incident.record',
|
|
138
|
+
content: incident,
|
|
139
|
+
promote: true,
|
|
140
|
+
provenance: {
|
|
141
|
+
tool: this.name(),
|
|
142
|
+
incidentId: input.incidentId,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
class RoutingContextTool extends ContextTool<{ incidentId: string; severity?: string }> {
|
|
149
|
+
name(): string {
|
|
150
|
+
return 'routing';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
protected async produceArtifacts(input: { incidentId: string; severity?: string }): Promise<ContextRetrievalArtifact> {
|
|
154
|
+
const incident = await getIncident(input.incidentId);
|
|
155
|
+
if (!incident) {
|
|
156
|
+
throw new Error(`Incident ${input.incidentId} not found for routing lookup`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const rule = await findRoutingRule(incident, input.severity as any);
|
|
160
|
+
if (!rule) {
|
|
161
|
+
throw new Error(`Routing rule not found for incident ${input.incidentId}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
type: 'incident.routing_rule',
|
|
166
|
+
content: rule,
|
|
167
|
+
promote: true,
|
|
168
|
+
provenance: {
|
|
169
|
+
tool: this.name(),
|
|
170
|
+
incidentId: input.incidentId,
|
|
171
|
+
severity: input.severity,
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
class InvoiceContextTool extends ContextTool<{ invoiceId: string }> {
|
|
178
|
+
name(): string {
|
|
179
|
+
return 'erp';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
protected async produceArtifacts(input: { invoiceId: string }): Promise<ContextRetrievalArtifact[]> {
|
|
183
|
+
const invoice = await getInvoice(input.invoiceId);
|
|
184
|
+
if (!invoice) {
|
|
185
|
+
throw new Error(`Invoice ${input.invoiceId} not found`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const purchaseOrder = invoice.purchaseOrderId
|
|
189
|
+
? await getPurchaseOrder(invoice.purchaseOrderId)
|
|
190
|
+
: undefined;
|
|
191
|
+
|
|
192
|
+
const artifacts: ContextRetrievalArtifact[] = [
|
|
193
|
+
{
|
|
194
|
+
type: 'erp.invoice',
|
|
195
|
+
content: invoice,
|
|
196
|
+
promote: true,
|
|
197
|
+
provenance: {
|
|
198
|
+
tool: this.name(),
|
|
199
|
+
stage: 'invoice',
|
|
200
|
+
invoiceId: input.invoiceId,
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
if (purchaseOrder) {
|
|
206
|
+
artifacts.push({
|
|
207
|
+
type: 'erp.purchase_order',
|
|
208
|
+
content: purchaseOrder,
|
|
209
|
+
promote: true,
|
|
210
|
+
provenance: {
|
|
211
|
+
tool: this.name(),
|
|
212
|
+
stage: 'purchase-order',
|
|
213
|
+
invoiceId: input.invoiceId,
|
|
214
|
+
purchaseOrderId: purchaseOrder.id,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return artifacts;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
class TranscriptContextTool extends ContextTool<{ transcriptId: string }> {
|
|
224
|
+
name(): string {
|
|
225
|
+
return 'transcript';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
protected async produceArtifacts(input: { transcriptId: string }): Promise<ContextRetrievalArtifact[]> {
|
|
229
|
+
const transcript = await getTranscript(input.transcriptId);
|
|
230
|
+
if (!transcript) {
|
|
231
|
+
throw new Error(`Transcript ${input.transcriptId} not found`);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const agent = await getAgent(transcript.agentId);
|
|
235
|
+
|
|
236
|
+
const artifacts: ContextRetrievalArtifact[] = [
|
|
237
|
+
{
|
|
238
|
+
type: 'coaching.transcript',
|
|
239
|
+
content: transcript,
|
|
240
|
+
promote: true,
|
|
241
|
+
provenance: {
|
|
242
|
+
tool: this.name(),
|
|
243
|
+
transcriptId: input.transcriptId,
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
];
|
|
247
|
+
|
|
248
|
+
if (agent) {
|
|
249
|
+
artifacts.push({
|
|
250
|
+
type: 'coaching.agent',
|
|
251
|
+
content: agent,
|
|
252
|
+
promote: true,
|
|
253
|
+
provenance: {
|
|
254
|
+
tool: this.name(),
|
|
255
|
+
transcriptId: input.transcriptId,
|
|
256
|
+
stage: 'agent-profile',
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return artifacts;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function registerExampleContextProviders(adapter: ExternalContextProviderAdapter): void {
|
|
266
|
+
const customerTool = new CustomerContextTool();
|
|
267
|
+
adapter.register(customerTool, {
|
|
268
|
+
match: directive => directive.startsWith('crm:'),
|
|
269
|
+
buildInput: directive => {
|
|
270
|
+
const payload = extractPayload(directive);
|
|
271
|
+
if (typeof payload !== 'string') {
|
|
272
|
+
throw new Error(`crm directive expects customer id payload, got ${JSON.stringify(payload)}`);
|
|
273
|
+
}
|
|
274
|
+
return { customerId: payload };
|
|
275
|
+
},
|
|
276
|
+
describe: 'CRM customer profile loader',
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
const policyTool = new PolicyContextTool();
|
|
280
|
+
adapter.register(policyTool, {
|
|
281
|
+
match: directive => directive.startsWith('policy:'),
|
|
282
|
+
buildInput: directive => {
|
|
283
|
+
const payload = extractPayload(directive);
|
|
284
|
+
if (typeof payload !== 'string') {
|
|
285
|
+
throw new Error(`policy directive expects benefit code payload`);
|
|
286
|
+
}
|
|
287
|
+
return { benefitCode: payload };
|
|
288
|
+
},
|
|
289
|
+
describe: 'Entitlement policy lookup',
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const knowledgeTool = new KnowledgeContextTool();
|
|
293
|
+
adapter.register(knowledgeTool, {
|
|
294
|
+
match: directive => directive.startsWith('kb:'),
|
|
295
|
+
buildInput: directive => {
|
|
296
|
+
const payload = extractPayload(directive);
|
|
297
|
+
if (typeof payload !== 'string') {
|
|
298
|
+
throw new Error(`kb directive expects document id payload`);
|
|
299
|
+
}
|
|
300
|
+
return { docId: payload };
|
|
301
|
+
},
|
|
302
|
+
autoPromote: false,
|
|
303
|
+
describe: 'Knowledge base snippet fetcher',
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const incidentTool = new IncidentContextTool();
|
|
307
|
+
adapter.register(incidentTool, {
|
|
308
|
+
match: directive => directive.startsWith('inc:'),
|
|
309
|
+
buildInput: directive => {
|
|
310
|
+
const payload = extractPayload(directive);
|
|
311
|
+
if (typeof payload !== 'string') {
|
|
312
|
+
throw new Error('inc directive expects incident id payload');
|
|
313
|
+
}
|
|
314
|
+
return { incidentId: payload };
|
|
315
|
+
},
|
|
316
|
+
describe: 'Incident record retrieval',
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const routingTool = new RoutingContextTool();
|
|
320
|
+
adapter.register(routingTool, {
|
|
321
|
+
match: directive => directive.startsWith('routing:'),
|
|
322
|
+
buildInput: directive => {
|
|
323
|
+
const payload = extractPayload(directive);
|
|
324
|
+
if (typeof payload === 'string') {
|
|
325
|
+
return { incidentId: payload };
|
|
326
|
+
}
|
|
327
|
+
if (payload && typeof payload === 'object' && typeof payload.incidentId === 'string') {
|
|
328
|
+
return {
|
|
329
|
+
incidentId: payload.incidentId,
|
|
330
|
+
severity: typeof payload.severity === 'string' ? payload.severity : undefined,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
throw new Error('routing directive expects incident id payload');
|
|
334
|
+
},
|
|
335
|
+
describe: 'Routing rule lookup',
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const invoiceTool = new InvoiceContextTool();
|
|
339
|
+
adapter.register(invoiceTool, {
|
|
340
|
+
match: directive => directive.startsWith('erp:'),
|
|
341
|
+
buildInput: directive => {
|
|
342
|
+
const payload = extractPayload(directive);
|
|
343
|
+
if (typeof payload === 'string') {
|
|
344
|
+
return { invoiceId: payload };
|
|
345
|
+
}
|
|
346
|
+
if (payload && typeof payload === 'object' && typeof payload.invoiceId === 'string') {
|
|
347
|
+
return { invoiceId: payload.invoiceId };
|
|
348
|
+
}
|
|
349
|
+
throw new Error('erp directive expects invoice id payload');
|
|
350
|
+
},
|
|
351
|
+
describe: 'ERP invoice + purchase order fetcher',
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const transcriptTool = new TranscriptContextTool();
|
|
355
|
+
adapter.register(transcriptTool, {
|
|
356
|
+
match: directive => directive.startsWith('transcript:'),
|
|
357
|
+
buildInput: directive => {
|
|
358
|
+
const payload = extractPayload(directive);
|
|
359
|
+
if (typeof payload !== 'string') {
|
|
360
|
+
throw new Error('transcript directive expects transcript id payload');
|
|
361
|
+
}
|
|
362
|
+
return { transcriptId: payload };
|
|
363
|
+
},
|
|
364
|
+
describe: 'Contact center transcript loader',
|
|
365
|
+
});
|
|
366
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registerExampleContextProviders } from './directives.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { loadJson } from './loader.js';
|
|
2
|
+
|
|
3
|
+
export interface CoachingTranscript {
|
|
4
|
+
id: string;
|
|
5
|
+
agentId: string;
|
|
6
|
+
customerSentiment: 'POSITIVE' | 'NEUTRAL' | 'NEGATIVE';
|
|
7
|
+
complianceFlags: string[];
|
|
8
|
+
transcript: string[];
|
|
9
|
+
callDurationSeconds: number;
|
|
10
|
+
followUpRequired: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface AgentProfile {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
region: string;
|
|
17
|
+
tenureMonths: number;
|
|
18
|
+
managerEmail: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface CoachingData {
|
|
22
|
+
transcripts: CoachingTranscript[];
|
|
23
|
+
agents: AgentProfile[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let cache: CoachingData | null = null;
|
|
27
|
+
|
|
28
|
+
async function loadData(): Promise<CoachingData> {
|
|
29
|
+
if (cache) {
|
|
30
|
+
return cache;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const [transcripts, agents] = await Promise.all([
|
|
34
|
+
loadJson<CoachingTranscript[]>('data/coaching/transcripts.json'),
|
|
35
|
+
loadJson<AgentProfile[]>('data/coaching/agents.json'),
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
cache = { transcripts, agents };
|
|
39
|
+
return cache;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function getTranscript(id: string): Promise<CoachingTranscript | undefined> {
|
|
43
|
+
const { transcripts } = await loadData();
|
|
44
|
+
return transcripts.find(item => item.id === id);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getAgent(agentId: string): Promise<AgentProfile | undefined> {
|
|
48
|
+
const { agents } = await loadData();
|
|
49
|
+
return agents.find(agent => agent.id === agentId);
|
|
50
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { loadJson } from './loader.js';
|
|
2
|
+
|
|
3
|
+
export interface CustomerProfile {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
tier: 'STANDARD' | 'GOLD' | 'PLATINUM';
|
|
7
|
+
accountAgeDays: number;
|
|
8
|
+
complianceFlags: string[];
|
|
9
|
+
benefits: string[];
|
|
10
|
+
supervisor: {
|
|
11
|
+
name: string;
|
|
12
|
+
email: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface EntitlementPolicy {
|
|
17
|
+
id: string;
|
|
18
|
+
benefitCode: string;
|
|
19
|
+
description: string;
|
|
20
|
+
requiredTier: 'STANDARD' | 'GOLD' | 'PLATINUM';
|
|
21
|
+
minAccountAgeDays: number;
|
|
22
|
+
requiresComplianceClearance: boolean;
|
|
23
|
+
slaMinutes: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface EntitlementData {
|
|
27
|
+
customers: CustomerProfile[];
|
|
28
|
+
policies: EntitlementPolicy[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let cachedData: EntitlementData | null = null;
|
|
32
|
+
|
|
33
|
+
async function loadData(): Promise<EntitlementData> {
|
|
34
|
+
if (cachedData) {
|
|
35
|
+
return cachedData;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [customers, policies] = await Promise.all([
|
|
39
|
+
loadJson<CustomerProfile[]>('data/entitlement/customers.json'),
|
|
40
|
+
loadJson<EntitlementPolicy[]>('data/entitlement/policies.json'),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
cachedData = { customers, policies };
|
|
44
|
+
return cachedData;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getCustomerProfile(customerId: string): Promise<CustomerProfile | undefined> {
|
|
48
|
+
const { customers } = await loadData();
|
|
49
|
+
return customers.find(c => c.id === customerId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function getPolicy(benefitCode: string): Promise<EntitlementPolicy | undefined> {
|
|
53
|
+
const { policies } = await loadData();
|
|
54
|
+
return policies.find(p => p.benefitCode === benefitCode);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function listPolicies(): Promise<EntitlementPolicy[]> {
|
|
58
|
+
const { policies } = await loadData();
|
|
59
|
+
return policies;
|
|
60
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { loadJson } from './loader.js';
|
|
2
|
+
|
|
3
|
+
export type IncidentSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
|
|
4
|
+
|
|
5
|
+
export interface IncidentRecord {
|
|
6
|
+
id: string;
|
|
7
|
+
service: string;
|
|
8
|
+
reportedAt: string;
|
|
9
|
+
customerImpact: 'NONE' | 'MINOR' | 'MAJOR';
|
|
10
|
+
category: 'PERFORMANCE' | 'OUTAGE' | 'SECURITY' | 'QUALITY';
|
|
11
|
+
signalScore: number;
|
|
12
|
+
declaredSeverity: IncidentSeverity;
|
|
13
|
+
vipCustomer?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface RoutingRule {
|
|
17
|
+
id: string;
|
|
18
|
+
service: string;
|
|
19
|
+
category: IncidentRecord['category'];
|
|
20
|
+
minSeverity: IncidentSeverity;
|
|
21
|
+
queue: string;
|
|
22
|
+
escalatesTo?: string;
|
|
23
|
+
notes?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface IncidentData {
|
|
27
|
+
incidents: IncidentRecord[];
|
|
28
|
+
routing: RoutingRule[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let cache: IncidentData | null = null;
|
|
32
|
+
|
|
33
|
+
async function loadData(): Promise<IncidentData> {
|
|
34
|
+
if (cache) {
|
|
35
|
+
return cache;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [incidents, routing] = await Promise.all([
|
|
39
|
+
loadJson<IncidentRecord[]>('data/incidents/incidents.json'),
|
|
40
|
+
loadJson<RoutingRule[]>('data/incidents/routing_rules.json'),
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
cache = { incidents, routing };
|
|
44
|
+
return cache;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function getIncident(incidentId: string): Promise<IncidentRecord | undefined> {
|
|
48
|
+
const { incidents } = await loadData();
|
|
49
|
+
return incidents.find(item => item.id === incidentId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function severityRank(severity: IncidentSeverity): number {
|
|
53
|
+
switch (severity) {
|
|
54
|
+
case 'LOW': return 1;
|
|
55
|
+
case 'MEDIUM': return 2;
|
|
56
|
+
case 'HIGH': return 3;
|
|
57
|
+
case 'CRITICAL': return 4;
|
|
58
|
+
default: return 0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function findRoutingRule(
|
|
63
|
+
incident: IncidentRecord,
|
|
64
|
+
severityOverride?: IncidentSeverity,
|
|
65
|
+
): Promise<RoutingRule | undefined> {
|
|
66
|
+
const { routing } = await loadData();
|
|
67
|
+
const effectiveSeverity = severityOverride ?? incident.declaredSeverity;
|
|
68
|
+
const effectiveRank = severityRank(effectiveSeverity);
|
|
69
|
+
|
|
70
|
+
const candidates = routing.filter(rule =>
|
|
71
|
+
rule.service === incident.service &&
|
|
72
|
+
rule.category === incident.category &&
|
|
73
|
+
severityRank(rule.minSeverity) <= effectiveRank,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
candidates.sort((a, b) => severityRank(b.minSeverity) - severityRank(a.minSeverity));
|
|
77
|
+
return candidates[0];
|
|
78
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { loadJson } from './loader.js';
|
|
2
|
+
|
|
3
|
+
export interface InvoiceLine {
|
|
4
|
+
sku: string;
|
|
5
|
+
description: string;
|
|
6
|
+
quantity: number;
|
|
7
|
+
unitPrice: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface InvoiceRecord {
|
|
11
|
+
id: string;
|
|
12
|
+
supplier: string;
|
|
13
|
+
total: number;
|
|
14
|
+
currency: string;
|
|
15
|
+
purchaseOrderId: string;
|
|
16
|
+
receivedAt: string;
|
|
17
|
+
lines: InvoiceLine[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface PurchaseOrderRecord {
|
|
21
|
+
id: string;
|
|
22
|
+
initiator: string;
|
|
23
|
+
department: string;
|
|
24
|
+
total: number;
|
|
25
|
+
currency: string;
|
|
26
|
+
status: string;
|
|
27
|
+
lines: InvoiceLine[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface InvoiceData {
|
|
31
|
+
invoices: InvoiceRecord[];
|
|
32
|
+
purchaseOrders: PurchaseOrderRecord[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let cached: InvoiceData | null = null;
|
|
36
|
+
|
|
37
|
+
async function loadData(): Promise<InvoiceData> {
|
|
38
|
+
if (cached) {
|
|
39
|
+
return cached;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const [invoices, purchaseOrders] = await Promise.all([
|
|
43
|
+
loadJson<InvoiceRecord[]>('data/invoices/invoices.json'),
|
|
44
|
+
loadJson<PurchaseOrderRecord[]>('data/invoices/purchase-orders.json'),
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
cached = { invoices, purchaseOrders };
|
|
48
|
+
return cached;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function getInvoice(invoiceId: string): Promise<InvoiceRecord | undefined> {
|
|
52
|
+
const { invoices } = await loadData();
|
|
53
|
+
return invoices.find(inv => inv.id === invoiceId);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function getPurchaseOrder(poId: string): Promise<PurchaseOrderRecord | undefined> {
|
|
57
|
+
const { purchaseOrders } = await loadData();
|
|
58
|
+
return purchaseOrders.find(po => po.id === poId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function compareLineItems(invoice: InvoiceRecord, po: PurchaseOrderRecord): Array<{
|
|
62
|
+
sku: string;
|
|
63
|
+
expectedQuantity: number;
|
|
64
|
+
actualQuantity: number;
|
|
65
|
+
expectedPrice: number;
|
|
66
|
+
actualPrice: number;
|
|
67
|
+
}> {
|
|
68
|
+
const discrepancies: Array<{
|
|
69
|
+
sku: string;
|
|
70
|
+
expectedQuantity: number;
|
|
71
|
+
actualQuantity: number;
|
|
72
|
+
expectedPrice: number;
|
|
73
|
+
actualPrice: number;
|
|
74
|
+
}> = [];
|
|
75
|
+
|
|
76
|
+
const poLines = new Map(po.lines.map(line => [line.sku, line]));
|
|
77
|
+
|
|
78
|
+
for (const invLine of invoice.lines) {
|
|
79
|
+
const poLine = poLines.get(invLine.sku);
|
|
80
|
+
if (!poLine) {
|
|
81
|
+
discrepancies.push({
|
|
82
|
+
sku: invLine.sku,
|
|
83
|
+
expectedQuantity: 0,
|
|
84
|
+
actualQuantity: invLine.quantity,
|
|
85
|
+
expectedPrice: 0,
|
|
86
|
+
actualPrice: invLine.unitPrice,
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (poLine.quantity !== invLine.quantity || poLine.unitPrice !== invLine.unitPrice) {
|
|
92
|
+
discrepancies.push({
|
|
93
|
+
sku: invLine.sku,
|
|
94
|
+
expectedQuantity: poLine.quantity,
|
|
95
|
+
actualQuantity: invLine.quantity,
|
|
96
|
+
expectedPrice: poLine.unitPrice,
|
|
97
|
+
actualPrice: invLine.unitPrice,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return discrepancies;
|
|
103
|
+
}
|