@absolutejs/voice 0.0.22-beta.243 → 0.0.22-beta.245
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/README.md +52 -1
- package/dist/guardrails.d.ts +108 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +398 -0
- package/dist/postCallAnalysis.d.ts +98 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ These are the primitive-first paths a Vapi-style buyer usually needs. Each path
|
|
|
37
37
|
| Phone voice assistant | `createVoicePhoneAgent(...)` | carrier matrix, setup instructions, phone smoke contract, production readiness, operations record | phone setup HTML/JSON, smoke HTML/JSON, framework status UI |
|
|
38
38
|
| Multi-specialist support flow | `createVoiceAgentSquad(...)` | squad contract, handoff traces, context traces, operations record | Agent Squad status hooks/composables/services/widgets |
|
|
39
39
|
| Business actions and tools | `createVoiceAgentTool(...)` plus agent tool runtime | tool contracts, audit events, integration events, outcome contracts | operations record, action center, contract routes |
|
|
40
|
+
| Guardrails and policy checks | `createVoiceGuardrailPolicy(...)` plus `createVoiceGuardrailRoutes(...)` | blocking/warning decisions, redacted content, `assistant.guardrail` trace events | guardrail JSON/Markdown routes and operations record traces |
|
|
40
41
|
| Provider routing and fallback | provider routers, health checks, simulation controls | provider contract matrix, provider-stage traces, latency SLO reports | provider contract hooks/composables/services/widgets |
|
|
41
42
|
| Production operations | ops status, ops recovery, production readiness, delivery runtime | readiness gates, recovery report, incident Markdown, delivery queues | ops action center, delivery runtime UI, operations record |
|
|
42
43
|
| Outbound campaigns | `createVoiceCampaignRoutes(...)` | recipient validation, consent/dedupe, carrier dry-run, campaign readiness | campaign routes and operations-record-linked attempt proof |
|
|
@@ -68,7 +69,7 @@ Use this checklist when a buyer asks, "How do I know this replaces a hosted voic
|
|
|
68
69
|
| Can I prove provider fallback and latency? | provider contract matrix, provider status UI, `/turn-latency`, `/live-latency` | Provider choice, fallback behavior, server turn timing, browser p50/p95 timing |
|
|
69
70
|
| Can operators intervene safely? | live-ops routes, action center, ops action audit routes, operations record | Pause/resume/takeover, injected instructions, operator action audit trail |
|
|
70
71
|
| Can I run outbound campaigns? | `/voice/campaigns`, `/voice/campaigns/observability`, `/api/voice/campaigns/readiness-proof` | Recipient import evidence, consent/dedupe checks, scheduling policy, worker-safe attempts |
|
|
71
|
-
| Can I handle post-call workflow? | reviews, tasks, integration events, outcome contracts, operations record |
|
|
72
|
+
| Can I handle post-call workflow? | `createVoicePostCallAnalysisRoutes(...)`, reviews, tasks, integration events, outcome contracts, operations record | Extracted-field proof, task creation, webhook/sink delivery, matched session proof |
|
|
72
73
|
| Can I keep data in my infrastructure? | `/data-control`, `/data-control/audit.md`, retention dry-run/apply routes | Customer-owned storage, redaction, audit export, guarded deletion, zero-retention planning |
|
|
73
74
|
| Can I prove release readiness? | `/production-readiness`, `/ops-recovery`, delivery runtime, readiness profiles | Deploy gates for session health, audits, delivery queues, provider/campaign/phone proof |
|
|
74
75
|
|
|
@@ -82,6 +83,56 @@ For a demo, the fastest convincing path is:
|
|
|
82
83
|
|
|
83
84
|
If those five surfaces are green and linked, the buyer can see the core difference from Vapi-style hosted orchestration: the operational proof lives inside the app, not in a vendor dashboard.
|
|
84
85
|
|
|
86
|
+
## Post-Call Analysis Proof
|
|
87
|
+
|
|
88
|
+
Use `createVoicePostCallAnalysisRoutes(...)` when the hosted-platform feature you need is call analysis plus follow-up proof. It validates that required extracted fields exist, expected ops tasks were created, integration/webhook events delivered, and the report links back to `/voice-operations/:sessionId`.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { createVoicePostCallAnalysisRoutes } from '@absolutejs/voice';
|
|
92
|
+
|
|
93
|
+
app.use(
|
|
94
|
+
createVoicePostCallAnalysisRoutes({
|
|
95
|
+
path: '/api/voice/post-call-analysis',
|
|
96
|
+
operationRecordBasePath: '/voice-operations/:sessionId',
|
|
97
|
+
reviews: runtime.reviews,
|
|
98
|
+
tasks: runtime.tasks,
|
|
99
|
+
integrationEvents: runtime.events,
|
|
100
|
+
source: ({ reviewId, sessionId }) => ({
|
|
101
|
+
reviewId,
|
|
102
|
+
sessionId,
|
|
103
|
+
// Use your own extractor output here, for example fields persisted from an LLM/tool result.
|
|
104
|
+
extractedFields: loadExtractedPostCallFields(reviewId ?? sessionId)
|
|
105
|
+
}),
|
|
106
|
+
fields: [
|
|
107
|
+
{ path: 'review.postCall.target', label: 'customer target' },
|
|
108
|
+
{ path: 'customerId' },
|
|
109
|
+
{ path: 'category' }
|
|
110
|
+
],
|
|
111
|
+
requiredTaskKinds: ['support-triage'],
|
|
112
|
+
requireDeliveredIntegrationEvent: true
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Guardrails
|
|
118
|
+
|
|
119
|
+
Use `createVoiceGuardrailRoutes(...)` when you need code-owned policy checks for what an agent may say, what tool payloads may contain, or which transcript content should warn/redact before downstream workflow. The primitive does not force a moderation vendor or hosted dashboard; it returns JSON/Markdown proof and can emit `assistant.guardrail` trace events.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import {
|
|
123
|
+
createVoiceGuardrailRoutes,
|
|
124
|
+
voiceGuardrailPolicyPresets
|
|
125
|
+
} from '@absolutejs/voice';
|
|
126
|
+
|
|
127
|
+
app.use(
|
|
128
|
+
createVoiceGuardrailRoutes({
|
|
129
|
+
path: '/api/voice/guardrails',
|
|
130
|
+
policies: [voiceGuardrailPolicyPresets.supportSafeDefaults],
|
|
131
|
+
trace: runtime.traces
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
85
136
|
## Use-Case Recipe: Support Triage
|
|
86
137
|
|
|
87
138
|
Use this path when you want a Vapi-style support assistant that can answer web or phone calls, look up customer context, route billing issues to a specialist, create follow-up work, and leave one debuggable call record. It is a recipe over primitives, not a support app kit.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { VoiceTraceEventStore } from './trace';
|
|
3
|
+
export type VoiceGuardrailStage = 'assistant-output' | 'handoff' | 'model-input' | 'tool-input' | 'tool-output' | 'transcript';
|
|
4
|
+
export type VoiceGuardrailSeverity = 'block' | 'warn';
|
|
5
|
+
export type VoiceGuardrailStatus = 'blocked' | 'pass' | 'warn';
|
|
6
|
+
export type VoiceGuardrailRule = {
|
|
7
|
+
action?: VoiceGuardrailSeverity;
|
|
8
|
+
description?: string;
|
|
9
|
+
id: string;
|
|
10
|
+
label?: string;
|
|
11
|
+
match: RegExp | string | ((input: VoiceGuardrailEvaluationInput) => boolean | Promise<boolean>);
|
|
12
|
+
redactWith?: string;
|
|
13
|
+
stages?: VoiceGuardrailStage[];
|
|
14
|
+
};
|
|
15
|
+
export type VoiceGuardrailEvaluationInput = {
|
|
16
|
+
content?: unknown;
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
stage: VoiceGuardrailStage;
|
|
20
|
+
turnId?: string;
|
|
21
|
+
};
|
|
22
|
+
export type VoiceGuardrailFinding = {
|
|
23
|
+
action: VoiceGuardrailSeverity;
|
|
24
|
+
description?: string;
|
|
25
|
+
label: string;
|
|
26
|
+
ruleId: string;
|
|
27
|
+
stage: VoiceGuardrailStage;
|
|
28
|
+
};
|
|
29
|
+
export type VoiceGuardrailDecision = {
|
|
30
|
+
allowed: boolean;
|
|
31
|
+
checkedAt: number;
|
|
32
|
+
content?: unknown;
|
|
33
|
+
findings: VoiceGuardrailFinding[];
|
|
34
|
+
redactedContent?: unknown;
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
stage: VoiceGuardrailStage;
|
|
37
|
+
status: VoiceGuardrailStatus;
|
|
38
|
+
turnId?: string;
|
|
39
|
+
};
|
|
40
|
+
export type VoiceGuardrailPolicy = {
|
|
41
|
+
defaultAction?: VoiceGuardrailSeverity;
|
|
42
|
+
id: string;
|
|
43
|
+
label?: string;
|
|
44
|
+
rules: VoiceGuardrailRule[];
|
|
45
|
+
};
|
|
46
|
+
export type VoiceGuardrailReport = {
|
|
47
|
+
checkedAt: number;
|
|
48
|
+
decisions: VoiceGuardrailDecision[];
|
|
49
|
+
failed: number;
|
|
50
|
+
policies: Array<{
|
|
51
|
+
id: string;
|
|
52
|
+
label?: string;
|
|
53
|
+
rules: number;
|
|
54
|
+
}>;
|
|
55
|
+
status: 'fail' | 'pass' | 'warn';
|
|
56
|
+
summary: {
|
|
57
|
+
blocked: number;
|
|
58
|
+
passed: number;
|
|
59
|
+
warned: number;
|
|
60
|
+
};
|
|
61
|
+
total: number;
|
|
62
|
+
};
|
|
63
|
+
export type VoiceGuardrailRoutesOptions = {
|
|
64
|
+
headers?: HeadersInit;
|
|
65
|
+
name?: string;
|
|
66
|
+
path?: string;
|
|
67
|
+
policies?: VoiceGuardrailPolicy[];
|
|
68
|
+
source?: ((input: VoiceGuardrailEvaluationInput) => Promise<VoiceGuardrailDecision | VoiceGuardrailReport> | VoiceGuardrailDecision | VoiceGuardrailReport) | VoiceGuardrailDecision | VoiceGuardrailReport;
|
|
69
|
+
trace?: VoiceTraceEventStore;
|
|
70
|
+
};
|
|
71
|
+
export declare const evaluateVoiceGuardrailPolicy: (policy: VoiceGuardrailPolicy, input: VoiceGuardrailEvaluationInput) => Promise<VoiceGuardrailDecision>;
|
|
72
|
+
export declare const buildVoiceGuardrailReport: (input?: {
|
|
73
|
+
decisions: VoiceGuardrailDecision[];
|
|
74
|
+
policies?: VoiceGuardrailPolicy[];
|
|
75
|
+
}) => VoiceGuardrailReport;
|
|
76
|
+
export declare const createVoiceGuardrailPolicy: (policy: VoiceGuardrailPolicy) => VoiceGuardrailPolicy;
|
|
77
|
+
export declare const voiceGuardrailPolicyPresets: {
|
|
78
|
+
supportSafeDefaults: VoiceGuardrailPolicy;
|
|
79
|
+
};
|
|
80
|
+
export declare const renderVoiceGuardrailMarkdown: (report: VoiceGuardrailReport) => string;
|
|
81
|
+
export declare const createVoiceGuardrailRoutes: (options?: VoiceGuardrailRoutesOptions) => Elysia<"", {
|
|
82
|
+
decorator: {};
|
|
83
|
+
store: {};
|
|
84
|
+
derive: {};
|
|
85
|
+
resolve: {};
|
|
86
|
+
}, {
|
|
87
|
+
typebox: {};
|
|
88
|
+
error: {};
|
|
89
|
+
}, {
|
|
90
|
+
schema: {};
|
|
91
|
+
standaloneSchema: {};
|
|
92
|
+
macro: {};
|
|
93
|
+
macroFn: {};
|
|
94
|
+
parser: {};
|
|
95
|
+
response: {};
|
|
96
|
+
}, {}, {
|
|
97
|
+
derive: {};
|
|
98
|
+
resolve: {};
|
|
99
|
+
schema: {};
|
|
100
|
+
standaloneSchema: {};
|
|
101
|
+
response: {};
|
|
102
|
+
}, {
|
|
103
|
+
derive: {};
|
|
104
|
+
resolve: {};
|
|
105
|
+
schema: {};
|
|
106
|
+
standaloneSchema: {};
|
|
107
|
+
response: {};
|
|
108
|
+
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -83,6 +83,8 @@ export { createVoiceCallReviewFromSession, recordVoiceRuntimeOps } from './runti
|
|
|
83
83
|
export { createVoiceOpsRuntime } from './opsRuntime';
|
|
84
84
|
export { resolveVoiceOpsPreset } from './opsPresets';
|
|
85
85
|
export { resolveVoiceOutcomeRecipe } from './outcomeRecipes';
|
|
86
|
+
export { buildVoicePostCallAnalysisReport, createVoicePostCallAnalysisRoutes, renderVoicePostCallAnalysisMarkdown } from './postCallAnalysis';
|
|
87
|
+
export { buildVoiceGuardrailReport, createVoiceGuardrailPolicy, createVoiceGuardrailRoutes, evaluateVoiceGuardrailPolicy, renderVoiceGuardrailMarkdown, voiceGuardrailPolicyPresets } from './guardrails';
|
|
86
88
|
export { createId, createVoiceSessionRecord } from './store';
|
|
87
89
|
export { createVoiceSTTRoutingCorrectionHandler, resolveVoiceSTTRoutingStrategy } from './routing';
|
|
88
90
|
export { applyRiskTieredPhraseHintCorrections, applyPhraseHintCorrections, createDomainLexicon, createDomainPhraseHints, createPhraseHintCorrectionHandler, createRiskyTurnCorrectionHandler } from './correction';
|
|
@@ -135,6 +137,8 @@ export type { VoiceToolContractCase, VoiceToolContractCaseReport, VoiceToolContr
|
|
|
135
137
|
export type { VoiceOpsRuntime, VoiceOpsRuntimeConfig, VoiceOpsRuntimeSummary, VoiceOpsRuntimeSinkWorkerConfig, VoiceOpsRuntimeTaskWorkerConfig, VoiceOpsRuntimeTickResult, VoiceOpsRuntimeWebhookWorkerConfig } from './opsRuntime';
|
|
136
138
|
export type { VoiceOpsPresetName, VoiceOpsPresetOverrides, VoiceResolvedOpsPreset } from './opsPresets';
|
|
137
139
|
export type { VoiceOutcomeRecipe, VoiceOutcomeRecipeName, VoiceOutcomeRecipeOptions } from './outcomeRecipes';
|
|
140
|
+
export type { VoicePostCallAnalysisFieldRequirement, VoicePostCallAnalysisFieldResult, VoicePostCallAnalysisIssue, VoicePostCallAnalysisIssueCode, VoicePostCallAnalysisOptions, VoicePostCallAnalysisReport, VoicePostCallAnalysisRoutesOptions, VoicePostCallAnalysisStatus } from './postCallAnalysis';
|
|
141
|
+
export type { VoiceGuardrailDecision, VoiceGuardrailEvaluationInput, VoiceGuardrailFinding, VoiceGuardrailPolicy, VoiceGuardrailReport, VoiceGuardrailRoutesOptions, VoiceGuardrailRule, VoiceGuardrailSeverity, VoiceGuardrailStage, VoiceGuardrailStatus } from './guardrails';
|
|
138
142
|
export type { VoiceCRMActivitySinkOptions, VoiceHubSpotTaskSinkOptions, VoiceHubSpotTaskUpdateSinkOptions, VoiceHelpdeskTicketSinkOptions, VoiceIntegrationHTTPSinkOptions, VoiceIntegrationSink, VoiceIntegrationSinkDeliveryResult, VoiceLinearIssueSinkOptions, VoiceLinearIssueUpdateSinkOptions, VoiceZendeskTicketSinkOptions, VoiceZendeskTicketUpdateSinkOptions } from './opsSinks';
|
|
139
143
|
export type { VoiceOpsWebhookEnvelope, VoiceOpsWebhookEntity, VoiceOpsWebhookLinkResolver, VoiceOpsWebhookReceiverRoutesOptions, VoiceOpsWebhookSinkOptions, VoiceOpsWebhookVerificationResult } from './opsWebhook';
|
|
140
144
|
export type { VoiceHandoffDelivery, VoiceHandoffDeliveryRecord, VoiceHandoffDeliveryRecordInput, VoiceHandoffFanoutResult, VoiceQueuedHandoffDeliveryOptions, VoiceTwilioRedirectHandoffAdapterOptions, VoiceWebhookHandoffAdapterOptions } from './handoff';
|
package/dist/index.js
CHANGED
|
@@ -28727,6 +28727,395 @@ var resolveVoiceOpsPreset = (name, overrides = {}) => {
|
|
|
28727
28727
|
taskPolicies: mergePolicies(preset.taskPolicies, overrides.taskPolicies)
|
|
28728
28728
|
};
|
|
28729
28729
|
};
|
|
28730
|
+
// src/postCallAnalysis.ts
|
|
28731
|
+
import { Elysia as Elysia49 } from "elysia";
|
|
28732
|
+
var isStore = (value) => Boolean(value) && typeof value === "object" && value !== null && ("list" in value);
|
|
28733
|
+
var asArray = async (value) => Array.isArray(value) ? value : isStore(value) ? await value.list() : [];
|
|
28734
|
+
var getPathValue3 = (source, path) => {
|
|
28735
|
+
const parts = path.split(".").filter(Boolean);
|
|
28736
|
+
let current = source;
|
|
28737
|
+
for (const part of parts) {
|
|
28738
|
+
if (!current || typeof current !== "object" || Array.isArray(current)) {
|
|
28739
|
+
return;
|
|
28740
|
+
}
|
|
28741
|
+
current = current[part];
|
|
28742
|
+
}
|
|
28743
|
+
return current;
|
|
28744
|
+
};
|
|
28745
|
+
var hasValue2 = (value) => {
|
|
28746
|
+
if (value === undefined || value === null) {
|
|
28747
|
+
return false;
|
|
28748
|
+
}
|
|
28749
|
+
if (typeof value === "string") {
|
|
28750
|
+
return value.trim().length > 0;
|
|
28751
|
+
}
|
|
28752
|
+
if (Array.isArray(value)) {
|
|
28753
|
+
return value.length > 0;
|
|
28754
|
+
}
|
|
28755
|
+
return true;
|
|
28756
|
+
};
|
|
28757
|
+
var matchesReview = (reviewId, id) => Boolean(reviewId && id && (id === reviewId || id.startsWith(`${reviewId}:`)));
|
|
28758
|
+
var matchesSession = (sessionId, event) => {
|
|
28759
|
+
const payloadSessionId = event.payload.sessionId;
|
|
28760
|
+
return Boolean(sessionId && (event.id === sessionId || event.id.startsWith(`${sessionId}:`) || payloadSessionId === sessionId));
|
|
28761
|
+
};
|
|
28762
|
+
var matchesIntegrationEvent = (input) => {
|
|
28763
|
+
const payloadReviewId = input.event.payload.reviewId;
|
|
28764
|
+
return matchesReview(input.reviewId, input.event.id) || payloadReviewId === input.reviewId || matchesSession(input.sessionId, input.event);
|
|
28765
|
+
};
|
|
28766
|
+
var normalizeOperationRecordHref = (basePath, sessionId) => {
|
|
28767
|
+
if (!basePath || !sessionId) {
|
|
28768
|
+
return;
|
|
28769
|
+
}
|
|
28770
|
+
return basePath.includes(":sessionId") ? basePath.replace(":sessionId", encodeURIComponent(sessionId)) : `${basePath.replace(/\/$/, "")}/${encodeURIComponent(sessionId)}`;
|
|
28771
|
+
};
|
|
28772
|
+
var isPostCallAnalysisReport = (value) => ("status" in value) && ("summary" in value) && Array.isArray(value.issues);
|
|
28773
|
+
var buildVoicePostCallAnalysisReport = async (options = {}) => {
|
|
28774
|
+
const reviews = await asArray(options.reviews);
|
|
28775
|
+
const review = options.review ?? reviews.find((candidate) => options.reviewId ? candidate.id === options.reviewId : options.sessionId ? candidate.id.startsWith(`${options.sessionId}:`) : false);
|
|
28776
|
+
const reviewId = options.reviewId ?? review?.id;
|
|
28777
|
+
const sessionId = options.sessionId ?? (reviewId?.endsWith(":review") ? reviewId.slice(0, -":review".length) : undefined);
|
|
28778
|
+
const allTasks = await asArray(options.tasks);
|
|
28779
|
+
const tasks = allTasks.filter((task) => reviewId ? task.reviewId === reviewId || task.intakeId === reviewId || matchesReview(reviewId, task.id) : false);
|
|
28780
|
+
const allIntegrationEvents = await asArray(options.integrationEvents);
|
|
28781
|
+
const integrationEvents = allIntegrationEvents.filter((event) => matchesIntegrationEvent({ event, reviewId, sessionId }));
|
|
28782
|
+
const fieldSource = {
|
|
28783
|
+
extractedFields: options.extractedFields ?? {},
|
|
28784
|
+
review
|
|
28785
|
+
};
|
|
28786
|
+
const fields = (options.fields ?? []).map((field) => {
|
|
28787
|
+
const value = getPathValue3(fieldSource.extractedFields, field.path) ?? getPathValue3(fieldSource, field.path);
|
|
28788
|
+
const required = field.required !== false;
|
|
28789
|
+
return {
|
|
28790
|
+
label: field.label ?? field.path,
|
|
28791
|
+
ok: !required || hasValue2(value),
|
|
28792
|
+
path: field.path,
|
|
28793
|
+
required,
|
|
28794
|
+
value
|
|
28795
|
+
};
|
|
28796
|
+
});
|
|
28797
|
+
const requiredTaskKinds = options.requiredTaskKinds ?? [];
|
|
28798
|
+
const missingTaskKinds = requiredTaskKinds.filter((kind) => !tasks.some((task) => task.kind === kind));
|
|
28799
|
+
const deliveredIntegrationEvents = integrationEvents.filter((event) => event.deliveryStatus === "delivered").length;
|
|
28800
|
+
const failedIntegrationEvents = integrationEvents.filter((event) => event.deliveryStatus === "failed").length;
|
|
28801
|
+
const issues = [];
|
|
28802
|
+
if (!review) {
|
|
28803
|
+
issues.push({
|
|
28804
|
+
code: "voice.post_call_analysis.review_missing",
|
|
28805
|
+
label: "Review missing",
|
|
28806
|
+
severity: "fail"
|
|
28807
|
+
});
|
|
28808
|
+
} else if (review.summary.pass === false) {
|
|
28809
|
+
issues.push({
|
|
28810
|
+
code: "voice.post_call_analysis.review_failed",
|
|
28811
|
+
detail: review.errors.join("; ") || review.summary.outcome,
|
|
28812
|
+
label: "Review failed",
|
|
28813
|
+
severity: "fail"
|
|
28814
|
+
});
|
|
28815
|
+
}
|
|
28816
|
+
for (const field of fields) {
|
|
28817
|
+
if (field.required && !field.ok) {
|
|
28818
|
+
issues.push({
|
|
28819
|
+
code: "voice.post_call_analysis.required_field_missing",
|
|
28820
|
+
detail: field.path,
|
|
28821
|
+
label: `Missing ${field.label}`,
|
|
28822
|
+
severity: "fail"
|
|
28823
|
+
});
|
|
28824
|
+
}
|
|
28825
|
+
}
|
|
28826
|
+
for (const kind of missingTaskKinds) {
|
|
28827
|
+
issues.push({
|
|
28828
|
+
code: "voice.post_call_analysis.required_task_missing",
|
|
28829
|
+
detail: kind,
|
|
28830
|
+
label: `Missing ${kind} task`,
|
|
28831
|
+
severity: "fail"
|
|
28832
|
+
});
|
|
28833
|
+
}
|
|
28834
|
+
if (options.requireDeliveredIntegrationEvent && deliveredIntegrationEvents === 0) {
|
|
28835
|
+
issues.push({
|
|
28836
|
+
code: "voice.post_call_analysis.integration_missing",
|
|
28837
|
+
label: "Delivered integration event missing",
|
|
28838
|
+
severity: "fail"
|
|
28839
|
+
});
|
|
28840
|
+
}
|
|
28841
|
+
if (failedIntegrationEvents > 0) {
|
|
28842
|
+
issues.push({
|
|
28843
|
+
code: "voice.post_call_analysis.integration_failed",
|
|
28844
|
+
detail: `${failedIntegrationEvents} failed integration event(s)`,
|
|
28845
|
+
label: "Integration delivery failed",
|
|
28846
|
+
severity: "warn"
|
|
28847
|
+
});
|
|
28848
|
+
}
|
|
28849
|
+
const status = issues.some((issue) => issue.severity === "fail") ? "fail" : issues.length > 0 ? "warn" : "pass";
|
|
28850
|
+
return {
|
|
28851
|
+
checkedAt: options.at ?? Date.now(),
|
|
28852
|
+
fields,
|
|
28853
|
+
integrationEvents,
|
|
28854
|
+
issues,
|
|
28855
|
+
operationRecordHref: normalizeOperationRecordHref(options.operationRecordBasePath, sessionId),
|
|
28856
|
+
review,
|
|
28857
|
+
reviewId,
|
|
28858
|
+
sessionId,
|
|
28859
|
+
status,
|
|
28860
|
+
summary: {
|
|
28861
|
+
deliveredIntegrationEvents,
|
|
28862
|
+
failedIntegrationEvents,
|
|
28863
|
+
fields: fields.length,
|
|
28864
|
+
missingRequiredFields: fields.filter((field) => field.required && !field.ok).length,
|
|
28865
|
+
missingRequiredTasks: missingTaskKinds.length,
|
|
28866
|
+
requiredFields: fields.filter((field) => field.required).length,
|
|
28867
|
+
requiredTaskKinds: requiredTaskKinds.length,
|
|
28868
|
+
tasks: tasks.length
|
|
28869
|
+
},
|
|
28870
|
+
tasks
|
|
28871
|
+
};
|
|
28872
|
+
};
|
|
28873
|
+
var renderVoicePostCallAnalysisMarkdown = (report) => {
|
|
28874
|
+
const lines = [
|
|
28875
|
+
"# Voice Post-Call Analysis",
|
|
28876
|
+
"",
|
|
28877
|
+
`Status: ${report.status}`,
|
|
28878
|
+
`Checked: ${new Date(report.checkedAt).toISOString()}`,
|
|
28879
|
+
report.reviewId ? `Review: ${report.reviewId}` : undefined,
|
|
28880
|
+
report.sessionId ? `Session: ${report.sessionId}` : undefined,
|
|
28881
|
+
report.operationRecordHref ? `Operations record: ${report.operationRecordHref}` : undefined,
|
|
28882
|
+
"",
|
|
28883
|
+
"## Summary",
|
|
28884
|
+
`- Fields: ${report.summary.fields}`,
|
|
28885
|
+
`- Missing required fields: ${report.summary.missingRequiredFields}`,
|
|
28886
|
+
`- Tasks: ${report.summary.tasks}`,
|
|
28887
|
+
`- Missing required tasks: ${report.summary.missingRequiredTasks}`,
|
|
28888
|
+
`- Delivered integration events: ${report.summary.deliveredIntegrationEvents}`,
|
|
28889
|
+
`- Failed integration events: ${report.summary.failedIntegrationEvents}`,
|
|
28890
|
+
"",
|
|
28891
|
+
"## Issues",
|
|
28892
|
+
...report.issues.length ? report.issues.map((issue) => `- ${issue.severity}: ${issue.code} - ${issue.label}${issue.detail ? ` (${issue.detail})` : ""}`) : ["- none"]
|
|
28893
|
+
].filter((line) => line !== undefined);
|
|
28894
|
+
return `${lines.join(`
|
|
28895
|
+
`)}
|
|
28896
|
+
`;
|
|
28897
|
+
};
|
|
28898
|
+
var resolvePostCallAnalysisReport = async (options, input) => {
|
|
28899
|
+
const source = options.source === undefined ? options : typeof options.source === "function" ? await options.source(input) : options.source;
|
|
28900
|
+
const merged = {
|
|
28901
|
+
...options,
|
|
28902
|
+
...source,
|
|
28903
|
+
reviewId: input.reviewId ?? source.reviewId ?? options.reviewId,
|
|
28904
|
+
sessionId: input.sessionId ?? source.sessionId ?? options.sessionId
|
|
28905
|
+
};
|
|
28906
|
+
return isPostCallAnalysisReport(merged) ? merged : buildVoicePostCallAnalysisReport(merged);
|
|
28907
|
+
};
|
|
28908
|
+
var createVoicePostCallAnalysisRoutes = (options = {}) => {
|
|
28909
|
+
const path = options.path ?? "/api/voice/post-call-analysis";
|
|
28910
|
+
const routes = new Elysia49({
|
|
28911
|
+
name: options.name ?? "absolutejs-voice-post-call-analysis"
|
|
28912
|
+
});
|
|
28913
|
+
routes.get(path, async ({ query }) => {
|
|
28914
|
+
const report = await resolvePostCallAnalysisReport(options, {
|
|
28915
|
+
reviewId: typeof query.reviewId === "string" ? query.reviewId : undefined,
|
|
28916
|
+
sessionId: typeof query.sessionId === "string" ? query.sessionId : undefined
|
|
28917
|
+
});
|
|
28918
|
+
return Response.json(report, { headers: options.headers });
|
|
28919
|
+
});
|
|
28920
|
+
routes.get(`${path}.md`, async ({ query }) => {
|
|
28921
|
+
const report = await resolvePostCallAnalysisReport(options, {
|
|
28922
|
+
reviewId: typeof query.reviewId === "string" ? query.reviewId : undefined,
|
|
28923
|
+
sessionId: typeof query.sessionId === "string" ? query.sessionId : undefined
|
|
28924
|
+
});
|
|
28925
|
+
return new Response(renderVoicePostCallAnalysisMarkdown(report), {
|
|
28926
|
+
headers: {
|
|
28927
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
28928
|
+
...options.headers
|
|
28929
|
+
}
|
|
28930
|
+
});
|
|
28931
|
+
});
|
|
28932
|
+
return routes;
|
|
28933
|
+
};
|
|
28934
|
+
// src/guardrails.ts
|
|
28935
|
+
import { Elysia as Elysia50 } from "elysia";
|
|
28936
|
+
var stringifyContent = (value) => typeof value === "string" ? value : JSON.stringify(value) ?? "";
|
|
28937
|
+
var appliesToStage = (rule, stage) => !rule.stages || rule.stages.length === 0 || rule.stages.includes(stage);
|
|
28938
|
+
var matchesRule = async (rule, input) => {
|
|
28939
|
+
if (!appliesToStage(rule, input.stage)) {
|
|
28940
|
+
return false;
|
|
28941
|
+
}
|
|
28942
|
+
if (typeof rule.match === "function") {
|
|
28943
|
+
return rule.match(input);
|
|
28944
|
+
}
|
|
28945
|
+
const content = stringifyContent(input.content);
|
|
28946
|
+
return typeof rule.match === "string" ? content.toLowerCase().includes(rule.match.toLowerCase()) : rule.match.test(content);
|
|
28947
|
+
};
|
|
28948
|
+
var applyRedactions = (content, rules, findings) => {
|
|
28949
|
+
if (typeof content !== "string") {
|
|
28950
|
+
return content;
|
|
28951
|
+
}
|
|
28952
|
+
return findings.reduce((value, finding) => {
|
|
28953
|
+
const rule = rules.find((candidate) => candidate.id === finding.ruleId);
|
|
28954
|
+
if (!rule || !rule.redactWith) {
|
|
28955
|
+
return value;
|
|
28956
|
+
}
|
|
28957
|
+
if (typeof rule.match === "string") {
|
|
28958
|
+
return value.replaceAll(rule.match, rule.redactWith);
|
|
28959
|
+
}
|
|
28960
|
+
if (rule.match instanceof RegExp) {
|
|
28961
|
+
return value.replace(rule.match, rule.redactWith);
|
|
28962
|
+
}
|
|
28963
|
+
return value;
|
|
28964
|
+
}, content);
|
|
28965
|
+
};
|
|
28966
|
+
var evaluateVoiceGuardrailPolicy = async (policy, input) => {
|
|
28967
|
+
const findings = [];
|
|
28968
|
+
for (const rule of policy.rules) {
|
|
28969
|
+
if (!await matchesRule(rule, input)) {
|
|
28970
|
+
continue;
|
|
28971
|
+
}
|
|
28972
|
+
findings.push({
|
|
28973
|
+
action: rule.action ?? policy.defaultAction ?? "block",
|
|
28974
|
+
description: rule.description,
|
|
28975
|
+
label: rule.label ?? rule.id,
|
|
28976
|
+
ruleId: rule.id,
|
|
28977
|
+
stage: input.stage
|
|
28978
|
+
});
|
|
28979
|
+
}
|
|
28980
|
+
const blocked = findings.some((finding) => finding.action === "block");
|
|
28981
|
+
const status = blocked ? "blocked" : findings.length > 0 ? "warn" : "pass";
|
|
28982
|
+
return {
|
|
28983
|
+
allowed: !blocked,
|
|
28984
|
+
checkedAt: Date.now(),
|
|
28985
|
+
content: input.content,
|
|
28986
|
+
findings,
|
|
28987
|
+
redactedContent: applyRedactions(input.content, policy.rules, findings),
|
|
28988
|
+
sessionId: input.sessionId,
|
|
28989
|
+
stage: input.stage,
|
|
28990
|
+
status,
|
|
28991
|
+
turnId: input.turnId
|
|
28992
|
+
};
|
|
28993
|
+
};
|
|
28994
|
+
var buildVoiceGuardrailReport = (input = { decisions: [] }) => {
|
|
28995
|
+
const blocked = input.decisions.filter((decision) => decision.status === "blocked").length;
|
|
28996
|
+
const warned = input.decisions.filter((decision) => decision.status === "warn").length;
|
|
28997
|
+
const passed = input.decisions.filter((decision) => decision.status === "pass").length;
|
|
28998
|
+
const status = blocked > 0 ? "fail" : warned > 0 ? "warn" : "pass";
|
|
28999
|
+
return {
|
|
29000
|
+
checkedAt: Date.now(),
|
|
29001
|
+
decisions: input.decisions,
|
|
29002
|
+
failed: blocked,
|
|
29003
|
+
policies: (input.policies ?? []).map((policy) => ({
|
|
29004
|
+
id: policy.id,
|
|
29005
|
+
label: policy.label,
|
|
29006
|
+
rules: policy.rules.length
|
|
29007
|
+
})),
|
|
29008
|
+
status,
|
|
29009
|
+
summary: {
|
|
29010
|
+
blocked,
|
|
29011
|
+
passed,
|
|
29012
|
+
warned
|
|
29013
|
+
},
|
|
29014
|
+
total: input.decisions.length
|
|
29015
|
+
};
|
|
29016
|
+
};
|
|
29017
|
+
var createVoiceGuardrailPolicy = (policy) => policy;
|
|
29018
|
+
var voiceGuardrailPolicyPresets = {
|
|
29019
|
+
supportSafeDefaults: createVoiceGuardrailPolicy({
|
|
29020
|
+
id: "support-safe-defaults",
|
|
29021
|
+
label: "Support safe defaults",
|
|
29022
|
+
rules: [
|
|
29023
|
+
{
|
|
29024
|
+
description: "Blocks final legal, medical, or financial advice claims that should route to a human or qualified professional.",
|
|
29025
|
+
id: "regulated-advice",
|
|
29026
|
+
label: "Regulated advice",
|
|
29027
|
+
match: /\b(legal advice|medical advice|financial advice|diagnose|prescribe|guaranteed refund|guaranteed approval)\b/i,
|
|
29028
|
+
stages: ["assistant-output"]
|
|
29029
|
+
},
|
|
29030
|
+
{
|
|
29031
|
+
description: "Warns when payment-card-like data appears in transcripts or tool payloads.",
|
|
29032
|
+
action: "warn",
|
|
29033
|
+
id: "payment-card-like-data",
|
|
29034
|
+
label: "Payment card-like data",
|
|
29035
|
+
match: /\b(?:\d[ -]*?){13,19}\b/,
|
|
29036
|
+
redactWith: "[redacted-card]",
|
|
29037
|
+
stages: ["transcript", "tool-input", "tool-output"]
|
|
29038
|
+
}
|
|
29039
|
+
]
|
|
29040
|
+
})
|
|
29041
|
+
};
|
|
29042
|
+
var renderVoiceGuardrailMarkdown = (report) => {
|
|
29043
|
+
const lines = [
|
|
29044
|
+
"# Voice Guardrail Report",
|
|
29045
|
+
"",
|
|
29046
|
+
`Status: ${report.status}`,
|
|
29047
|
+
`Checked: ${new Date(report.checkedAt).toISOString()}`,
|
|
29048
|
+
`Decisions: ${report.total}`,
|
|
29049
|
+
`Blocked: ${report.summary.blocked}`,
|
|
29050
|
+
`Warned: ${report.summary.warned}`,
|
|
29051
|
+
"",
|
|
29052
|
+
"## Decisions",
|
|
29053
|
+
...report.decisions.length > 0 ? report.decisions.map((decision) => `- ${decision.status}: ${decision.stage}${decision.sessionId ? ` session=${decision.sessionId}` : ""} findings=${decision.findings.length}`) : ["- none"]
|
|
29054
|
+
];
|
|
29055
|
+
return `${lines.join(`
|
|
29056
|
+
`)}
|
|
29057
|
+
`;
|
|
29058
|
+
};
|
|
29059
|
+
var isGuardrailReport = (value) => ("decisions" in value) && ("summary" in value);
|
|
29060
|
+
var normalizeGuardrailRouteInput = async (request) => {
|
|
29061
|
+
if (request.method === "POST") {
|
|
29062
|
+
return await request.json().catch(() => ({}));
|
|
29063
|
+
}
|
|
29064
|
+
const url = new URL(request.url);
|
|
29065
|
+
return {
|
|
29066
|
+
content: url.searchParams.get("content") ?? "",
|
|
29067
|
+
sessionId: url.searchParams.get("sessionId") ?? undefined,
|
|
29068
|
+
stage: url.searchParams.get("stage") ?? "assistant-output",
|
|
29069
|
+
turnId: url.searchParams.get("turnId") ?? undefined
|
|
29070
|
+
};
|
|
29071
|
+
};
|
|
29072
|
+
var resolveGuardrailReport = async (options, input) => {
|
|
29073
|
+
if (options.source !== undefined) {
|
|
29074
|
+
const value = typeof options.source === "function" ? await options.source(input) : options.source;
|
|
29075
|
+
return isGuardrailReport(value) ? value : buildVoiceGuardrailReport({ decisions: [value] });
|
|
29076
|
+
}
|
|
29077
|
+
const decisions = await Promise.all((options.policies ?? []).map((policy) => evaluateVoiceGuardrailPolicy(policy, input)));
|
|
29078
|
+
return buildVoiceGuardrailReport({
|
|
29079
|
+
decisions,
|
|
29080
|
+
policies: options.policies
|
|
29081
|
+
});
|
|
29082
|
+
};
|
|
29083
|
+
var createVoiceGuardrailRoutes = (options = {}) => {
|
|
29084
|
+
const path = options.path ?? "/api/voice/guardrails";
|
|
29085
|
+
const routes = new Elysia50({
|
|
29086
|
+
name: options.name ?? "absolutejs-voice-guardrails"
|
|
29087
|
+
});
|
|
29088
|
+
routes.all(path, async ({ request }) => {
|
|
29089
|
+
const input = await normalizeGuardrailRouteInput(request);
|
|
29090
|
+
const report = await resolveGuardrailReport(options, input);
|
|
29091
|
+
if (options.trace) {
|
|
29092
|
+
await Promise.all(report.decisions.map((decision) => options.trace.append({
|
|
29093
|
+
at: decision.checkedAt,
|
|
29094
|
+
payload: {
|
|
29095
|
+
allowed: decision.allowed,
|
|
29096
|
+
findings: decision.findings,
|
|
29097
|
+
stage: decision.stage,
|
|
29098
|
+
status: decision.status
|
|
29099
|
+
},
|
|
29100
|
+
sessionId: decision.sessionId ?? "guardrail-check",
|
|
29101
|
+
turnId: decision.turnId,
|
|
29102
|
+
type: "assistant.guardrail"
|
|
29103
|
+
})));
|
|
29104
|
+
}
|
|
29105
|
+
return Response.json(report, { headers: options.headers });
|
|
29106
|
+
});
|
|
29107
|
+
routes.all(`${path}.md`, async ({ request }) => {
|
|
29108
|
+
const input = await normalizeGuardrailRouteInput(request);
|
|
29109
|
+
const report = await resolveGuardrailReport(options, input);
|
|
29110
|
+
return new Response(renderVoiceGuardrailMarkdown(report), {
|
|
29111
|
+
headers: {
|
|
29112
|
+
"content-type": "text/markdown; charset=utf-8",
|
|
29113
|
+
...options.headers
|
|
29114
|
+
}
|
|
29115
|
+
});
|
|
29116
|
+
});
|
|
29117
|
+
return routes;
|
|
29118
|
+
};
|
|
28730
29119
|
// src/correction.ts
|
|
28731
29120
|
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28732
29121
|
var buildAliasMatcher = (alias) => new RegExp(`(?<![\\p{L}\\p{N}'])${escapeRegExp(alias)}(?![\\p{L}\\p{N}'])`, "giu");
|
|
@@ -29119,6 +29508,7 @@ export {
|
|
|
29119
29508
|
voiceTelephonyOutcomeToRouteResult,
|
|
29120
29509
|
voiceObservabilityExportSchemaVersion,
|
|
29121
29510
|
voiceObservabilityExportSchemaId,
|
|
29511
|
+
voiceGuardrailPolicyPresets,
|
|
29122
29512
|
voiceComplianceRedactionDefaults,
|
|
29123
29513
|
voice,
|
|
29124
29514
|
verifyVoiceTwilioWebhookSignature,
|
|
@@ -29219,6 +29609,7 @@ export {
|
|
|
29219
29609
|
renderVoiceProviderContractMatrixHTML,
|
|
29220
29610
|
renderVoiceProviderCapabilityHTML,
|
|
29221
29611
|
renderVoiceProductionReadinessHTML,
|
|
29612
|
+
renderVoicePostCallAnalysisMarkdown,
|
|
29222
29613
|
renderVoicePhoneAgentProductionSmokeHTML,
|
|
29223
29614
|
renderVoiceOutcomeContractHTML,
|
|
29224
29615
|
renderVoiceOpsStatusHTML,
|
|
@@ -29233,6 +29624,7 @@ export {
|
|
|
29233
29624
|
renderVoiceLiveLatencyHTML,
|
|
29234
29625
|
renderVoiceLatencySLOMarkdown,
|
|
29235
29626
|
renderVoiceHandoffHealthHTML,
|
|
29627
|
+
renderVoiceGuardrailMarkdown,
|
|
29236
29628
|
renderVoiceEvalHTML,
|
|
29237
29629
|
renderVoiceEvalBaselineHTML,
|
|
29238
29630
|
renderVoiceDemoReadyHTML,
|
|
@@ -29292,6 +29684,7 @@ export {
|
|
|
29292
29684
|
evaluateVoiceTelephonyContract,
|
|
29293
29685
|
evaluateVoiceQuality,
|
|
29294
29686
|
evaluateVoiceProviderStackGaps,
|
|
29687
|
+
evaluateVoiceGuardrailPolicy,
|
|
29295
29688
|
encodeTwilioMulawBase64,
|
|
29296
29689
|
deliverVoiceTraceEventsToSinks,
|
|
29297
29690
|
deliverVoiceObservabilityExport,
|
|
@@ -29414,6 +29807,7 @@ export {
|
|
|
29414
29807
|
createVoicePostgresCampaignStore,
|
|
29415
29808
|
createVoicePostgresAuditSinkDeliveryStore,
|
|
29416
29809
|
createVoicePostgresAuditEventStore,
|
|
29810
|
+
createVoicePostCallAnalysisRoutes,
|
|
29417
29811
|
createVoicePlivoCampaignDialer,
|
|
29418
29812
|
createVoicePlatformCoverageRoutes,
|
|
29419
29813
|
createVoicePhoneAgentProductionSmokeRoutes,
|
|
@@ -29470,6 +29864,8 @@ export {
|
|
|
29470
29864
|
createVoiceHandoffDeliveryWorkerLoop,
|
|
29471
29865
|
createVoiceHandoffDeliveryWorker,
|
|
29472
29866
|
createVoiceHandoffDeliveryRecord,
|
|
29867
|
+
createVoiceGuardrailRoutes,
|
|
29868
|
+
createVoiceGuardrailPolicy,
|
|
29473
29869
|
createVoiceFileTraceSinkDeliveryStore,
|
|
29474
29870
|
createVoiceFileTraceEventStore,
|
|
29475
29871
|
createVoiceFileTaskStore,
|
|
@@ -29570,6 +29966,7 @@ export {
|
|
|
29570
29966
|
buildVoiceProofTrendReport,
|
|
29571
29967
|
buildVoiceProductionReadinessReport,
|
|
29572
29968
|
buildVoiceProductionReadinessGate,
|
|
29969
|
+
buildVoicePostCallAnalysisReport,
|
|
29573
29970
|
buildVoicePlatformCoverageSummary,
|
|
29574
29971
|
buildVoiceOpsTaskFromSLABreach,
|
|
29575
29972
|
buildVoiceOpsTaskFromReview,
|
|
@@ -29585,6 +29982,7 @@ export {
|
|
|
29585
29982
|
buildVoiceLiveOpsControlState,
|
|
29586
29983
|
buildVoiceLatencySLOGate,
|
|
29587
29984
|
buildVoiceIncidentBundle,
|
|
29985
|
+
buildVoiceGuardrailReport,
|
|
29588
29986
|
buildVoiceDiagnosticsMarkdown,
|
|
29589
29987
|
buildVoiceDemoReadyReport,
|
|
29590
29988
|
buildVoiceDeliverySinkReport,
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import type { StoredVoiceIntegrationEvent, StoredVoiceOpsTask, VoiceIntegrationEventStore, VoiceOpsTaskKind, VoiceOpsTaskStore } from './ops';
|
|
3
|
+
import type { StoredVoiceCallReviewArtifact, VoiceCallReviewStore } from './testing/review';
|
|
4
|
+
export type VoicePostCallAnalysisStatus = 'fail' | 'pass' | 'warn';
|
|
5
|
+
export type VoicePostCallAnalysisFieldRequirement = {
|
|
6
|
+
label?: string;
|
|
7
|
+
path: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type VoicePostCallAnalysisFieldResult = {
|
|
11
|
+
label: string;
|
|
12
|
+
ok: boolean;
|
|
13
|
+
path: string;
|
|
14
|
+
required: boolean;
|
|
15
|
+
value?: unknown;
|
|
16
|
+
};
|
|
17
|
+
export type VoicePostCallAnalysisIssueCode = 'voice.post_call_analysis.integration_failed' | 'voice.post_call_analysis.integration_missing' | 'voice.post_call_analysis.required_field_missing' | 'voice.post_call_analysis.required_task_missing' | 'voice.post_call_analysis.review_failed' | 'voice.post_call_analysis.review_missing';
|
|
18
|
+
export type VoicePostCallAnalysisIssue = {
|
|
19
|
+
code: VoicePostCallAnalysisIssueCode;
|
|
20
|
+
detail?: string;
|
|
21
|
+
label: string;
|
|
22
|
+
severity: Exclude<VoicePostCallAnalysisStatus, 'pass'>;
|
|
23
|
+
};
|
|
24
|
+
export type VoicePostCallAnalysisReport = {
|
|
25
|
+
checkedAt: number;
|
|
26
|
+
fields: VoicePostCallAnalysisFieldResult[];
|
|
27
|
+
integrationEvents: StoredVoiceIntegrationEvent[];
|
|
28
|
+
issues: VoicePostCallAnalysisIssue[];
|
|
29
|
+
operationRecordHref?: string;
|
|
30
|
+
review?: StoredVoiceCallReviewArtifact;
|
|
31
|
+
reviewId?: string;
|
|
32
|
+
sessionId?: string;
|
|
33
|
+
status: VoicePostCallAnalysisStatus;
|
|
34
|
+
summary: {
|
|
35
|
+
deliveredIntegrationEvents: number;
|
|
36
|
+
failedIntegrationEvents: number;
|
|
37
|
+
fields: number;
|
|
38
|
+
missingRequiredFields: number;
|
|
39
|
+
missingRequiredTasks: number;
|
|
40
|
+
requiredFields: number;
|
|
41
|
+
requiredTaskKinds: number;
|
|
42
|
+
tasks: number;
|
|
43
|
+
};
|
|
44
|
+
tasks: StoredVoiceOpsTask[];
|
|
45
|
+
};
|
|
46
|
+
export type VoicePostCallAnalysisOptions = {
|
|
47
|
+
at?: number;
|
|
48
|
+
extractedFields?: Record<string, unknown>;
|
|
49
|
+
fields?: VoicePostCallAnalysisFieldRequirement[];
|
|
50
|
+
integrationEvents?: StoredVoiceIntegrationEvent[] | VoiceIntegrationEventStore;
|
|
51
|
+
operationRecordBasePath?: string;
|
|
52
|
+
requireDeliveredIntegrationEvent?: boolean;
|
|
53
|
+
requiredTaskKinds?: VoiceOpsTaskKind[];
|
|
54
|
+
review?: StoredVoiceCallReviewArtifact;
|
|
55
|
+
reviewId?: string;
|
|
56
|
+
reviews?: StoredVoiceCallReviewArtifact[] | VoiceCallReviewStore;
|
|
57
|
+
sessionId?: string;
|
|
58
|
+
tasks?: StoredVoiceOpsTask[] | VoiceOpsTaskStore;
|
|
59
|
+
};
|
|
60
|
+
export type VoicePostCallAnalysisRoutesOptions = VoicePostCallAnalysisOptions & {
|
|
61
|
+
headers?: HeadersInit;
|
|
62
|
+
name?: string;
|
|
63
|
+
path?: string;
|
|
64
|
+
source?: ((input: {
|
|
65
|
+
reviewId?: string;
|
|
66
|
+
sessionId?: string;
|
|
67
|
+
}) => Promise<VoicePostCallAnalysisOptions | VoicePostCallAnalysisReport> | VoicePostCallAnalysisOptions | VoicePostCallAnalysisReport) | VoicePostCallAnalysisOptions | VoicePostCallAnalysisReport;
|
|
68
|
+
};
|
|
69
|
+
export declare const buildVoicePostCallAnalysisReport: (options?: VoicePostCallAnalysisOptions) => Promise<VoicePostCallAnalysisReport>;
|
|
70
|
+
export declare const renderVoicePostCallAnalysisMarkdown: (report: VoicePostCallAnalysisReport) => string;
|
|
71
|
+
export declare const createVoicePostCallAnalysisRoutes: (options?: VoicePostCallAnalysisRoutesOptions) => Elysia<"", {
|
|
72
|
+
decorator: {};
|
|
73
|
+
store: {};
|
|
74
|
+
derive: {};
|
|
75
|
+
resolve: {};
|
|
76
|
+
}, {
|
|
77
|
+
typebox: {};
|
|
78
|
+
error: {};
|
|
79
|
+
}, {
|
|
80
|
+
schema: {};
|
|
81
|
+
standaloneSchema: {};
|
|
82
|
+
macro: {};
|
|
83
|
+
macroFn: {};
|
|
84
|
+
parser: {};
|
|
85
|
+
response: {};
|
|
86
|
+
}, {}, {
|
|
87
|
+
derive: {};
|
|
88
|
+
resolve: {};
|
|
89
|
+
schema: {};
|
|
90
|
+
standaloneSchema: {};
|
|
91
|
+
response: {};
|
|
92
|
+
}, {
|
|
93
|
+
derive: {};
|
|
94
|
+
resolve: {};
|
|
95
|
+
schema: {};
|
|
96
|
+
standaloneSchema: {};
|
|
97
|
+
response: {};
|
|
98
|
+
}>;
|