@qcobro/common 1.39.2 → 1.40.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/config.d.ts +12 -41
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +63 -81
- package/dist/config.js.map +1 -1
- package/dist/schemas/agentEvaluations.d.ts +9 -9
- package/dist/schemas/agentEvaluations.d.ts.map +1 -1
- package/dist/schemas/agentEvaluations.js +7 -6
- package/dist/schemas/agentEvaluations.js.map +1 -1
- package/dist/schemas/agentTemplates.d.ts +7 -7
- package/dist/schemas/agentTemplates.js +6 -6
- package/dist/schemas/contactLog.d.ts +108 -31
- package/dist/schemas/contactLog.d.ts.map +1 -1
- package/dist/schemas/contactLog.js +58 -32
- package/dist/schemas/contactLog.js.map +1 -1
- package/dist/schemas/dispatch.d.ts +4 -4
- package/dist/schemas/email.d.ts +6 -6
- package/dist/schemas/email.js +6 -6
- package/dist/schemas/email.js.map +1 -1
- package/dist/schemas/engineEvents.d.ts +26 -26
- package/dist/schemas/voiceEvent.d.ts +1 -1
- package/dist/schemas/voiceEvent.js +1 -1
- package/dist/types/agentEvaluations.d.ts +1 -1
- package/dist/types/agentEvaluations.d.ts.map +1 -1
- package/dist/types/campaigns.d.ts +4 -4
- package/dist/types/campaigns.d.ts.map +1 -1
- package/dist/types/dispatch.d.ts +35 -0
- package/dist/types/dispatch.d.ts.map +1 -1
- package/dist/types/email.d.ts +2 -2
- package/dist/types/email.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
3
|
* A gestión answers up to three independent questions, one per axis. They were previously
|
|
4
|
-
* flattened into a single
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* flattened into a single enum (then also confusingly called `outcome`, before the axis
|
|
5
|
+
* split introduced `resultado` — since renamed to today's `outcome` below, a coincidence of
|
|
6
|
+
* naming across two unrelated eras, not the same field), which is why no value meant one
|
|
7
|
+
* thing: `WRONG_NUMBER` described both a carrier rejection (a delivery failure) and a human
|
|
8
|
+
* saying "that's not me" (a delivery *success* carrying a valuable finding), and `OTHER`
|
|
9
|
+
* served as dispatch placeholder, escalation marker, and unclassifiable-conversation
|
|
10
|
+
* catch-all at once.
|
|
8
11
|
*/
|
|
9
12
|
/** Did the attempt reach the account holder's device or inbox? Never null. */
|
|
10
|
-
export declare const
|
|
13
|
+
export declare const deliverySchema: z.ZodEnum<{
|
|
11
14
|
DISPATCHED: "DISPATCHED";
|
|
12
15
|
DELIVERED: "DELIVERED";
|
|
13
16
|
FAILED: "FAILED";
|
|
14
17
|
}>;
|
|
15
|
-
export type
|
|
18
|
+
export type Delivery = z.infer<typeof deliverySchema>;
|
|
16
19
|
/**
|
|
17
|
-
* Why delivery failed. Set if and only if `
|
|
20
|
+
* Why delivery failed. Set if and only if `delivery` is `FAILED`. The values are chosen so a
|
|
18
21
|
* retry policy can branch on them: `NO_ANSWER` and `BUSY` are transient, `INVALID_DESTINATION`
|
|
19
22
|
* and `CHANNEL_UNSUPPORTED` are permanent for that contact point.
|
|
23
|
+
*
|
|
24
|
+
* `OUTCOME_UNKNOWN` and `NOT_ORIGINATED` are voice-only, both written by the voice
|
|
25
|
+
* completion sweep from Fonoster's call detail record rather than a live completion
|
|
26
|
+
* signal: `OUTCOME_UNKNOWN` when the call connected and cleared normally but QCobro's own
|
|
27
|
+
* completion signal never arrived, `NOT_ORIGINATED` when the provider has no record of the
|
|
28
|
+
* call at all. Both are transient — the account stays eligible for a retry.
|
|
20
29
|
*/
|
|
21
30
|
export declare const deliveryReasonSchema: z.ZodEnum<{
|
|
22
31
|
NO_ANSWER: "NO_ANSWER";
|
|
@@ -26,6 +35,8 @@ export declare const deliveryReasonSchema: z.ZodEnum<{
|
|
|
26
35
|
CHANNEL_UNSUPPORTED: "CHANNEL_UNSUPPORTED";
|
|
27
36
|
INVALID_DESTINATION: "INVALID_DESTINATION";
|
|
28
37
|
REJECTED: "REJECTED";
|
|
38
|
+
OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN";
|
|
39
|
+
NOT_ORIGINATED: "NOT_ORIGINATED";
|
|
29
40
|
}>;
|
|
30
41
|
export type DeliveryReason = z.infer<typeof deliveryReasonSchema>;
|
|
31
42
|
/**
|
|
@@ -34,17 +45,17 @@ export type DeliveryReason = z.infer<typeof deliveryReasonSchema>;
|
|
|
34
45
|
* `VOICEMAIL` is reachable only on `VOICE_AI` and needs AMD before it can actually be
|
|
35
46
|
* detected (issue #83); it is defined now so the enum needs no second migration later.
|
|
36
47
|
*/
|
|
37
|
-
export declare const
|
|
48
|
+
export declare const pathSchema: z.ZodEnum<{
|
|
38
49
|
ENGAGED: "ENGAGED";
|
|
39
50
|
ABANDONED: "ABANDONED";
|
|
40
51
|
VOICEMAIL: "VOICEMAIL";
|
|
41
52
|
}>;
|
|
42
|
-
export type
|
|
53
|
+
export type Path = z.infer<typeof pathSchema>;
|
|
43
54
|
/**
|
|
44
55
|
* What came of the engagement. Nullable and single-valued; null is the common case and means
|
|
45
56
|
* nothing came of it, which is a real and frequent answer rather than missing data.
|
|
46
57
|
*/
|
|
47
|
-
export declare const
|
|
58
|
+
export declare const outcomeSchema: z.ZodEnum<{
|
|
48
59
|
PAYMENT_PROMISE: "PAYMENT_PROMISE";
|
|
49
60
|
NEW_TERMS: "NEW_TERMS";
|
|
50
61
|
PAID: "PAID";
|
|
@@ -56,15 +67,15 @@ export declare const resultadoSchema: z.ZodEnum<{
|
|
|
56
67
|
WRONG_PARTY: "WRONG_PARTY";
|
|
57
68
|
RESOLVED: "RESOLVED";
|
|
58
69
|
}>;
|
|
59
|
-
export type
|
|
70
|
+
export type Outcome = z.infer<typeof outcomeSchema>;
|
|
60
71
|
/**
|
|
61
|
-
* Channels with an inbound path, and therefore the only ones that can observe a `
|
|
62
|
-
* produce
|
|
72
|
+
* Channels with an inbound path, and therefore the only ones that can observe a `path` or
|
|
73
|
+
* produce an `outcome`. `SMS` has no inbound ingestion at all, so both axes are not merely
|
|
63
74
|
* usually-null there — they are unreachable. `VOICE_PRERECORDED` is the one exception: it has
|
|
64
75
|
* no inbound path of its own, but reaching call completion (the script played to the end,
|
|
65
76
|
* with or without an optional DTMF menu — see `prerecorded-audio`) always sets
|
|
66
|
-
* `
|
|
67
|
-
* other
|
|
77
|
+
* `path: ENGAGED`, and the opt-out digit specifically also sets `outcome: OPT_OUT` — no
|
|
78
|
+
* other path/outcome value is reachable. See {@link isAllowedOnPrerecorded} for that
|
|
68
79
|
* narrow carve-out.
|
|
69
80
|
*/
|
|
70
81
|
export declare const CHANNEL_CAN_ENGAGE: readonly ["VOICE_AI", "EMAIL", "WHATSAPP"];
|
|
@@ -91,32 +102,21 @@ export declare const paymentPromiseStatusSchema: z.ZodEnum<{
|
|
|
91
102
|
CANCELLED: "CANCELLED";
|
|
92
103
|
}>;
|
|
93
104
|
export type PaymentPromiseStatus = z.infer<typeof paymentPromiseStatusSchema>;
|
|
94
|
-
/**
|
|
95
|
-
* The axes are independent, but two combinations are incoherent rather than merely unusual,
|
|
96
|
-
* so they are rejected before the write rather than stored and worked around by every reader:
|
|
97
|
-
*
|
|
98
|
-
* - a failure reason without a failure (or a failure without a reason) — the reason is the
|
|
99
|
-
* only thing that makes `FAILED` actionable;
|
|
100
|
-
* - an interaction recorded on a channel that cannot observe one.
|
|
101
|
-
*
|
|
102
|
-
* Note there is deliberately no rule tying `resultado` to `entrega`: a `FAILED` delivery can
|
|
103
|
-
* still carry a `resultado` when someone answers and hangs up on a wrong-party identification.
|
|
104
|
-
*/
|
|
105
105
|
export declare const createContactLogSchema: z.ZodObject<{
|
|
106
106
|
portfolioAccountId: z.ZodString;
|
|
107
107
|
campaignId: z.ZodOptional<z.ZodString>;
|
|
108
108
|
agentTemplateId: z.ZodOptional<z.ZodString>;
|
|
109
109
|
paymentPromiseId: z.ZodOptional<z.ZodString>;
|
|
110
110
|
agentType: z.ZodEnum<{
|
|
111
|
-
SMS: "SMS";
|
|
112
|
-
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
113
111
|
VOICE_AI: "VOICE_AI";
|
|
112
|
+
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
113
|
+
SMS: "SMS";
|
|
114
114
|
EMAIL: "EMAIL";
|
|
115
115
|
WHATSAPP: "WHATSAPP";
|
|
116
116
|
}>;
|
|
117
117
|
contactedAt: z.ZodString;
|
|
118
118
|
durationSeconds: z.ZodOptional<z.ZodNumber>;
|
|
119
|
-
|
|
119
|
+
delivery: z.ZodDefault<z.ZodEnum<{
|
|
120
120
|
DISPATCHED: "DISPATCHED";
|
|
121
121
|
DELIVERED: "DELIVERED";
|
|
122
122
|
FAILED: "FAILED";
|
|
@@ -129,13 +129,15 @@ export declare const createContactLogSchema: z.ZodObject<{
|
|
|
129
129
|
CHANNEL_UNSUPPORTED: "CHANNEL_UNSUPPORTED";
|
|
130
130
|
INVALID_DESTINATION: "INVALID_DESTINATION";
|
|
131
131
|
REJECTED: "REJECTED";
|
|
132
|
+
OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN";
|
|
133
|
+
NOT_ORIGINATED: "NOT_ORIGINATED";
|
|
132
134
|
}>>;
|
|
133
|
-
|
|
135
|
+
path: z.ZodOptional<z.ZodEnum<{
|
|
134
136
|
ENGAGED: "ENGAGED";
|
|
135
137
|
ABANDONED: "ABANDONED";
|
|
136
138
|
VOICEMAIL: "VOICEMAIL";
|
|
137
139
|
}>>;
|
|
138
|
-
|
|
140
|
+
outcome: z.ZodOptional<z.ZodEnum<{
|
|
139
141
|
PAYMENT_PROMISE: "PAYMENT_PROMISE";
|
|
140
142
|
NEW_TERMS: "NEW_TERMS";
|
|
141
143
|
PAID: "PAID";
|
|
@@ -165,6 +167,81 @@ export declare const createContactLogSchema: z.ZodObject<{
|
|
|
165
167
|
providerMessageId: z.ZodOptional<z.ZodString>;
|
|
166
168
|
}, z.core.$strip>;
|
|
167
169
|
export type CreateContactLogInput = z.infer<typeof createContactLogSchema>;
|
|
170
|
+
/**
|
|
171
|
+
* REST-facing variant of {@link createContactLogSchema}. `.strict()` rejects any key that
|
|
172
|
+
* isn't one of the known fields — named in a `400` — rather than the base schema's default
|
|
173
|
+
* of silently stripping it. Internal callers (tRPC, the campaigns engine) are TypeScript-typed
|
|
174
|
+
* against `CreateContactLogInput` already, so a stray key there is a compile error, not
|
|
175
|
+
* something worth defending against at runtime; `POST /api/contact-logs` is the one boundary
|
|
176
|
+
* an integrator outside this codebase posts to directly. It exists specifically to catch an
|
|
177
|
+
* integrator still posting the pre-rename Spanish field names (`entrega`/`camino`/`resultado`)
|
|
178
|
+
* — silently stripped by the lenient schema, which would write a `DISPATCHED` row with no
|
|
179
|
+
* outcome and still answer `201`.
|
|
180
|
+
*/
|
|
181
|
+
export declare const createContactLogSchemaStrict: z.ZodObject<{
|
|
182
|
+
portfolioAccountId: z.ZodString;
|
|
183
|
+
campaignId: z.ZodOptional<z.ZodString>;
|
|
184
|
+
agentTemplateId: z.ZodOptional<z.ZodString>;
|
|
185
|
+
paymentPromiseId: z.ZodOptional<z.ZodString>;
|
|
186
|
+
agentType: z.ZodEnum<{
|
|
187
|
+
VOICE_AI: "VOICE_AI";
|
|
188
|
+
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
189
|
+
SMS: "SMS";
|
|
190
|
+
EMAIL: "EMAIL";
|
|
191
|
+
WHATSAPP: "WHATSAPP";
|
|
192
|
+
}>;
|
|
193
|
+
contactedAt: z.ZodString;
|
|
194
|
+
durationSeconds: z.ZodOptional<z.ZodNumber>;
|
|
195
|
+
delivery: z.ZodDefault<z.ZodEnum<{
|
|
196
|
+
DISPATCHED: "DISPATCHED";
|
|
197
|
+
DELIVERED: "DELIVERED";
|
|
198
|
+
FAILED: "FAILED";
|
|
199
|
+
}>>;
|
|
200
|
+
deliveryReason: z.ZodOptional<z.ZodEnum<{
|
|
201
|
+
NO_ANSWER: "NO_ANSWER";
|
|
202
|
+
BUSY: "BUSY";
|
|
203
|
+
UNREACHABLE: "UNREACHABLE";
|
|
204
|
+
PROVIDER_ERROR: "PROVIDER_ERROR";
|
|
205
|
+
CHANNEL_UNSUPPORTED: "CHANNEL_UNSUPPORTED";
|
|
206
|
+
INVALID_DESTINATION: "INVALID_DESTINATION";
|
|
207
|
+
REJECTED: "REJECTED";
|
|
208
|
+
OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN";
|
|
209
|
+
NOT_ORIGINATED: "NOT_ORIGINATED";
|
|
210
|
+
}>>;
|
|
211
|
+
path: z.ZodOptional<z.ZodEnum<{
|
|
212
|
+
ENGAGED: "ENGAGED";
|
|
213
|
+
ABANDONED: "ABANDONED";
|
|
214
|
+
VOICEMAIL: "VOICEMAIL";
|
|
215
|
+
}>>;
|
|
216
|
+
outcome: z.ZodOptional<z.ZodEnum<{
|
|
217
|
+
PAYMENT_PROMISE: "PAYMENT_PROMISE";
|
|
218
|
+
NEW_TERMS: "NEW_TERMS";
|
|
219
|
+
PAID: "PAID";
|
|
220
|
+
CALLBACK_REQUESTED: "CALLBACK_REQUESTED";
|
|
221
|
+
DISPUTE_RAISED: "DISPUTE_RAISED";
|
|
222
|
+
INFORMATION_REQUEST: "INFORMATION_REQUEST";
|
|
223
|
+
REFUSED: "REFUSED";
|
|
224
|
+
OPT_OUT: "OPT_OUT";
|
|
225
|
+
WRONG_PARTY: "WRONG_PARTY";
|
|
226
|
+
RESOLVED: "RESOLVED";
|
|
227
|
+
}>>;
|
|
228
|
+
notes: z.ZodOptional<z.ZodString>;
|
|
229
|
+
debtAmountSnapshot: z.ZodOptional<z.ZodNumber>;
|
|
230
|
+
aiSummary: z.ZodOptional<z.ZodString>;
|
|
231
|
+
aiSentiment: z.ZodOptional<z.ZodEnum<{
|
|
232
|
+
POSITIVE: "POSITIVE";
|
|
233
|
+
NEUTRAL: "NEUTRAL";
|
|
234
|
+
NEGATIVE: "NEGATIVE";
|
|
235
|
+
HOSTILE: "HOSTILE";
|
|
236
|
+
}>>;
|
|
237
|
+
aiDebtReason: z.ZodOptional<z.ZodString>;
|
|
238
|
+
aiResult: z.ZodOptional<z.ZodString>;
|
|
239
|
+
aiNextStep: z.ZodOptional<z.ZodString>;
|
|
240
|
+
intentMetadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
241
|
+
channelData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
242
|
+
providerRef: z.ZodOptional<z.ZodString>;
|
|
243
|
+
providerMessageId: z.ZodOptional<z.ZodString>;
|
|
244
|
+
}, z.core.$strict>;
|
|
168
245
|
/**
|
|
169
246
|
* Input to reserve a campaign attempt before the provider call (the engine's
|
|
170
247
|
* at-most-once step). Increments the attempt counters; writes no gestión.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contactLog.d.ts","sourceRoot":"","sources":["../../src/schemas/contactLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB
|
|
1
|
+
{"version":3,"file":"contactLog.d.ts","sourceRoot":"","sources":["../../src/schemas/contactLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;;;GASG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,cAAc;;;;EAAgD,CAAC;AAC5E,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;EAU/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,UAAU;;;;EAAgD,CAAC;AACxE,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;EAWxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,4CAA6C,CAAC;AAE7E,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE3D;AAiBD,eAAO,MAAM,iBAAiB;;;;;EAAyD,CAAC;AACxF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;;;;;EAAqD,CAAC;AAC7F,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAyF9E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2D,CAAC;AAC/F,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE3E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAEL,CAAC;AAErC;;;GAGG;AACH,eAAO,MAAM,oBAAoB;;;;iBAK/B,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEvE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;;;iBAGrC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEnF;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAC;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC"}
|
|
@@ -2,17 +2,26 @@ import { z } from "zod";
|
|
|
2
2
|
import { agentTypeSchema } from "./agentTemplates.js";
|
|
3
3
|
/**
|
|
4
4
|
* A gestión answers up to three independent questions, one per axis. They were previously
|
|
5
|
-
* flattened into a single
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* flattened into a single enum (then also confusingly called `outcome`, before the axis
|
|
6
|
+
* split introduced `resultado` — since renamed to today's `outcome` below, a coincidence of
|
|
7
|
+
* naming across two unrelated eras, not the same field), which is why no value meant one
|
|
8
|
+
* thing: `WRONG_NUMBER` described both a carrier rejection (a delivery failure) and a human
|
|
9
|
+
* saying "that's not me" (a delivery *success* carrying a valuable finding), and `OTHER`
|
|
10
|
+
* served as dispatch placeholder, escalation marker, and unclassifiable-conversation
|
|
11
|
+
* catch-all at once.
|
|
9
12
|
*/
|
|
10
13
|
/** Did the attempt reach the account holder's device or inbox? Never null. */
|
|
11
|
-
export const
|
|
14
|
+
export const deliverySchema = z.enum(["DISPATCHED", "DELIVERED", "FAILED"]);
|
|
12
15
|
/**
|
|
13
|
-
* Why delivery failed. Set if and only if `
|
|
16
|
+
* Why delivery failed. Set if and only if `delivery` is `FAILED`. The values are chosen so a
|
|
14
17
|
* retry policy can branch on them: `NO_ANSWER` and `BUSY` are transient, `INVALID_DESTINATION`
|
|
15
18
|
* and `CHANNEL_UNSUPPORTED` are permanent for that contact point.
|
|
19
|
+
*
|
|
20
|
+
* `OUTCOME_UNKNOWN` and `NOT_ORIGINATED` are voice-only, both written by the voice
|
|
21
|
+
* completion sweep from Fonoster's call detail record rather than a live completion
|
|
22
|
+
* signal: `OUTCOME_UNKNOWN` when the call connected and cleared normally but QCobro's own
|
|
23
|
+
* completion signal never arrived, `NOT_ORIGINATED` when the provider has no record of the
|
|
24
|
+
* call at all. Both are transient — the account stays eligible for a retry.
|
|
16
25
|
*/
|
|
17
26
|
export const deliveryReasonSchema = z.enum([
|
|
18
27
|
"NO_ANSWER",
|
|
@@ -21,7 +30,9 @@ export const deliveryReasonSchema = z.enum([
|
|
|
21
30
|
"PROVIDER_ERROR",
|
|
22
31
|
"CHANNEL_UNSUPPORTED",
|
|
23
32
|
"INVALID_DESTINATION",
|
|
24
|
-
"REJECTED"
|
|
33
|
+
"REJECTED",
|
|
34
|
+
"OUTCOME_UNKNOWN",
|
|
35
|
+
"NOT_ORIGINATED"
|
|
25
36
|
]);
|
|
26
37
|
/**
|
|
27
38
|
* What path the interaction took once delivered. Null when no interaction was observed —
|
|
@@ -29,12 +40,12 @@ export const deliveryReasonSchema = z.enum([
|
|
|
29
40
|
* `VOICEMAIL` is reachable only on `VOICE_AI` and needs AMD before it can actually be
|
|
30
41
|
* detected (issue #83); it is defined now so the enum needs no second migration later.
|
|
31
42
|
*/
|
|
32
|
-
export const
|
|
43
|
+
export const pathSchema = z.enum(["ENGAGED", "ABANDONED", "VOICEMAIL"]);
|
|
33
44
|
/**
|
|
34
45
|
* What came of the engagement. Nullable and single-valued; null is the common case and means
|
|
35
46
|
* nothing came of it, which is a real and frequent answer rather than missing data.
|
|
36
47
|
*/
|
|
37
|
-
export const
|
|
48
|
+
export const outcomeSchema = z.enum([
|
|
38
49
|
"PAYMENT_PROMISE",
|
|
39
50
|
"NEW_TERMS",
|
|
40
51
|
"PAID",
|
|
@@ -47,13 +58,13 @@ export const resultadoSchema = z.enum([
|
|
|
47
58
|
"RESOLVED"
|
|
48
59
|
]);
|
|
49
60
|
/**
|
|
50
|
-
* Channels with an inbound path, and therefore the only ones that can observe a `
|
|
51
|
-
* produce
|
|
61
|
+
* Channels with an inbound path, and therefore the only ones that can observe a `path` or
|
|
62
|
+
* produce an `outcome`. `SMS` has no inbound ingestion at all, so both axes are not merely
|
|
52
63
|
* usually-null there — they are unreachable. `VOICE_PRERECORDED` is the one exception: it has
|
|
53
64
|
* no inbound path of its own, but reaching call completion (the script played to the end,
|
|
54
65
|
* with or without an optional DTMF menu — see `prerecorded-audio`) always sets
|
|
55
|
-
* `
|
|
56
|
-
* other
|
|
66
|
+
* `path: ENGAGED`, and the opt-out digit specifically also sets `outcome: OPT_OUT` — no
|
|
67
|
+
* other path/outcome value is reachable. See {@link isAllowedOnPrerecorded} for that
|
|
57
68
|
* narrow carve-out.
|
|
58
69
|
*/
|
|
59
70
|
export const CHANNEL_CAN_ENGAGE = ["VOICE_AI", "EMAIL", "WHATSAPP"];
|
|
@@ -61,18 +72,18 @@ export const CHANNEL_CAN_ENGAGE = ["VOICE_AI", "EMAIL", "WHATSAPP"];
|
|
|
61
72
|
export function channelCanEngage(agentType) {
|
|
62
73
|
return CHANNEL_CAN_ENGAGE.includes(agentType);
|
|
63
74
|
}
|
|
64
|
-
const
|
|
65
|
-
const
|
|
75
|
+
const PRERECORDED_ALLOWED_PATH = new Set(["ENGAGED"]);
|
|
76
|
+
const PRERECORDED_ALLOWED_OUTCOME = new Set(["OPT_OUT"]);
|
|
66
77
|
/**
|
|
67
78
|
* `VOICE_PRERECORDED`'s one carve-out from {@link channelCanEngage}: call completion sets
|
|
68
|
-
* `
|
|
69
|
-
* nothing else. `ABANDONED`/`VOICEMAIL` and every other `
|
|
79
|
+
* `path: ENGAGED`, and the opt-out digit specifically also sets `outcome: OPT_OUT` — and
|
|
80
|
+
* nothing else. `ABANDONED`/`VOICEMAIL` and every other `outcome` value stay unreachable,
|
|
70
81
|
* exactly as for any other one-way channel.
|
|
71
82
|
*/
|
|
72
83
|
function isAllowedOnPrerecorded(field, value) {
|
|
73
|
-
return field === "
|
|
74
|
-
?
|
|
75
|
-
:
|
|
84
|
+
return field === "path"
|
|
85
|
+
? PRERECORDED_ALLOWED_PATH.has(value)
|
|
86
|
+
: PRERECORDED_ALLOWED_OUTCOME.has(value);
|
|
76
87
|
}
|
|
77
88
|
export const aiSentimentSchema = z.enum(["POSITIVE", "NEUTRAL", "NEGATIVE", "HOSTILE"]);
|
|
78
89
|
/**
|
|
@@ -94,10 +105,10 @@ const createContactLogFields = z.object({
|
|
|
94
105
|
contactedAt: z.string().min(1),
|
|
95
106
|
durationSeconds: z.number().int().nonnegative().optional(),
|
|
96
107
|
/** Defaults to the dispatch-time state, so a dispatch call site need not spell it out. */
|
|
97
|
-
|
|
108
|
+
delivery: deliverySchema.default("DISPATCHED"),
|
|
98
109
|
deliveryReason: deliveryReasonSchema.optional(),
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
path: pathSchema.optional(),
|
|
111
|
+
outcome: outcomeSchema.optional(),
|
|
101
112
|
notes: z.string().optional(),
|
|
102
113
|
debtAmountSnapshot: z.number().nonnegative().optional(),
|
|
103
114
|
aiSummary: z.string().optional(),
|
|
@@ -130,26 +141,26 @@ const createContactLogFields = z.object({
|
|
|
130
141
|
* only thing that makes `FAILED` actionable;
|
|
131
142
|
* - an interaction recorded on a channel that cannot observe one.
|
|
132
143
|
*
|
|
133
|
-
* Note there is deliberately no rule tying `
|
|
134
|
-
* still carry
|
|
144
|
+
* Note there is deliberately no rule tying `outcome` to `delivery`: a `FAILED` delivery can
|
|
145
|
+
* still carry an `outcome` when someone answers and hangs up on a wrong-party identification.
|
|
135
146
|
*/
|
|
136
|
-
|
|
137
|
-
if (value.
|
|
147
|
+
function refineContactLogAxes(value, ctx) {
|
|
148
|
+
if (value.delivery === "FAILED" && !value.deliveryReason) {
|
|
138
149
|
ctx.addIssue({
|
|
139
150
|
code: "custom",
|
|
140
151
|
path: ["deliveryReason"],
|
|
141
|
-
message: "deliveryReason is required when
|
|
152
|
+
message: "deliveryReason is required when delivery is FAILED"
|
|
142
153
|
});
|
|
143
154
|
}
|
|
144
|
-
if (value.
|
|
155
|
+
if (value.delivery !== "FAILED" && value.deliveryReason) {
|
|
145
156
|
ctx.addIssue({
|
|
146
157
|
code: "custom",
|
|
147
158
|
path: ["deliveryReason"],
|
|
148
|
-
message: `deliveryReason is only valid when
|
|
159
|
+
message: `deliveryReason is only valid when delivery is FAILED (got ${value.delivery})`
|
|
149
160
|
});
|
|
150
161
|
}
|
|
151
162
|
if (!channelCanEngage(value.agentType)) {
|
|
152
|
-
for (const field of ["
|
|
163
|
+
for (const field of ["path", "outcome"]) {
|
|
153
164
|
const fieldValue = value[field];
|
|
154
165
|
if (!fieldValue)
|
|
155
166
|
continue;
|
|
@@ -163,7 +174,22 @@ export const createContactLogSchema = createContactLogFields.superRefine((value,
|
|
|
163
174
|
});
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
|
-
}
|
|
177
|
+
}
|
|
178
|
+
export const createContactLogSchema = createContactLogFields.superRefine(refineContactLogAxes);
|
|
179
|
+
/**
|
|
180
|
+
* REST-facing variant of {@link createContactLogSchema}. `.strict()` rejects any key that
|
|
181
|
+
* isn't one of the known fields — named in a `400` — rather than the base schema's default
|
|
182
|
+
* of silently stripping it. Internal callers (tRPC, the campaigns engine) are TypeScript-typed
|
|
183
|
+
* against `CreateContactLogInput` already, so a stray key there is a compile error, not
|
|
184
|
+
* something worth defending against at runtime; `POST /api/contact-logs` is the one boundary
|
|
185
|
+
* an integrator outside this codebase posts to directly. It exists specifically to catch an
|
|
186
|
+
* integrator still posting the pre-rename Spanish field names (`entrega`/`camino`/`resultado`)
|
|
187
|
+
* — silently stripped by the lenient schema, which would write a `DISPATCHED` row with no
|
|
188
|
+
* outcome and still answer `201`.
|
|
189
|
+
*/
|
|
190
|
+
export const createContactLogSchemaStrict = createContactLogFields
|
|
191
|
+
.strict()
|
|
192
|
+
.superRefine(refineContactLogAxes);
|
|
167
193
|
/**
|
|
168
194
|
* Input to reserve a campaign attempt before the provider call (the engine's
|
|
169
195
|
* at-most-once step). Increments the attempt counters; writes no gestión.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contactLog.js","sourceRoot":"","sources":["../../src/schemas/contactLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD
|
|
1
|
+
{"version":3,"file":"contactLog.js","sourceRoot":"","sources":["../../src/schemas/contactLog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/** The channels the dispatch layer triggers (subset of AgentType). */
|
|
3
3
|
export declare const dispatchChannelSchema: z.ZodEnum<{
|
|
4
|
-
SMS: "SMS";
|
|
5
|
-
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
6
4
|
VOICE_AI: "VOICE_AI";
|
|
5
|
+
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
6
|
+
SMS: "SMS";
|
|
7
7
|
EMAIL: "EMAIL";
|
|
8
8
|
WHATSAPP: "WHATSAPP";
|
|
9
9
|
}>;
|
|
@@ -20,9 +20,9 @@ export declare const dispatchErrorKindSchema: z.ZodEnum<{
|
|
|
20
20
|
*/
|
|
21
21
|
export declare const dispatchOutreachSchema: z.ZodObject<{
|
|
22
22
|
channel: z.ZodEnum<{
|
|
23
|
-
SMS: "SMS";
|
|
24
|
-
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
25
23
|
VOICE_AI: "VOICE_AI";
|
|
24
|
+
VOICE_PRERECORDED: "VOICE_PRERECORDED";
|
|
25
|
+
SMS: "SMS";
|
|
26
26
|
EMAIL: "EMAIL";
|
|
27
27
|
WHATSAPP: "WHATSAPP";
|
|
28
28
|
}>;
|
package/dist/schemas/email.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
3
|
* The structured decision the EMAIL/WHATSAPP autopilots return for an inbound reply.
|
|
4
|
-
* Validated so a model can't drive the loop with malformed output. `
|
|
5
|
-
* contact-log
|
|
4
|
+
* Validated so a model can't drive the loop with malformed output. `outcome` mirrors the
|
|
5
|
+
* contact-log outcome axis; `objective` carries promise details when the reply implies one.
|
|
6
6
|
*
|
|
7
|
-
* `replyBody`/`
|
|
7
|
+
* `replyBody`/`outcome`/`objective` use `.nullish()`, not `.optional()`: Gemini's
|
|
8
8
|
* `responseMimeType: "application/json"` mode fills every key it considered rather than
|
|
9
|
-
* omitting the ones that don't apply, so a plain reply with no
|
|
10
|
-
* `"
|
|
9
|
+
* omitting the ones that don't apply, so a plain reply with no outcome comes back as
|
|
10
|
+
* `"outcome": null` (not an absent key) — `.optional()` alone rejects that.
|
|
11
11
|
*/
|
|
12
12
|
export declare const emailAutopilotDecisionSchema: z.ZodObject<{
|
|
13
13
|
action: z.ZodEnum<{
|
|
@@ -17,7 +17,7 @@ export declare const emailAutopilotDecisionSchema: z.ZodObject<{
|
|
|
17
17
|
escalate: "escalate";
|
|
18
18
|
}>;
|
|
19
19
|
replyBody: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
|
-
|
|
20
|
+
outcome: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
21
|
objective: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
22
22
|
amount: z.ZodOptional<z.ZodNumber>;
|
|
23
23
|
dueDate: z.ZodOptional<z.ZodString>;
|
package/dist/schemas/email.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
/**
|
|
3
3
|
* The structured decision the EMAIL/WHATSAPP autopilots return for an inbound reply.
|
|
4
|
-
* Validated so a model can't drive the loop with malformed output. `
|
|
5
|
-
* contact-log
|
|
4
|
+
* Validated so a model can't drive the loop with malformed output. `outcome` mirrors the
|
|
5
|
+
* contact-log outcome axis; `objective` carries promise details when the reply implies one.
|
|
6
6
|
*
|
|
7
|
-
* `replyBody`/`
|
|
7
|
+
* `replyBody`/`outcome`/`objective` use `.nullish()`, not `.optional()`: Gemini's
|
|
8
8
|
* `responseMimeType: "application/json"` mode fills every key it considered rather than
|
|
9
|
-
* omitting the ones that don't apply, so a plain reply with no
|
|
10
|
-
* `"
|
|
9
|
+
* omitting the ones that don't apply, so a plain reply with no outcome comes back as
|
|
10
|
+
* `"outcome": null` (not an absent key) — `.optional()` alone rejects that.
|
|
11
11
|
*/
|
|
12
12
|
export const emailAutopilotDecisionSchema = z.object({
|
|
13
13
|
action: z.enum(["reply", "ignore", "resolve", "escalate"]),
|
|
14
14
|
replyBody: z.string().nullish(),
|
|
15
|
-
|
|
15
|
+
outcome: z.string().nullish(),
|
|
16
16
|
objective: z
|
|
17
17
|
.object({
|
|
18
18
|
amount: z.number().optional(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/schemas/email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC1D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC/B,
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../src/schemas/email.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAC1D,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE;IAC7B,SAAS,EAAE,CAAC;SACT,MAAM,CAAC;QACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KAC5B,CAAC;SACD,OAAO,EAAE;CACb,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC"}
|