@absolutejs/voice 0.0.22-beta.522 → 0.0.22-beta.523
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/index.d.ts +4 -0
- package/dist/index.js +136 -0
- package/dist/variableAnalytics.d.ts +47 -0
- package/dist/zeroDataRetention.d.ts +41 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,10 @@ export { DEFAULT_VOICE_REDACTION_PATTERNS, createVoiceTranscriptRedactor, redact
|
|
|
81
81
|
export type { CreateVoiceTranscriptRedactorOptions, VoiceRedactionPattern, VoiceTranscriptRedactor, } from "./redaction";
|
|
82
82
|
export { deriveVoiceRecordingRedactionRanges, redactVoiceRecording, } from "./recordingRedaction";
|
|
83
83
|
export type { DeriveVoiceRecordingRedactionRangesInput, RedactVoiceRecordingInput, RedactVoiceRecordingResult, VoiceRecordingRedactionRange, } from "./recordingRedaction";
|
|
84
|
+
export { buildVoiceVariableAnalytics } from "./variableAnalytics";
|
|
85
|
+
export type { BuildVoiceVariableAnalyticsInput, VoiceAnalyticsCall, VoiceAnalyticsVariableValue, VoiceVariableAnalyticsReport, VoiceVariableBreakdown, VoiceVariableValueStats, } from "./variableAnalytics";
|
|
86
|
+
export { VOICE_ZERO_DATA_RETENTION_REDACTION_MARKER, createVoiceZeroDataRetentionPolicy, isVoiceZeroDataRetentionActive, scrubVoiceTraceForZeroDataRetention, scrubVoiceTurnForZeroDataRetention, shouldRetainVoiceRecording, shouldRetainVoiceTranscript, } from "./zeroDataRetention";
|
|
87
|
+
export type { CreateVoiceZeroDataRetentionPolicyOptions, VoiceZeroDataRetentionMode, VoiceZeroDataRetentionPolicy, VoiceZeroDataRetentionRetainFlags, } from "./zeroDataRetention";
|
|
84
88
|
export { DEFAULT_VOICE_PRICE_BOOK, createVoiceCostAccountant, } from "./costAccounting";
|
|
85
89
|
export type { CreateVoiceCostAccountantOptions, VoiceCostAccountant, VoiceCostBreakdown, VoiceCostLLMRecord, VoiceCostSTTRecord, VoiceCostTTSRecord, VoiceCostTelephonyRecord, VoicePriceBook, VoiceProviderRates, } from "./costAccounting";
|
|
86
90
|
export { describeVoiceAssistantMode, resolveVoiceAssistantMode, } from "./assistantMode";
|
package/dist/index.js
CHANGED
|
@@ -35794,6 +35794,134 @@ var redactVoiceRecording = (input) => {
|
|
|
35794
35794
|
redactedCount: ranges.length
|
|
35795
35795
|
};
|
|
35796
35796
|
};
|
|
35797
|
+
// src/variableAnalytics.ts
|
|
35798
|
+
var stringifyValue = (value) => {
|
|
35799
|
+
if (value === null || value === undefined)
|
|
35800
|
+
return "(none)";
|
|
35801
|
+
return String(value);
|
|
35802
|
+
};
|
|
35803
|
+
var mean = (values) => values.length === 0 ? null : values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
35804
|
+
var successRateFor = (calls, successOutcomes) => {
|
|
35805
|
+
const flagged = calls.filter((call) => call.success !== undefined || call.outcome !== undefined);
|
|
35806
|
+
if (flagged.length === 0)
|
|
35807
|
+
return null;
|
|
35808
|
+
const successes = flagged.filter((call) => call.success !== undefined ? call.success : call.outcome !== undefined && successOutcomes.has(call.outcome.toLowerCase())).length;
|
|
35809
|
+
return successes / flagged.length;
|
|
35810
|
+
};
|
|
35811
|
+
var buildVoiceVariableAnalytics = (input) => {
|
|
35812
|
+
const successOutcomes = new Set((input.successOutcomes ?? ["won", "resolved", "qualified", "completed", "booked"]).map((outcome) => outcome.toLowerCase()));
|
|
35813
|
+
const totalCalls = input.calls.length;
|
|
35814
|
+
const overall = {
|
|
35815
|
+
avgCostUsd: mean(input.calls.map((call) => call.costUsd).filter((cost) => typeof cost === "number")),
|
|
35816
|
+
avgDurationSeconds: mean(input.calls.map((call) => call.durationSeconds).filter((duration) => typeof duration === "number")),
|
|
35817
|
+
successRate: successRateFor(input.calls, successOutcomes)
|
|
35818
|
+
};
|
|
35819
|
+
const byVariable = {};
|
|
35820
|
+
for (const variable of input.variables) {
|
|
35821
|
+
const groups = new Map;
|
|
35822
|
+
let missingCount = 0;
|
|
35823
|
+
for (const call of input.calls) {
|
|
35824
|
+
const raw = call.variables[variable];
|
|
35825
|
+
if (raw === undefined || raw === null) {
|
|
35826
|
+
missingCount += 1;
|
|
35827
|
+
continue;
|
|
35828
|
+
}
|
|
35829
|
+
const key = stringifyValue(raw);
|
|
35830
|
+
const bucket = groups.get(key) ?? [];
|
|
35831
|
+
bucket.push(call);
|
|
35832
|
+
groups.set(key, bucket);
|
|
35833
|
+
}
|
|
35834
|
+
let values = [];
|
|
35835
|
+
for (const [value, calls] of groups) {
|
|
35836
|
+
const outcomes = {};
|
|
35837
|
+
for (const call of calls) {
|
|
35838
|
+
if (call.outcome) {
|
|
35839
|
+
outcomes[call.outcome] = (outcomes[call.outcome] ?? 0) + 1;
|
|
35840
|
+
}
|
|
35841
|
+
}
|
|
35842
|
+
values.push({
|
|
35843
|
+
avgCostUsd: mean(calls.map((call) => call.costUsd).filter((cost) => typeof cost === "number")),
|
|
35844
|
+
avgDurationSeconds: mean(calls.map((call) => call.durationSeconds).filter((d) => typeof d === "number")),
|
|
35845
|
+
count: calls.length,
|
|
35846
|
+
outcomes,
|
|
35847
|
+
share: totalCalls === 0 ? 0 : calls.length / totalCalls,
|
|
35848
|
+
successRate: successRateFor(calls, successOutcomes),
|
|
35849
|
+
value
|
|
35850
|
+
});
|
|
35851
|
+
}
|
|
35852
|
+
values.sort((left, right) => right.count - left.count);
|
|
35853
|
+
if (input.topValuesPerVariable !== undefined) {
|
|
35854
|
+
values = values.slice(0, input.topValuesPerVariable);
|
|
35855
|
+
}
|
|
35856
|
+
byVariable[variable] = {
|
|
35857
|
+
distinctValues: groups.size,
|
|
35858
|
+
missingCount,
|
|
35859
|
+
values,
|
|
35860
|
+
variable
|
|
35861
|
+
};
|
|
35862
|
+
}
|
|
35863
|
+
return { byVariable, overall, totalCalls };
|
|
35864
|
+
};
|
|
35865
|
+
// src/zeroDataRetention.ts
|
|
35866
|
+
var RETAIN_ALL = {
|
|
35867
|
+
assistantText: true,
|
|
35868
|
+
metadata: true,
|
|
35869
|
+
recordings: true,
|
|
35870
|
+
traceText: true,
|
|
35871
|
+
transcriptText: true
|
|
35872
|
+
};
|
|
35873
|
+
var RETAIN_NONE = {
|
|
35874
|
+
assistantText: false,
|
|
35875
|
+
metadata: false,
|
|
35876
|
+
recordings: false,
|
|
35877
|
+
traceText: false,
|
|
35878
|
+
transcriptText: false
|
|
35879
|
+
};
|
|
35880
|
+
var REDACTED = "[redacted:zdr]";
|
|
35881
|
+
var createVoiceZeroDataRetentionPolicy = (options = {}) => {
|
|
35882
|
+
const mode = options.mode ?? "off";
|
|
35883
|
+
const base = mode === "strict" ? RETAIN_NONE : mode === "off" ? RETAIN_ALL : RETAIN_ALL;
|
|
35884
|
+
return {
|
|
35885
|
+
mode,
|
|
35886
|
+
retain: { ...base, ...options.retain ?? {} }
|
|
35887
|
+
};
|
|
35888
|
+
};
|
|
35889
|
+
var isVoiceZeroDataRetentionActive = (policy) => policy.mode !== "off" && Object.values(policy.retain).some((retain) => retain === false);
|
|
35890
|
+
var shouldRetainVoiceRecording = (policy) => policy.retain.recordings;
|
|
35891
|
+
var shouldRetainVoiceTranscript = (policy) => policy.retain.transcriptText;
|
|
35892
|
+
var scrubVoiceTurnForZeroDataRetention = (turn, policy) => {
|
|
35893
|
+
if (!isVoiceZeroDataRetentionActive(policy))
|
|
35894
|
+
return turn;
|
|
35895
|
+
const scrubbed = {
|
|
35896
|
+
...turn,
|
|
35897
|
+
text: policy.retain.transcriptText ? turn.text : REDACTED,
|
|
35898
|
+
transcripts: policy.retain.transcriptText ? turn.transcripts : turn.transcripts.map((transcript) => ({
|
|
35899
|
+
...transcript,
|
|
35900
|
+
text: REDACTED
|
|
35901
|
+
}))
|
|
35902
|
+
};
|
|
35903
|
+
if (!policy.retain.assistantText && scrubbed.assistantText !== undefined) {
|
|
35904
|
+
scrubbed.assistantText = REDACTED;
|
|
35905
|
+
}
|
|
35906
|
+
if (!policy.retain.metadata) {
|
|
35907
|
+
delete scrubbed.attachments;
|
|
35908
|
+
}
|
|
35909
|
+
return scrubbed;
|
|
35910
|
+
};
|
|
35911
|
+
var scrubVoiceTraceForZeroDataRetention = (event, policy) => {
|
|
35912
|
+
if (!isVoiceZeroDataRetentionActive(policy) || policy.retain.traceText) {
|
|
35913
|
+
return event;
|
|
35914
|
+
}
|
|
35915
|
+
const payload = event.payload;
|
|
35916
|
+
if (!payload || typeof payload !== "object")
|
|
35917
|
+
return event;
|
|
35918
|
+
const scrubbedPayload = {};
|
|
35919
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
35920
|
+
scrubbedPayload[key] = typeof value === "string" ? REDACTED : value;
|
|
35921
|
+
}
|
|
35922
|
+
return { ...event, payload: scrubbedPayload };
|
|
35923
|
+
};
|
|
35924
|
+
var VOICE_ZERO_DATA_RETENTION_REDACTION_MARKER = REDACTED;
|
|
35797
35925
|
// src/costAccounting.ts
|
|
35798
35926
|
var DEFAULT_VOICE_PRICE_BOOK = {
|
|
35799
35927
|
"anthropic:claude-opus-4-5": {
|
|
@@ -51913,8 +52041,12 @@ export {
|
|
|
51913
52041
|
signVoiceTwilioWebhook,
|
|
51914
52042
|
signVoicePlivoWebhook,
|
|
51915
52043
|
shouldRetryCampaignAttempt,
|
|
52044
|
+
shouldRetainVoiceTranscript,
|
|
52045
|
+
shouldRetainVoiceRecording,
|
|
51916
52046
|
shapeTelephonyAssistantText,
|
|
51917
52047
|
selectVoiceTraceEventsForPrune,
|
|
52048
|
+
scrubVoiceTurnForZeroDataRetention,
|
|
52049
|
+
scrubVoiceTraceForZeroDataRetention,
|
|
51918
52050
|
scoreVoiceNoShowRisk,
|
|
51919
52051
|
saveVoiceIncidentBundleArtifact,
|
|
51920
52052
|
runVoiceToolContractSuite,
|
|
@@ -52116,6 +52248,7 @@ export {
|
|
|
52116
52248
|
listVoiceProviderDecisionTraces,
|
|
52117
52249
|
listVoiceOpsTasks,
|
|
52118
52250
|
isWithinCampaignWindow,
|
|
52251
|
+
isVoiceZeroDataRetentionActive,
|
|
52119
52252
|
isVoiceOpsTaskOverdue,
|
|
52120
52253
|
isPhoneOnDNC,
|
|
52121
52254
|
interleaveStereoPcm,
|
|
@@ -52202,6 +52335,7 @@ export {
|
|
|
52202
52335
|
decodeTwilioMulawBase64,
|
|
52203
52336
|
deadLetterVoiceOpsTask,
|
|
52204
52337
|
createVoiceZeroRetentionPolicy,
|
|
52338
|
+
createVoiceZeroDataRetentionPolicy,
|
|
52205
52339
|
createVoiceZendeskTicketUpdateSink,
|
|
52206
52340
|
createVoiceZendeskTicketSyncSinks,
|
|
52207
52341
|
createVoiceZendeskTicketSink,
|
|
@@ -52611,6 +52745,7 @@ export {
|
|
|
52611
52745
|
collectVoiceDTMFInput,
|
|
52612
52746
|
collectVoiceCampaignTemplateVariables,
|
|
52613
52747
|
claimVoiceOpsTask,
|
|
52748
|
+
buildVoiceVariableAnalytics,
|
|
52614
52749
|
buildVoiceTraceReplay,
|
|
52615
52750
|
buildVoiceTraceDeliveryReport,
|
|
52616
52751
|
buildVoiceTelephonyWebhookSecurityReport,
|
|
@@ -52760,6 +52895,7 @@ export {
|
|
|
52760
52895
|
appendVoiceIOProviderRouterTraceEvent,
|
|
52761
52896
|
aggregateVoiceTurnLatencySpans,
|
|
52762
52897
|
acknowledgeVoiceMonitorIssue,
|
|
52898
|
+
VOICE_ZERO_DATA_RETENTION_REDACTION_MARKER,
|
|
52763
52899
|
VOICE_WEBHOOK_TIMESTAMP_HEADER,
|
|
52764
52900
|
VOICE_WEBHOOK_SIGNATURE_HEADER,
|
|
52765
52901
|
VOICE_TCPA_DEFAULT_WINDOW,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type VoiceAnalyticsVariableValue = string | number | boolean | null;
|
|
2
|
+
export type VoiceAnalyticsCall = {
|
|
3
|
+
sessionId: string;
|
|
4
|
+
variables: Record<string, VoiceAnalyticsVariableValue>;
|
|
5
|
+
durationSeconds?: number;
|
|
6
|
+
costUsd?: number;
|
|
7
|
+
outcome?: string;
|
|
8
|
+
success?: boolean;
|
|
9
|
+
at?: number;
|
|
10
|
+
};
|
|
11
|
+
export type VoiceVariableValueStats = {
|
|
12
|
+
value: string;
|
|
13
|
+
count: number;
|
|
14
|
+
share: number;
|
|
15
|
+
successRate: number | null;
|
|
16
|
+
avgDurationSeconds: number | null;
|
|
17
|
+
avgCostUsd: number | null;
|
|
18
|
+
outcomes: Record<string, number>;
|
|
19
|
+
};
|
|
20
|
+
export type VoiceVariableBreakdown = {
|
|
21
|
+
variable: string;
|
|
22
|
+
distinctValues: number;
|
|
23
|
+
missingCount: number;
|
|
24
|
+
values: VoiceVariableValueStats[];
|
|
25
|
+
};
|
|
26
|
+
export type VoiceVariableAnalyticsReport = {
|
|
27
|
+
totalCalls: number;
|
|
28
|
+
overall: {
|
|
29
|
+
successRate: number | null;
|
|
30
|
+
avgDurationSeconds: number | null;
|
|
31
|
+
avgCostUsd: number | null;
|
|
32
|
+
};
|
|
33
|
+
byVariable: Record<string, VoiceVariableBreakdown>;
|
|
34
|
+
};
|
|
35
|
+
export type BuildVoiceVariableAnalyticsInput = {
|
|
36
|
+
calls: ReadonlyArray<VoiceAnalyticsCall>;
|
|
37
|
+
/** Variable keys to break analytics down by. */
|
|
38
|
+
variables: ReadonlyArray<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Treat these outcome strings as successes when a call has no explicit
|
|
41
|
+
* `success` flag. Case-insensitive.
|
|
42
|
+
*/
|
|
43
|
+
successOutcomes?: ReadonlyArray<string>;
|
|
44
|
+
/** Cap the values returned per variable (highest count first). */
|
|
45
|
+
topValuesPerVariable?: number;
|
|
46
|
+
};
|
|
47
|
+
export declare const buildVoiceVariableAnalytics: (input: BuildVoiceVariableAnalyticsInput) => VoiceVariableAnalyticsReport;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { VoiceTraceEvent } from "./trace";
|
|
2
|
+
import type { VoiceTurnRecord } from "./types";
|
|
3
|
+
export type VoiceZeroDataRetentionMode = "off" | "strict" | "custom";
|
|
4
|
+
export type VoiceZeroDataRetentionRetainFlags = {
|
|
5
|
+
/** Persist committed/partial transcript text. */
|
|
6
|
+
transcriptText: boolean;
|
|
7
|
+
/** Persist assistant response text. */
|
|
8
|
+
assistantText: boolean;
|
|
9
|
+
/** Persist recorded audio artifacts. */
|
|
10
|
+
recordings: boolean;
|
|
11
|
+
/** Persist free-text payloads on trace events. */
|
|
12
|
+
traceText: boolean;
|
|
13
|
+
/** Persist arbitrary session/turn metadata. */
|
|
14
|
+
metadata: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type VoiceZeroDataRetentionPolicy = {
|
|
17
|
+
mode: VoiceZeroDataRetentionMode;
|
|
18
|
+
retain: VoiceZeroDataRetentionRetainFlags;
|
|
19
|
+
};
|
|
20
|
+
export type CreateVoiceZeroDataRetentionPolicyOptions = {
|
|
21
|
+
mode?: VoiceZeroDataRetentionMode;
|
|
22
|
+
/** Per-flag overrides; only meaningful with mode "custom" (or to relax "strict"). */
|
|
23
|
+
retain?: Partial<VoiceZeroDataRetentionRetainFlags>;
|
|
24
|
+
};
|
|
25
|
+
export declare const createVoiceZeroDataRetentionPolicy: (options?: CreateVoiceZeroDataRetentionPolicyOptions) => VoiceZeroDataRetentionPolicy;
|
|
26
|
+
export declare const isVoiceZeroDataRetentionActive: (policy: VoiceZeroDataRetentionPolicy) => boolean;
|
|
27
|
+
export declare const shouldRetainVoiceRecording: (policy: VoiceZeroDataRetentionPolicy) => boolean;
|
|
28
|
+
export declare const shouldRetainVoiceTranscript: (policy: VoiceZeroDataRetentionPolicy) => boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Returns a scrubbed copy of a turn record honoring the ZDR policy. Structural
|
|
31
|
+
* fields (ids, timestamps, transcript count, citation ids) are preserved;
|
|
32
|
+
* content fields are replaced with a redaction marker or dropped.
|
|
33
|
+
*/
|
|
34
|
+
export declare const scrubVoiceTurnForZeroDataRetention: <TResult = unknown>(turn: VoiceTurnRecord<TResult>, policy: VoiceZeroDataRetentionPolicy) => VoiceTurnRecord<TResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Returns a scrubbed copy of a trace event honoring the ZDR policy. Drops or
|
|
37
|
+
* masks free-text payload fields while keeping the event type, ids, and
|
|
38
|
+
* timestamps so observability/lifecycle accounting still works.
|
|
39
|
+
*/
|
|
40
|
+
export declare const scrubVoiceTraceForZeroDataRetention: (event: VoiceTraceEvent, policy: VoiceZeroDataRetentionPolicy) => VoiceTraceEvent;
|
|
41
|
+
export declare const VOICE_ZERO_DATA_RETENTION_REDACTION_MARKER = "[redacted:zdr]";
|