@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
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { Task, type RunContext } from '@ddse/acm-sdk';
|
|
2
|
+
import type { InvoiceRecord, PurchaseOrderRecord } from '../data/invoices.js';
|
|
3
|
+
import {
|
|
4
|
+
type FetchInvoiceInput,
|
|
5
|
+
type FetchInvoiceOutput,
|
|
6
|
+
type FetchPurchaseOrderInput,
|
|
7
|
+
type FetchPurchaseOrderOutput,
|
|
8
|
+
type CompareLineItemsInput,
|
|
9
|
+
type CompareLineItemsOutput,
|
|
10
|
+
type RecordFindingsInput,
|
|
11
|
+
type RecordFindingsOutput,
|
|
12
|
+
} from '../tools/invoices/index.js';
|
|
13
|
+
|
|
14
|
+
export class FetchInvoiceTask extends Task<FetchInvoiceInput, FetchInvoiceOutput> {
|
|
15
|
+
constructor() {
|
|
16
|
+
super('task-invoice-fetch', 'invoice.fetch');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
idemKey(_ctx: RunContext, input: FetchInvoiceInput): string | undefined {
|
|
20
|
+
return input?.invoiceId ? `invoice:${input.invoiceId}` : undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
policyInput(_ctx: RunContext, input: FetchInvoiceInput): Record<string, unknown> {
|
|
24
|
+
return {
|
|
25
|
+
action: 'fetch_invoice',
|
|
26
|
+
invoiceId: input.invoiceId,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
verification(): string[] {
|
|
31
|
+
return ['output.invoice !== undefined'];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async execute(
|
|
35
|
+
ctx: RunContext,
|
|
36
|
+
input: FetchInvoiceInput
|
|
37
|
+
): Promise<FetchInvoiceOutput> {
|
|
38
|
+
const tool = ctx.getTool('fetch_invoice');
|
|
39
|
+
if (!tool) {
|
|
40
|
+
throw new Error('fetch_invoice tool is not registered');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result = (await tool.call(input)) as FetchInvoiceOutput;
|
|
44
|
+
ctx.stream?.emit('task', {
|
|
45
|
+
taskId: this.id,
|
|
46
|
+
stage: 'invoice_loaded',
|
|
47
|
+
invoiceId: input.invoiceId,
|
|
48
|
+
});
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class FetchPurchaseOrderTask extends Task<
|
|
54
|
+
FetchPurchaseOrderInput,
|
|
55
|
+
FetchPurchaseOrderOutput
|
|
56
|
+
> {
|
|
57
|
+
constructor() {
|
|
58
|
+
super('task-invoice-fetch-po', 'invoice.fetch_purchase_order');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
idemKey(_ctx: RunContext, input: FetchPurchaseOrderInput): string | undefined {
|
|
62
|
+
return input?.purchaseOrderId ? `purchase-order:${input.purchaseOrderId}` : undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
policyInput(_ctx: RunContext, input: FetchPurchaseOrderInput): Record<string, unknown> {
|
|
66
|
+
return {
|
|
67
|
+
action: 'fetch_purchase_order',
|
|
68
|
+
purchaseOrderId: input.purchaseOrderId,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
verification(): string[] {
|
|
73
|
+
return ['output.purchaseOrder !== undefined'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async execute(
|
|
77
|
+
ctx: RunContext,
|
|
78
|
+
input: FetchPurchaseOrderInput
|
|
79
|
+
): Promise<FetchPurchaseOrderOutput> {
|
|
80
|
+
const tool = ctx.getTool('fetch_purchase_order');
|
|
81
|
+
if (!tool) {
|
|
82
|
+
throw new Error('fetch_purchase_order tool is not registered');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = (await tool.call(input)) as FetchPurchaseOrderOutput;
|
|
86
|
+
ctx.stream?.emit('task', {
|
|
87
|
+
taskId: this.id,
|
|
88
|
+
stage: 'purchase_order_loaded',
|
|
89
|
+
purchaseOrderId: input.purchaseOrderId,
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface CompareLineItemsTaskInput extends Partial<CompareLineItemsInput> {
|
|
96
|
+
invoiceId?: string;
|
|
97
|
+
purchaseOrderId?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class CompareLineItemsTask extends Task<
|
|
101
|
+
CompareLineItemsTaskInput,
|
|
102
|
+
CompareLineItemsOutput
|
|
103
|
+
> {
|
|
104
|
+
constructor() {
|
|
105
|
+
super('task-invoice-compare-lines', 'invoice.compare_line_items');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
policyInput(_ctx: RunContext, input: CompareLineItemsTaskInput): Record<string, unknown> {
|
|
109
|
+
const invoice = this.resolveInvoice(_ctx, input);
|
|
110
|
+
const purchaseOrder = this.resolvePurchaseOrder(_ctx, input);
|
|
111
|
+
return {
|
|
112
|
+
action: 'compare_line_items',
|
|
113
|
+
invoiceId: invoice?.id ?? input.invoiceId,
|
|
114
|
+
purchaseOrderId: purchaseOrder?.id ?? input.purchaseOrderId,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
verification(): string[] {
|
|
119
|
+
return ['Array.isArray(output.discrepancies)', 'typeof output.variance === "number"'];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async execute(
|
|
123
|
+
ctx: RunContext,
|
|
124
|
+
input: CompareLineItemsTaskInput
|
|
125
|
+
): Promise<CompareLineItemsOutput> {
|
|
126
|
+
const tool = ctx.getTool('compare_line_items');
|
|
127
|
+
if (!tool) {
|
|
128
|
+
throw new Error('compare_line_items tool is not registered');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const invoice = this.resolveInvoice(ctx, input);
|
|
132
|
+
const purchaseOrder = this.resolvePurchaseOrder(ctx, input);
|
|
133
|
+
|
|
134
|
+
if (!invoice || !purchaseOrder) {
|
|
135
|
+
throw new Error('invoice and purchaseOrder are required');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const result = (await tool.call({ invoice, purchaseOrder })) as CompareLineItemsOutput;
|
|
139
|
+
ctx.stream?.emit('task', {
|
|
140
|
+
taskId: this.id,
|
|
141
|
+
stage: 'invoice_line_items_compared',
|
|
142
|
+
invoiceId: invoice.id,
|
|
143
|
+
purchaseOrderId: purchaseOrder.id,
|
|
144
|
+
discrepancies: result.discrepancies.length,
|
|
145
|
+
variance: result.variance,
|
|
146
|
+
});
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private resolveInvoice(
|
|
151
|
+
ctx: RunContext,
|
|
152
|
+
input: CompareLineItemsTaskInput
|
|
153
|
+
): InvoiceRecord | undefined {
|
|
154
|
+
if (input?.invoice) {
|
|
155
|
+
return input.invoice;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const fetchOutput = ctx.outputs?.['task-invoice-fetch'] as FetchInvoiceOutput | undefined;
|
|
159
|
+
const invoice = fetchOutput?.invoice;
|
|
160
|
+
if (!invoice) {
|
|
161
|
+
return undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (!input?.invoiceId || invoice.id === input.invoiceId) {
|
|
165
|
+
return invoice;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private resolvePurchaseOrder(
|
|
172
|
+
ctx: RunContext,
|
|
173
|
+
input: CompareLineItemsTaskInput
|
|
174
|
+
): PurchaseOrderRecord | undefined {
|
|
175
|
+
if (input?.purchaseOrder) {
|
|
176
|
+
return input.purchaseOrder;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const fetchOutput = ctx.outputs?.['task-invoice-fetch-po'] as FetchPurchaseOrderOutput | undefined;
|
|
180
|
+
const purchaseOrder = fetchOutput?.purchaseOrder;
|
|
181
|
+
if (!purchaseOrder) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!input?.purchaseOrderId || purchaseOrder.id === input.purchaseOrderId) {
|
|
186
|
+
return purchaseOrder;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface RecordFindingsTaskInput extends Partial<RecordFindingsInput> {
|
|
194
|
+
invoiceId?: string;
|
|
195
|
+
purchaseOrderId?: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export class RecordFindingsTask extends Task<
|
|
199
|
+
RecordFindingsTaskInput,
|
|
200
|
+
RecordFindingsOutput
|
|
201
|
+
> {
|
|
202
|
+
constructor() {
|
|
203
|
+
super('task-invoice-record-findings', 'invoice.record_findings');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
policyInput(_ctx: RunContext, input: RecordFindingsTaskInput): Record<string, unknown> {
|
|
207
|
+
const resolved = this.resolveInput(_ctx, input);
|
|
208
|
+
return {
|
|
209
|
+
action: 'record_findings',
|
|
210
|
+
invoiceId: resolved.invoice.id,
|
|
211
|
+
purchaseOrderId: resolved.purchaseOrder.id,
|
|
212
|
+
discrepancyCount: resolved.discrepancies.length,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
verification(): string[] {
|
|
217
|
+
return ['typeof output.reportId === "string"', 'Array.isArray(output.nextSteps)'];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async execute(
|
|
221
|
+
ctx: RunContext,
|
|
222
|
+
input: RecordFindingsTaskInput
|
|
223
|
+
): Promise<RecordFindingsOutput> {
|
|
224
|
+
const tool = ctx.getTool('record_findings');
|
|
225
|
+
if (!tool) {
|
|
226
|
+
throw new Error('record_findings tool is not registered');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const resolved = this.resolveInput(ctx, input);
|
|
230
|
+
|
|
231
|
+
const result = (await tool.call(resolved)) as RecordFindingsOutput;
|
|
232
|
+
ctx.stream?.emit('task', {
|
|
233
|
+
taskId: this.id,
|
|
234
|
+
stage: 'invoice_findings_recorded',
|
|
235
|
+
invoiceId: resolved.invoice.id,
|
|
236
|
+
purchaseOrderId: resolved.purchaseOrder.id,
|
|
237
|
+
status: result.status,
|
|
238
|
+
});
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private resolveInput(
|
|
243
|
+
ctx: RunContext,
|
|
244
|
+
input: RecordFindingsTaskInput
|
|
245
|
+
): RecordFindingsInput {
|
|
246
|
+
const invoice = input.invoice ?? (ctx.outputs?.['task-invoice-fetch'] as FetchInvoiceOutput | undefined)?.invoice;
|
|
247
|
+
const purchaseOrder =
|
|
248
|
+
input.purchaseOrder ?? (ctx.outputs?.['task-invoice-fetch-po'] as FetchPurchaseOrderOutput | undefined)?.purchaseOrder;
|
|
249
|
+
const compareOutput = ctx.outputs?.['task-invoice-compare-lines'] as CompareLineItemsOutput | undefined;
|
|
250
|
+
|
|
251
|
+
if (!invoice) {
|
|
252
|
+
throw new Error('invoice is required for recording findings');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!purchaseOrder) {
|
|
256
|
+
throw new Error('purchaseOrder is required for recording findings');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const discrepancies = input.discrepancies ?? compareOutput?.discrepancies ?? [];
|
|
260
|
+
const variance = input.variance ?? compareOutput?.variance ?? 0;
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
invoice,
|
|
264
|
+
purchaseOrder,
|
|
265
|
+
discrepancies,
|
|
266
|
+
variance,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Task, type RunContext } from '@ddse/acm-sdk';
|
|
2
|
+
import {
|
|
3
|
+
type KnowledgeSearchInput,
|
|
4
|
+
type KnowledgeSearchOutput,
|
|
5
|
+
type SummarizeSnippetInput,
|
|
6
|
+
type SummarizeSnippetOutput,
|
|
7
|
+
type SuggestFollowupsInput,
|
|
8
|
+
type SuggestFollowupsOutput,
|
|
9
|
+
} from '../tools/knowledge/index.js';
|
|
10
|
+
|
|
11
|
+
export class SearchKnowledgeTask extends Task<
|
|
12
|
+
KnowledgeSearchInput,
|
|
13
|
+
KnowledgeSearchOutput
|
|
14
|
+
> {
|
|
15
|
+
constructor() {
|
|
16
|
+
super('task-knowledge-search', 'knowledge.search');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
idemKey(_ctx: RunContext, input: KnowledgeSearchInput): string | undefined {
|
|
20
|
+
const query = input?.query?.trim();
|
|
21
|
+
return query ? `knowledge:search:${query.toLowerCase()}` : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
policyInput(_ctx: RunContext, input: KnowledgeSearchInput): Record<string, unknown> {
|
|
25
|
+
return {
|
|
26
|
+
action: 'search_knowledge',
|
|
27
|
+
query: input.query,
|
|
28
|
+
limit: input.limit,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
verification(): string[] {
|
|
33
|
+
return ['Array.isArray(output.hits)', 'output.hits.length >= 0'];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async execute(
|
|
37
|
+
ctx: RunContext,
|
|
38
|
+
input: KnowledgeSearchInput
|
|
39
|
+
): Promise<KnowledgeSearchOutput> {
|
|
40
|
+
const tool = ctx.getTool('search_knowledge');
|
|
41
|
+
if (!tool) {
|
|
42
|
+
throw new Error('search_knowledge tool is not registered');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const result = (await tool.call(input)) as KnowledgeSearchOutput;
|
|
46
|
+
ctx.stream?.emit('task', {
|
|
47
|
+
taskId: this.id,
|
|
48
|
+
stage: 'knowledge_hits_found',
|
|
49
|
+
hits: result.hits?.map(hit => ({ docId: hit.id, score: hit.score })),
|
|
50
|
+
});
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class SummarizeSnippetTask extends Task<
|
|
56
|
+
SummarizeSnippetInput,
|
|
57
|
+
SummarizeSnippetOutput
|
|
58
|
+
> {
|
|
59
|
+
constructor() {
|
|
60
|
+
super('task-knowledge-summarize', 'knowledge.summarize');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
policyInput(_ctx: RunContext, input: SummarizeSnippetInput): Record<string, unknown> {
|
|
64
|
+
return {
|
|
65
|
+
action: 'summarize_snippet',
|
|
66
|
+
docId: input.docId,
|
|
67
|
+
maxSentences: input.maxSentences,
|
|
68
|
+
focus: input.focus,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
verification(): string[] {
|
|
73
|
+
return ['typeof output.summary === "string"', 'Array.isArray(output.highlights)'];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async execute(
|
|
77
|
+
ctx: RunContext,
|
|
78
|
+
input: SummarizeSnippetInput
|
|
79
|
+
): Promise<SummarizeSnippetOutput> {
|
|
80
|
+
const tool = ctx.getTool('summarize_snippet');
|
|
81
|
+
if (!tool) {
|
|
82
|
+
throw new Error('summarize_snippet tool is not registered');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const result = (await tool.call(input)) as SummarizeSnippetOutput;
|
|
86
|
+
ctx.stream?.emit('task', {
|
|
87
|
+
taskId: this.id,
|
|
88
|
+
stage: 'knowledge_snippet_summarized',
|
|
89
|
+
docId: input.docId,
|
|
90
|
+
title: result.title,
|
|
91
|
+
});
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class SuggestFollowupsTask extends Task<
|
|
97
|
+
SuggestFollowupsInput,
|
|
98
|
+
SuggestFollowupsOutput
|
|
99
|
+
> {
|
|
100
|
+
constructor() {
|
|
101
|
+
super('task-knowledge-followups', 'knowledge.followups');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private resolveDocId(
|
|
105
|
+
ctx: RunContext,
|
|
106
|
+
input: SuggestFollowupsInput
|
|
107
|
+
): string | undefined {
|
|
108
|
+
const direct = input?.docId;
|
|
109
|
+
if (typeof direct === 'string' && direct.trim()) {
|
|
110
|
+
return direct.trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const summary = ctx.outputs?.['task-knowledge-summarize'] as
|
|
114
|
+
| SummarizeSnippetOutput
|
|
115
|
+
| undefined;
|
|
116
|
+
const summaryDocId = summary?.docId;
|
|
117
|
+
if (typeof summaryDocId === 'string' && summaryDocId.trim()) {
|
|
118
|
+
return summaryDocId.trim();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const search = ctx.outputs?.['task-knowledge-search'] as
|
|
122
|
+
| KnowledgeSearchOutput
|
|
123
|
+
| undefined;
|
|
124
|
+
const firstHitId = search?.hits?.[0]?.id;
|
|
125
|
+
if (typeof firstHitId === 'string' && firstHitId.trim()) {
|
|
126
|
+
return firstHitId.trim();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
policyInput(_ctx: RunContext, input: SuggestFollowupsInput): Record<string, unknown> {
|
|
133
|
+
const docId = this.resolveDocId(_ctx, input);
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
action: 'suggest_followups',
|
|
137
|
+
docId,
|
|
138
|
+
context: input.context,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
verification(): string[] {
|
|
143
|
+
return ['Array.isArray(output.suggestions)', 'output.suggestions.length >= 0'];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async execute(
|
|
147
|
+
ctx: RunContext,
|
|
148
|
+
input: SuggestFollowupsInput
|
|
149
|
+
): Promise<SuggestFollowupsOutput> {
|
|
150
|
+
const tool = ctx.getTool('suggest_followups');
|
|
151
|
+
if (!tool) {
|
|
152
|
+
throw new Error('suggest_followups tool is not registered');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const docId = this.resolveDocId(ctx, input);
|
|
156
|
+
if (!docId) {
|
|
157
|
+
throw new Error('docId is required');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const result = (await tool.call({ ...input, docId })) as SuggestFollowupsOutput;
|
|
161
|
+
ctx.stream?.emit('task', {
|
|
162
|
+
taskId: this.id,
|
|
163
|
+
stage: 'knowledge_followups_suggested',
|
|
164
|
+
docId,
|
|
165
|
+
suggestionCount: result.suggestions.length,
|
|
166
|
+
});
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Task, type RunContext } from '@ddse/acm-sdk';
|
|
2
|
+
|
|
3
|
+
export class SearchTask extends Task<{ query: string }, { results: string[] }> {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('search-task', 'search');
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async execute(ctx: RunContext, input: { query: string }): Promise<{ results: string[] }> {
|
|
9
|
+
const tool = ctx.getTool('search');
|
|
10
|
+
if (!tool) {
|
|
11
|
+
throw new Error('Search tool not found');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const result = await tool.call(input);
|
|
15
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'search_complete', results: result });
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class EnrichAndActTask extends Task<
|
|
21
|
+
{ searchQuery: string; orderId: string },
|
|
22
|
+
{ action: string; details: any }
|
|
23
|
+
> {
|
|
24
|
+
constructor() {
|
|
25
|
+
super('enrich-and-act-task', 'enrich_and_act');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async execute(
|
|
29
|
+
ctx: RunContext,
|
|
30
|
+
input: { searchQuery: string; orderId: string }
|
|
31
|
+
): Promise<{ action: string; details: any }> {
|
|
32
|
+
const searchTool = ctx.getTool('search');
|
|
33
|
+
if (!searchTool) throw new Error('Search tool not found');
|
|
34
|
+
|
|
35
|
+
const searchResult = await searchTool.call({ query: input.searchQuery });
|
|
36
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'search_done' });
|
|
37
|
+
|
|
38
|
+
const extractTool = ctx.getTool('extract_entities');
|
|
39
|
+
if (!extractTool) throw new Error('Extract entities tool not found');
|
|
40
|
+
|
|
41
|
+
const entities = await extractTool.call({ text: JSON.stringify(searchResult) });
|
|
42
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'entities_extracted' });
|
|
43
|
+
|
|
44
|
+
const riskTool = ctx.getTool('assess_risk');
|
|
45
|
+
if (!riskTool) throw new Error('Risk assessment tool not found');
|
|
46
|
+
|
|
47
|
+
const risk = await riskTool.call({ context: { entities, orderId: input.orderId } });
|
|
48
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'risk_assessed', risk });
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
action: risk.riskTier === 'HIGH' ? 'ESCALATE' : 'PROCEED',
|
|
52
|
+
details: { searchResult, entities, risk },
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
policyInput(ctx: RunContext, input: any): Record<string, unknown> {
|
|
57
|
+
return {
|
|
58
|
+
orderId: input.orderId,
|
|
59
|
+
action: 'enrich_and_assess',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
verification(): string[] {
|
|
64
|
+
return ['output.action !== undefined', 'output.details !== undefined'];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class RefundFlowTask extends Task<
|
|
69
|
+
{ orderId: string; amount: number },
|
|
70
|
+
{ transactionId: string; notified: boolean }
|
|
71
|
+
> {
|
|
72
|
+
constructor() {
|
|
73
|
+
super('refund-flow-task', 'refund_flow');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async execute(
|
|
77
|
+
ctx: RunContext,
|
|
78
|
+
input: { orderId: string; amount: number }
|
|
79
|
+
): Promise<{ transactionId: string; notified: boolean }> {
|
|
80
|
+
const refundTool = ctx.getTool('create_refund_txn');
|
|
81
|
+
if (!refundTool) throw new Error('Refund tool not found');
|
|
82
|
+
|
|
83
|
+
const txn = await refundTool.call(input);
|
|
84
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'refund_created', txn });
|
|
85
|
+
|
|
86
|
+
const notifyTool = ctx.getTool('notify_supervisor_legacy');
|
|
87
|
+
if (!notifyTool) throw new Error('Notify tool not found');
|
|
88
|
+
|
|
89
|
+
const notification = await notifyTool.call({
|
|
90
|
+
message: `Refund ${txn.transactionId} created for order ${input.orderId}`,
|
|
91
|
+
channel: 'email',
|
|
92
|
+
});
|
|
93
|
+
ctx.stream?.emit('task', { taskId: this.id, step: 'notification_sent' });
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
transactionId: txn.transactionId,
|
|
97
|
+
notified: notification.sent,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
policyInput(ctx: RunContext, input: any): Record<string, unknown> {
|
|
102
|
+
return {
|
|
103
|
+
orderId: input.orderId,
|
|
104
|
+
amount: input.amount,
|
|
105
|
+
action: 'create_refund',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
verification(): string[] {
|
|
110
|
+
return ['output.transactionId !== undefined', 'output.notified === true'];
|
|
111
|
+
}
|
|
112
|
+
}
|