@absolutejs/voice 0.0.22-beta.183 → 0.0.22-beta.185
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/incidentBundle.d.ts +66 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +262 -35
- package/dist/productionReadiness.d.ts +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Elysia } from 'elysia';
|
|
2
|
+
import { type VoiceOperationsRecord, type VoiceOperationsRecordOptions } from './operationsRecord';
|
|
3
|
+
import { type VoiceTraceRedactionConfig } from './trace';
|
|
4
|
+
export type VoiceIncidentBundleFormat = 'json' | 'markdown';
|
|
5
|
+
export type VoiceIncidentBundle = {
|
|
6
|
+
auditMarkdown?: string;
|
|
7
|
+
exportedAt: number;
|
|
8
|
+
formatVersion: 1;
|
|
9
|
+
markdown: string;
|
|
10
|
+
record: VoiceOperationsRecord;
|
|
11
|
+
redacted: boolean;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
summary: VoiceIncidentBundleSummary;
|
|
14
|
+
traceMarkdown: string;
|
|
15
|
+
};
|
|
16
|
+
export type VoiceIncidentBundleSummary = {
|
|
17
|
+
auditEvents: number;
|
|
18
|
+
durationMs?: number;
|
|
19
|
+
errors: number;
|
|
20
|
+
handoffs: number;
|
|
21
|
+
providers: string[];
|
|
22
|
+
sessionId: string;
|
|
23
|
+
status: VoiceOperationsRecord['status'];
|
|
24
|
+
tools: number;
|
|
25
|
+
traceEvents: number;
|
|
26
|
+
turns: number;
|
|
27
|
+
};
|
|
28
|
+
export type VoiceIncidentBundleOptions = VoiceOperationsRecordOptions & {
|
|
29
|
+
redact?: VoiceTraceRedactionConfig;
|
|
30
|
+
title?: string;
|
|
31
|
+
};
|
|
32
|
+
export type VoiceIncidentBundleRoutesOptions = Omit<VoiceIncidentBundleOptions, 'sessionId'> & {
|
|
33
|
+
headers?: HeadersInit;
|
|
34
|
+
markdownPath?: false | string;
|
|
35
|
+
name?: string;
|
|
36
|
+
path?: string;
|
|
37
|
+
};
|
|
38
|
+
export declare const buildVoiceIncidentBundle: (options: VoiceIncidentBundleOptions) => Promise<VoiceIncidentBundle>;
|
|
39
|
+
export declare const createVoiceIncidentBundleRoutes: (options: VoiceIncidentBundleRoutesOptions) => Elysia<"", {
|
|
40
|
+
decorator: {};
|
|
41
|
+
store: {};
|
|
42
|
+
derive: {};
|
|
43
|
+
resolve: {};
|
|
44
|
+
}, {
|
|
45
|
+
typebox: {};
|
|
46
|
+
error: {};
|
|
47
|
+
}, {
|
|
48
|
+
schema: {};
|
|
49
|
+
standaloneSchema: {};
|
|
50
|
+
macro: {};
|
|
51
|
+
macroFn: {};
|
|
52
|
+
parser: {};
|
|
53
|
+
response: {};
|
|
54
|
+
}, {}, {
|
|
55
|
+
derive: {};
|
|
56
|
+
resolve: {};
|
|
57
|
+
schema: {};
|
|
58
|
+
standaloneSchema: {};
|
|
59
|
+
response: {};
|
|
60
|
+
}, {
|
|
61
|
+
derive: {};
|
|
62
|
+
resolve: {};
|
|
63
|
+
schema: {};
|
|
64
|
+
standaloneSchema: {};
|
|
65
|
+
response: {};
|
|
66
|
+
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -49,6 +49,7 @@ export { createVoiceReadinessProfile, recommendVoiceReadinessProfile } from './r
|
|
|
49
49
|
export { buildVoiceProviderContractMatrix, createVoiceProviderContractMatrixHTMLHandler, createVoiceProviderContractMatrixJSONHandler, createVoiceProviderContractMatrixPreset, createVoiceProviderContractMatrixRoutes, evaluateVoiceProviderStackGaps, renderVoiceProviderContractMatrixHTML, recommendVoiceProviderStack } from './providerStackRecommendations';
|
|
50
50
|
export { buildVoiceOpsConsoleReport, createVoiceOpsConsoleRoutes, renderVoiceOpsConsoleHTML } from './opsConsoleRoutes';
|
|
51
51
|
export { buildVoiceOperationsRecord, createVoiceOperationsRecordRoutes, renderVoiceOperationsRecordHTML } from './operationsRecord';
|
|
52
|
+
export { buildVoiceIncidentBundle, createVoiceIncidentBundleRoutes } from './incidentBundle';
|
|
52
53
|
export { summarizeVoiceOpsStatus } from './opsStatus';
|
|
53
54
|
export { createVoiceOpsStatusRoutes, renderVoiceOpsStatusHTML } from './opsStatusRoutes';
|
|
54
55
|
export { createVoiceQualityRoutes, evaluateVoiceQuality, renderVoiceQualityHTML } from './qualityRoutes';
|
|
@@ -105,10 +106,11 @@ export type { VoicePhoneAgentCarrier, VoicePhoneAgentCarrierSummary, VoicePhoneA
|
|
|
105
106
|
export type { VoicePhoneAgentProductionSmokeIssue, VoicePhoneAgentProductionSmokeHandlerOptions, VoicePhoneAgentProductionSmokeHTMLHandlerOptions, VoicePhoneAgentProductionSmokeOptions, VoicePhoneAgentProductionSmokeReport, VoicePhoneAgentProductionSmokeRoutesOptions, VoicePhoneAgentProductionSmokeRequirement } from './phoneAgentProductionSmoke';
|
|
106
107
|
export type { VoiceOpsConsoleLink, VoiceOpsConsoleReport, VoiceOpsConsoleRoutesOptions } from './opsConsoleRoutes';
|
|
107
108
|
export type { VoiceOpsStatus, VoiceOpsStatusLink, VoiceOpsStatusOptions, VoiceOpsStatusReport, VoiceOpsStatusRoutesOptions } from './opsStatus';
|
|
108
|
-
export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
|
|
109
|
+
export type { VoiceProductionReadinessAction, VoiceProductionReadinessAuditOptions, VoiceProductionReadinessAuditRequirement, VoiceProductionReadinessAuditSummary, VoiceProductionReadinessCheck, VoiceProductionReadinessGateIssue, VoiceProductionReadinessGateOptions, VoiceProductionReadinessGateProfile, VoiceProductionReadinessGateProfileSurface, VoiceProductionReadinessGateReport, VoiceProductionReadinessOpsActionHistoryOptions, VoiceProductionReadinessOpsActionHistorySummary, VoiceProductionReadinessOperationsRecordLink, VoiceProductionReadinessOperationsRecordLinks, VoiceProductionReadinessProfileExplanation, VoiceProductionReadinessProfileSurface, VoiceProductionReadinessProofSource, VoiceProductionReadinessReport, VoiceProductionReadinessRoutesOptions, VoiceProductionReadinessTraceDeliverySummary, VoiceProductionReadinessAuditDeliveryOptions, VoiceProductionReadinessAuditDeliverySummary, VoiceProductionReadinessTraceDeliveryOptions, VoiceProductionReadinessStatus } from './productionReadiness';
|
|
109
110
|
export type { VoiceReadinessProfileName, VoiceReadinessProfileOptions, VoiceReadinessProfileRecommendation, VoiceReadinessProfileRecommendationScore, VoiceReadinessProfileRoutesOptions } from './readinessProfiles';
|
|
110
111
|
export type { VoiceProviderStackChoice, VoiceProviderStackCapabilities, VoiceProviderStackCapabilityGap, VoiceProviderStackCapabilityGapInput, VoiceProviderStackCapabilityGapReport, VoiceProviderContractCheck, VoiceProviderContractCheckStatus, VoiceProviderContractDefinition, VoiceProviderContractMatrixHandlerOptions, VoiceProviderContractMatrixHTMLHandlerOptions, VoiceProviderContractMatrixInput, VoiceProviderContractMatrixPresetOptions, VoiceProviderContractMatrixReport, VoiceProviderContractMatrixRoutesOptions, VoiceProviderContractMatrixRow, VoiceProviderStackInput, VoiceProviderStackKind, VoiceProviderStackRecommendation } from './providerStackRecommendations';
|
|
111
112
|
export type { VoiceOperationsRecord, VoiceOperationsRecordAgentHandoff, VoiceOperationsRecordAuditSummary, VoiceOperationsRecordOptions, VoiceOperationsRecordOutcome, VoiceOperationsRecordRoutesOptions, VoiceOperationsRecordStatus, VoiceOperationsRecordTool } from './operationsRecord';
|
|
113
|
+
export type { VoiceIncidentBundle, VoiceIncidentBundleFormat, VoiceIncidentBundleOptions, VoiceIncidentBundleRoutesOptions, VoiceIncidentBundleSummary } from './incidentBundle';
|
|
112
114
|
export type { VoiceQualityLink, VoiceQualityMetric, VoiceQualityReport, VoiceQualityRoutesOptions, VoiceQualityStatus, VoiceQualityThresholds } from './qualityRoutes';
|
|
113
115
|
export type { VoiceResilienceIOSimulator, VoiceResilienceLink, VoiceResiliencePageData, VoiceResilienceRoutesOptions, VoiceResilienceSimulationProvider, VoiceRoutingKindSummary, VoiceRoutingDecisionSummary, VoiceRoutingDecisionSummaryOptions, VoiceRoutingEvent, VoiceRoutingEventKind, VoiceRoutingSessionSummary, VoiceRoutingSessionSummaryOptions } from './resilienceRoutes';
|
|
114
116
|
export type { VoiceIOProviderRouterEvent, VoiceIOProviderRouterOptions, VoiceIOProviderRouterPolicy, VoiceIOProviderRouterPolicyConfig, VoiceSTTProviderRouterOptions, VoiceTTSProviderRouterOptions } from './providerAdapters';
|
package/dist/index.js
CHANGED
|
@@ -20482,6 +20482,7 @@ var readinessGateCodes = {
|
|
|
20482
20482
|
"Delivery runtime": "voice.readiness.delivery_runtime",
|
|
20483
20483
|
"Handoff delivery": "voice.readiness.handoff_delivery",
|
|
20484
20484
|
"Live latency proof": "voice.readiness.live_latency",
|
|
20485
|
+
"Operations records": "voice.readiness.operations_records",
|
|
20485
20486
|
"Operator action history": "voice.readiness.operator_action_history",
|
|
20486
20487
|
"Phone agent production smoke": "voice.readiness.phone_agent_smoke",
|
|
20487
20488
|
"Provider contract matrix": "voice.readiness.provider_contract_matrix",
|
|
@@ -20810,6 +20811,46 @@ var summarizeLiveLatency = (events, options) => {
|
|
|
20810
20811
|
warnings
|
|
20811
20812
|
};
|
|
20812
20813
|
};
|
|
20814
|
+
var getString12 = (value) => typeof value === "string" ? value : undefined;
|
|
20815
|
+
var getNumber7 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
20816
|
+
var voiceOperationsRecordHref = (base, sessionId) => {
|
|
20817
|
+
const encoded = encodeURIComponent(sessionId);
|
|
20818
|
+
if (base.includes(":sessionId")) {
|
|
20819
|
+
return base.replace(":sessionId", encoded);
|
|
20820
|
+
}
|
|
20821
|
+
return `${base.replace(/\/+$/, "")}/${encoded}`;
|
|
20822
|
+
};
|
|
20823
|
+
var buildOperationsRecordLinks = (input) => {
|
|
20824
|
+
const failedSessionSet = new Set(input.failedSessionIds);
|
|
20825
|
+
const providerErrors = input.events.filter((event) => event.type === "session.error" && (event.payload.providerStatus === "error" || typeof event.payload.error === "string")).map((event) => ({
|
|
20826
|
+
detail: getString12(event.payload.error),
|
|
20827
|
+
href: voiceOperationsRecordHref(input.base, event.sessionId),
|
|
20828
|
+
label: "Open provider error operations record",
|
|
20829
|
+
sessionId: event.sessionId,
|
|
20830
|
+
status: "fail"
|
|
20831
|
+
}));
|
|
20832
|
+
const failingLatency = input.events.filter((event) => event.type === "client.live_latency").map((event) => ({
|
|
20833
|
+
event,
|
|
20834
|
+
latencyMs: getNumber7(event.payload.latencyMs) ?? getNumber7(event.payload.elapsedMs)
|
|
20835
|
+
})).filter((entry) => entry.latencyMs !== undefined && entry.latencyMs > input.liveLatencyWarnAfterMs).map(({ event, latencyMs }) => ({
|
|
20836
|
+
detail: `${latencyMs}ms live latency`,
|
|
20837
|
+
href: voiceOperationsRecordHref(input.base, event.sessionId),
|
|
20838
|
+
label: "Open latency operations record",
|
|
20839
|
+
sessionId: event.sessionId,
|
|
20840
|
+
status: latencyMs > input.liveLatencyFailAfterMs ? "fail" : "warn"
|
|
20841
|
+
}));
|
|
20842
|
+
return {
|
|
20843
|
+
failedSessions: input.failedSessionIds.map((sessionId) => ({
|
|
20844
|
+
href: voiceOperationsRecordHref(input.base, sessionId),
|
|
20845
|
+
label: "Open failed session operations record",
|
|
20846
|
+
sessionId,
|
|
20847
|
+
status: failedSessionSet.has(sessionId) ? "fail" : "warn"
|
|
20848
|
+
})),
|
|
20849
|
+
failingLatency,
|
|
20850
|
+
providerErrors
|
|
20851
|
+
};
|
|
20852
|
+
};
|
|
20853
|
+
var firstOperationsRecordHref = (links) => links[0]?.href;
|
|
20813
20854
|
var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
20814
20855
|
const request = input.request ?? new Request("http://localhost/");
|
|
20815
20856
|
const query = input.query ?? {};
|
|
@@ -20873,6 +20914,14 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
20873
20914
|
const deliveryRuntime = summarizeDeliveryRuntime(deliveryRuntimeSummary);
|
|
20874
20915
|
const degradedProviders = providers.filter((provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed").length;
|
|
20875
20916
|
const failedSessions = sessions.filter((session) => session.status === "failed").length;
|
|
20917
|
+
const failedSessionItems = sessions.filter((session) => session.status === "failed");
|
|
20918
|
+
const operationsRecords = buildOperationsRecordLinks({
|
|
20919
|
+
base: options.links?.operationsRecords ?? "/voice-operations",
|
|
20920
|
+
events,
|
|
20921
|
+
failedSessionIds: failedSessionItems.map((session) => session.sessionId),
|
|
20922
|
+
liveLatencyFailAfterMs: options.liveLatencyFailAfterMs ?? 3200,
|
|
20923
|
+
liveLatencyWarnAfterMs: options.liveLatencyWarnAfterMs ?? 1800
|
|
20924
|
+
});
|
|
20876
20925
|
const checks = [
|
|
20877
20926
|
{
|
|
20878
20927
|
detail: quality.status === "pass" ? "Quality gates are passing." : "Quality gates need attention.",
|
|
@@ -20904,11 +20953,18 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
20904
20953
|
},
|
|
20905
20954
|
{
|
|
20906
20955
|
detail: providerRecovery.unresolvedErrors > 0 ? `${providerRecovery.unresolvedErrors} provider error(s) have no recovered fallback evidence.` : providerRecovery.recovered > 0 ? `${providerRecovery.recovered} provider fallback recovery event(s) kept sessions healthy.` : "No provider fallback recovery was needed in the current trace window.",
|
|
20907
|
-
href: options.links?.resilience ?? "/resilience",
|
|
20956
|
+
href: firstOperationsRecordHref(operationsRecords.providerErrors) ?? options.links?.resilience ?? "/resilience",
|
|
20908
20957
|
label: "Provider fallback recovery",
|
|
20909
20958
|
status: providerRecovery.status,
|
|
20910
20959
|
value: providerRecovery.total === 0 ? "0 events" : `${providerRecovery.recovered}/${providerRecovery.total}`,
|
|
20911
20960
|
actions: providerRecovery.status === "pass" ? [] : [
|
|
20961
|
+
...firstOperationsRecordHref(operationsRecords.providerErrors) ? [
|
|
20962
|
+
{
|
|
20963
|
+
description: "Open the exact call/session operations record for the first unresolved provider error.",
|
|
20964
|
+
href: firstOperationsRecordHref(operationsRecords.providerErrors),
|
|
20965
|
+
label: "Open failing operations record"
|
|
20966
|
+
}
|
|
20967
|
+
] : [],
|
|
20912
20968
|
{
|
|
20913
20969
|
description: "Open provider resilience traces and inspect unresolved provider errors.",
|
|
20914
20970
|
href: options.links?.resilience ?? "/resilience",
|
|
@@ -20918,11 +20974,18 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
20918
20974
|
},
|
|
20919
20975
|
{
|
|
20920
20976
|
detail: failedSessions === 0 ? sessions.length > 0 ? "Recent sessions have no recorded provider/session failures." : "No sessions have been recorded yet; run a smoke or live session for proof." : `${failedSessions} recent session(s) have failures.`,
|
|
20921
|
-
href: options.links?.sessions ?? "/sessions",
|
|
20977
|
+
href: firstOperationsRecordHref(operationsRecords.failedSessions) ?? options.links?.sessions ?? "/sessions",
|
|
20922
20978
|
label: "Session health",
|
|
20923
20979
|
status: failedSessions > 0 ? "fail" : sessions.length === 0 ? "warn" : "pass",
|
|
20924
20980
|
value: `${sessions.length - failedSessions}/${sessions.length}`,
|
|
20925
20981
|
actions: failedSessions > 0 ? [
|
|
20982
|
+
...firstOperationsRecordHref(operationsRecords.failedSessions) ? [
|
|
20983
|
+
{
|
|
20984
|
+
description: "Open the exact failed call/session operations record.",
|
|
20985
|
+
href: firstOperationsRecordHref(operationsRecords.failedSessions),
|
|
20986
|
+
label: "Open failed operations record"
|
|
20987
|
+
}
|
|
20988
|
+
] : [],
|
|
20926
20989
|
{
|
|
20927
20990
|
description: "Open failed sessions and replay traces.",
|
|
20928
20991
|
href: `${options.links?.sessions ?? "/sessions"}?status=failed`,
|
|
@@ -20974,12 +21037,19 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
20974
21037
|
const proofSource = (...keys) => keys.map((key) => proofSources?.[key]).find((source) => source !== undefined);
|
|
20975
21038
|
checks.push({
|
|
20976
21039
|
detail: liveLatency.total === 0 ? "No browser live-latency measurements are recorded yet." : liveLatency.status === "pass" ? `Live browser turn latency averages ${liveLatency.averageLatencyMs}ms.` : `${liveLatency.failed} failed and ${liveLatency.warnings} warned live-latency measurement(s).`,
|
|
20977
|
-
href: options.links?.liveLatency ?? "/traces",
|
|
21040
|
+
href: firstOperationsRecordHref(operationsRecords.failingLatency) ?? options.links?.liveLatency ?? "/traces",
|
|
20978
21041
|
label: "Live latency proof",
|
|
20979
21042
|
proofSource: proofSource("liveLatency", "liveLatencyProof"),
|
|
20980
21043
|
status: liveLatency.status,
|
|
20981
21044
|
value: liveLatency.averageLatencyMs === undefined ? `${liveLatency.total} samples` : `${liveLatency.averageLatencyMs}ms avg`,
|
|
20982
21045
|
actions: liveLatency.status === "pass" ? [] : [
|
|
21046
|
+
...firstOperationsRecordHref(operationsRecords.failingLatency) ? [
|
|
21047
|
+
{
|
|
21048
|
+
description: "Open the exact call/session operations record for the slow live turn.",
|
|
21049
|
+
href: firstOperationsRecordHref(operationsRecords.failingLatency),
|
|
21050
|
+
label: "Open latency operations record"
|
|
21051
|
+
}
|
|
21052
|
+
] : [],
|
|
20983
21053
|
{
|
|
20984
21054
|
description: "Run a live browser voice turn and inspect the persisted latency trace.",
|
|
20985
21055
|
href: options.links?.liveLatency ?? "/traces",
|
|
@@ -21260,6 +21330,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
21260
21330
|
handoffs: "/handoffs",
|
|
21261
21331
|
handoffRetry: "/api/voice-handoffs/retry",
|
|
21262
21332
|
liveLatency: "/traces",
|
|
21333
|
+
operationsRecords: "/voice-operations",
|
|
21263
21334
|
opsActions: "/voice/ops-actions",
|
|
21264
21335
|
phoneAgentSmoke: "/sessions",
|
|
21265
21336
|
providerContracts: "/provider-contracts",
|
|
@@ -21272,6 +21343,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
21272
21343
|
...options.links
|
|
21273
21344
|
},
|
|
21274
21345
|
profile: options.profile || undefined,
|
|
21346
|
+
operationsRecords,
|
|
21275
21347
|
proofSources,
|
|
21276
21348
|
status: rollupStatus2(checks),
|
|
21277
21349
|
summary: {
|
|
@@ -22193,11 +22265,11 @@ import { Elysia as Elysia37 } from "elysia";
|
|
|
22193
22265
|
// src/traceTimeline.ts
|
|
22194
22266
|
import { Elysia as Elysia36 } from "elysia";
|
|
22195
22267
|
var escapeHtml38 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
22196
|
-
var
|
|
22197
|
-
var
|
|
22268
|
+
var getString13 = (value) => typeof value === "string" && value.trim() ? value : undefined;
|
|
22269
|
+
var getNumber8 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
22198
22270
|
var firstString3 = (payload, keys) => {
|
|
22199
22271
|
for (const key of keys) {
|
|
22200
|
-
const value =
|
|
22272
|
+
const value = getString13(payload[key]);
|
|
22201
22273
|
if (value) {
|
|
22202
22274
|
return value;
|
|
22203
22275
|
}
|
|
@@ -22206,7 +22278,7 @@ var firstString3 = (payload, keys) => {
|
|
|
22206
22278
|
};
|
|
22207
22279
|
var firstNumber3 = (payload, keys) => {
|
|
22208
22280
|
for (const key of keys) {
|
|
22209
|
-
const value =
|
|
22281
|
+
const value = getNumber8(payload[key]);
|
|
22210
22282
|
if (value !== undefined) {
|
|
22211
22283
|
return value;
|
|
22212
22284
|
}
|
|
@@ -22234,15 +22306,15 @@ var timelineLabel = (event) => {
|
|
|
22234
22306
|
case "turn.transcript":
|
|
22235
22307
|
return event.payload.isFinal === true ? "Final transcript" : "Partial transcript";
|
|
22236
22308
|
case "turn.committed":
|
|
22237
|
-
return `Committed turn${
|
|
22309
|
+
return `Committed turn${getString13(event.payload.reason) ? ` (${getString13(event.payload.reason)})` : ""}`;
|
|
22238
22310
|
case "turn.assistant":
|
|
22239
22311
|
return "Assistant reply";
|
|
22240
22312
|
case "agent.model":
|
|
22241
22313
|
return `Model call${eventProvider(event) ? ` via ${eventProvider(event)}` : ""}`;
|
|
22242
22314
|
case "agent.tool":
|
|
22243
|
-
return `Tool ${
|
|
22315
|
+
return `Tool ${getString13(event.payload.toolName) ?? "call"}`;
|
|
22244
22316
|
case "agent.handoff":
|
|
22245
|
-
return `Agent handoff${
|
|
22317
|
+
return `Agent handoff${getString13(event.payload.targetAgentId) ? ` to ${getString13(event.payload.targetAgentId)}` : ""}`;
|
|
22246
22318
|
case "assistant.run":
|
|
22247
22319
|
return `Assistant run${eventProvider(event) ? ` via ${eventProvider(event)}` : ""}`;
|
|
22248
22320
|
case "assistant.guardrail":
|
|
@@ -22252,11 +22324,11 @@ var timelineLabel = (event) => {
|
|
|
22252
22324
|
case "client.live_latency":
|
|
22253
22325
|
return `Live latency${eventElapsedMs(event) !== undefined ? ` ${eventElapsedMs(event)}ms` : ""}`;
|
|
22254
22326
|
case "session.error":
|
|
22255
|
-
return `Error${
|
|
22327
|
+
return `Error${getString13(event.payload.error) ? `: ${getString13(event.payload.error)}` : ""}`;
|
|
22256
22328
|
case "turn.cost":
|
|
22257
22329
|
return "Cost telemetry";
|
|
22258
22330
|
case "turn_latency.stage":
|
|
22259
|
-
return `Latency ${
|
|
22331
|
+
return `Latency ${getString13(event.payload.stage) ?? "stage"}`;
|
|
22260
22332
|
case "workflow.contract":
|
|
22261
22333
|
return `Workflow contract ${eventStatus(event) ?? ""}`.trim();
|
|
22262
22334
|
default:
|
|
@@ -22449,26 +22521,26 @@ var createVoiceTraceTimelineRoutes = (options) => {
|
|
|
22449
22521
|
};
|
|
22450
22522
|
|
|
22451
22523
|
// src/operationsRecord.ts
|
|
22452
|
-
var
|
|
22453
|
-
var
|
|
22524
|
+
var getString14 = (value) => typeof value === "string" ? value : undefined;
|
|
22525
|
+
var getNumber9 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
22454
22526
|
var countOutcome = (events, outcome) => events.filter((event) => event.outcome === outcome).length;
|
|
22455
22527
|
var toHandoff = (event) => ({
|
|
22456
22528
|
at: event.at,
|
|
22457
|
-
fromAgentId:
|
|
22529
|
+
fromAgentId: getString14(event.payload.fromAgentId),
|
|
22458
22530
|
metadata: event.payload.metadata && typeof event.payload.metadata === "object" && !Array.isArray(event.payload.metadata) ? event.payload.metadata : undefined,
|
|
22459
|
-
reason:
|
|
22460
|
-
status:
|
|
22461
|
-
summary:
|
|
22462
|
-
targetAgentId:
|
|
22531
|
+
reason: getString14(event.payload.reason),
|
|
22532
|
+
status: getString14(event.payload.status),
|
|
22533
|
+
summary: getString14(event.payload.summary),
|
|
22534
|
+
targetAgentId: getString14(event.payload.targetAgentId),
|
|
22463
22535
|
turnId: event.turnId
|
|
22464
22536
|
});
|
|
22465
22537
|
var toTool = (event) => ({
|
|
22466
22538
|
at: event.at,
|
|
22467
|
-
elapsedMs:
|
|
22468
|
-
error:
|
|
22469
|
-
status:
|
|
22470
|
-
toolCallId:
|
|
22471
|
-
toolName:
|
|
22539
|
+
elapsedMs: getNumber9(event.payload.elapsedMs),
|
|
22540
|
+
error: getString14(event.payload.error),
|
|
22541
|
+
status: getString14(event.payload.status),
|
|
22542
|
+
toolCallId: getString14(event.payload.toolCallId),
|
|
22543
|
+
toolName: getString14(event.payload.toolName),
|
|
22472
22544
|
turnId: event.turnId
|
|
22473
22545
|
});
|
|
22474
22546
|
var resolveOutcome4 = (events) => {
|
|
@@ -22572,6 +22644,159 @@ var createVoiceOperationsRecordRoutes = (options) => {
|
|
|
22572
22644
|
}
|
|
22573
22645
|
return routes;
|
|
22574
22646
|
};
|
|
22647
|
+
// src/incidentBundle.ts
|
|
22648
|
+
import { Elysia as Elysia38 } from "elysia";
|
|
22649
|
+
var buildSummary = (record) => ({
|
|
22650
|
+
auditEvents: record.audit?.total ?? 0,
|
|
22651
|
+
durationMs: record.summary.callDurationMs,
|
|
22652
|
+
errors: record.summary.errorCount,
|
|
22653
|
+
handoffs: record.handoffs.length,
|
|
22654
|
+
providers: record.providers.map((provider) => provider.provider),
|
|
22655
|
+
sessionId: record.sessionId,
|
|
22656
|
+
status: record.status,
|
|
22657
|
+
tools: record.tools.length,
|
|
22658
|
+
traceEvents: record.traceEvents.length,
|
|
22659
|
+
turns: record.summary.turnCount
|
|
22660
|
+
});
|
|
22661
|
+
var renderIncidentMarkdown = (input) => {
|
|
22662
|
+
const lines = [
|
|
22663
|
+
`# ${input.title ?? `Voice Incident ${input.summary.sessionId}`}`,
|
|
22664
|
+
"",
|
|
22665
|
+
`Session: ${input.summary.sessionId}`,
|
|
22666
|
+
`Status: ${input.summary.status}`,
|
|
22667
|
+
`Trace events: ${input.summary.traceEvents}`,
|
|
22668
|
+
`Audit events: ${input.summary.auditEvents}`,
|
|
22669
|
+
`Turns: ${input.summary.turns}`,
|
|
22670
|
+
`Errors: ${input.summary.errors}`,
|
|
22671
|
+
`Handoffs: ${input.summary.handoffs}`,
|
|
22672
|
+
`Tools: ${input.summary.tools}`,
|
|
22673
|
+
`Providers: ${input.summary.providers.join(", ") || "none"}`,
|
|
22674
|
+
input.summary.durationMs === undefined ? undefined : `Duration: ${input.summary.durationMs}ms`,
|
|
22675
|
+
"",
|
|
22676
|
+
"## Outcome",
|
|
22677
|
+
"",
|
|
22678
|
+
`- Assistant replies: ${input.record.outcome.assistantReplies}`,
|
|
22679
|
+
`- Complete: ${input.record.outcome.complete ? "yes" : "no"}`,
|
|
22680
|
+
`- Escalated: ${input.record.outcome.escalated ? "yes" : "no"}`,
|
|
22681
|
+
`- Transferred: ${input.record.outcome.transferred ? "yes" : "no"}`,
|
|
22682
|
+
`- Voicemail: ${input.record.outcome.voicemail ? "yes" : "no"}`,
|
|
22683
|
+
`- No answer: ${input.record.outcome.noAnswer ? "yes" : "no"}`,
|
|
22684
|
+
"",
|
|
22685
|
+
"## Handoffs",
|
|
22686
|
+
"",
|
|
22687
|
+
...input.record.handoffs.length ? input.record.handoffs.map((handoff) => `- ${handoff.fromAgentId ?? "unknown"} -> ${handoff.targetAgentId ?? "unknown"} ${handoff.status ?? ""} ${handoff.summary ?? handoff.reason ?? ""}`.trim()) : ["- none"],
|
|
22688
|
+
"",
|
|
22689
|
+
"## Tools",
|
|
22690
|
+
"",
|
|
22691
|
+
...input.record.tools.length ? input.record.tools.map((tool) => `- ${tool.toolName ?? "tool"} ${tool.status ?? ""} ${tool.elapsedMs === undefined ? "" : `${tool.elapsedMs}ms`} ${tool.error ?? ""}`.trim()) : ["- none"],
|
|
22692
|
+
"",
|
|
22693
|
+
"## Trace Evidence",
|
|
22694
|
+
"",
|
|
22695
|
+
input.traceMarkdown,
|
|
22696
|
+
""
|
|
22697
|
+
].filter((line) => line !== undefined);
|
|
22698
|
+
if (input.auditMarkdown) {
|
|
22699
|
+
lines.push("## Audit Evidence", "", input.auditMarkdown);
|
|
22700
|
+
}
|
|
22701
|
+
return lines.join(`
|
|
22702
|
+
`);
|
|
22703
|
+
};
|
|
22704
|
+
var redactRecordValue = (value, redactedEvents, redact) => {
|
|
22705
|
+
if (!redact) {
|
|
22706
|
+
return value;
|
|
22707
|
+
}
|
|
22708
|
+
if (Array.isArray(value)) {
|
|
22709
|
+
return value.map((item) => redactRecordValue(item, redactedEvents, redact));
|
|
22710
|
+
}
|
|
22711
|
+
if (typeof value === "string") {
|
|
22712
|
+
return redactVoiceTraceText(value, redact);
|
|
22713
|
+
}
|
|
22714
|
+
if (typeof value === "object" && value) {
|
|
22715
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
|
|
22716
|
+
key,
|
|
22717
|
+
key === "events" || key === "traceEvents" ? redactedEvents : redactRecordValue(entryValue, redactedEvents, redact)
|
|
22718
|
+
]));
|
|
22719
|
+
}
|
|
22720
|
+
return value;
|
|
22721
|
+
};
|
|
22722
|
+
var redactOperationsRecord = (record, input) => ({
|
|
22723
|
+
...redactRecordValue(record, input.traceEvents, input.redact),
|
|
22724
|
+
audit: record.audit ? {
|
|
22725
|
+
...record.audit,
|
|
22726
|
+
events: input.auditEvents ?? []
|
|
22727
|
+
} : undefined,
|
|
22728
|
+
traceEvents: input.traceEvents
|
|
22729
|
+
});
|
|
22730
|
+
var buildVoiceIncidentBundle = async (options) => {
|
|
22731
|
+
const record = await buildVoiceOperationsRecord(options);
|
|
22732
|
+
const redactedTraceEvents = options.redact ? redactVoiceTraceEvents(record.traceEvents, options.redact) : record.traceEvents;
|
|
22733
|
+
const redactedAuditEvents = options.redact && record.audit ? redactVoiceAuditEvents(record.audit.events, options.redact) : record.audit?.events;
|
|
22734
|
+
const redactedRecord = redactOperationsRecord(record, {
|
|
22735
|
+
auditEvents: redactedAuditEvents,
|
|
22736
|
+
redact: options.redact,
|
|
22737
|
+
traceEvents: redactedTraceEvents
|
|
22738
|
+
});
|
|
22739
|
+
const summary = buildSummary(redactedRecord);
|
|
22740
|
+
const traceMarkdown = renderVoiceTraceMarkdown(record.traceEvents, {
|
|
22741
|
+
evaluation: options.evaluation,
|
|
22742
|
+
redact: options.redact,
|
|
22743
|
+
title: `Voice Incident Trace ${options.sessionId}`
|
|
22744
|
+
});
|
|
22745
|
+
const auditMarkdown = record.audit ? renderVoiceAuditMarkdown(record.audit.events, {
|
|
22746
|
+
redact: options.redact,
|
|
22747
|
+
title: `Voice Incident Audit ${options.sessionId}`
|
|
22748
|
+
}) : undefined;
|
|
22749
|
+
const markdown = renderIncidentMarkdown({
|
|
22750
|
+
auditMarkdown,
|
|
22751
|
+
record: redactedRecord,
|
|
22752
|
+
summary,
|
|
22753
|
+
title: options.title,
|
|
22754
|
+
traceMarkdown
|
|
22755
|
+
});
|
|
22756
|
+
return {
|
|
22757
|
+
auditMarkdown,
|
|
22758
|
+
exportedAt: Date.now(),
|
|
22759
|
+
formatVersion: 1,
|
|
22760
|
+
markdown,
|
|
22761
|
+
record: redactedRecord,
|
|
22762
|
+
redacted: Boolean(options.redact),
|
|
22763
|
+
sessionId: options.sessionId,
|
|
22764
|
+
summary,
|
|
22765
|
+
traceMarkdown
|
|
22766
|
+
};
|
|
22767
|
+
};
|
|
22768
|
+
var createVoiceIncidentBundleRoutes = (options) => {
|
|
22769
|
+
const path = options.path ?? "/api/voice-incidents/:sessionId";
|
|
22770
|
+
const markdownPath = options.markdownPath === undefined ? "/voice-incidents/:sessionId/markdown" : options.markdownPath;
|
|
22771
|
+
const routes = new Elysia38({
|
|
22772
|
+
name: options.name ?? "absolutejs-voice-incident-bundle"
|
|
22773
|
+
});
|
|
22774
|
+
const getSessionId = (params) => params.sessionId ?? "";
|
|
22775
|
+
const buildBundle = (sessionId) => buildVoiceIncidentBundle({
|
|
22776
|
+
audit: options.audit,
|
|
22777
|
+
evaluation: options.evaluation,
|
|
22778
|
+
events: options.events,
|
|
22779
|
+
redact: options.redact,
|
|
22780
|
+
sessionId,
|
|
22781
|
+
store: options.store,
|
|
22782
|
+
title: options.title
|
|
22783
|
+
});
|
|
22784
|
+
routes.get(path, async ({ params }) => Response.json(await buildBundle(getSessionId(params)), {
|
|
22785
|
+
headers: options.headers
|
|
22786
|
+
}));
|
|
22787
|
+
if (markdownPath) {
|
|
22788
|
+
routes.get(markdownPath, async ({ params }) => {
|
|
22789
|
+
const bundle = await buildBundle(getSessionId(params));
|
|
22790
|
+
return new Response(bundle.markdown, {
|
|
22791
|
+
headers: {
|
|
22792
|
+
"Content-Type": "text/markdown; charset=utf-8",
|
|
22793
|
+
...options.headers
|
|
22794
|
+
}
|
|
22795
|
+
});
|
|
22796
|
+
});
|
|
22797
|
+
}
|
|
22798
|
+
return routes;
|
|
22799
|
+
};
|
|
22575
22800
|
// src/opsStatus.ts
|
|
22576
22801
|
var DEFAULT_LINKS2 = [
|
|
22577
22802
|
{
|
|
@@ -22744,7 +22969,7 @@ var summarizeVoiceOpsStatus = async (options) => {
|
|
|
22744
22969
|
};
|
|
22745
22970
|
};
|
|
22746
22971
|
// src/opsStatusRoutes.ts
|
|
22747
|
-
import { Elysia as
|
|
22972
|
+
import { Elysia as Elysia39 } from "elysia";
|
|
22748
22973
|
var escapeHtml40 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
22749
22974
|
var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
22750
22975
|
const title = options.title ?? "AbsoluteJS Voice Ops Status";
|
|
@@ -22756,7 +22981,7 @@ var renderVoiceOpsStatusHTML = (report, options = {}) => {
|
|
|
22756
22981
|
};
|
|
22757
22982
|
var createVoiceOpsStatusRoutes = (options) => {
|
|
22758
22983
|
const path = options.path ?? "/api/voice/ops-status";
|
|
22759
|
-
const routes = new
|
|
22984
|
+
const routes = new Elysia39({
|
|
22760
22985
|
name: options.name ?? "absolutejs-voice-ops-status"
|
|
22761
22986
|
});
|
|
22762
22987
|
routes.get(path, async () => summarizeVoiceOpsStatus(options));
|
|
@@ -23189,10 +23414,10 @@ var createVoiceTTSProviderRouter = (options) => {
|
|
|
23189
23414
|
};
|
|
23190
23415
|
};
|
|
23191
23416
|
// src/traceDeliveryRoutes.ts
|
|
23192
|
-
import { Elysia as
|
|
23417
|
+
import { Elysia as Elysia40 } from "elysia";
|
|
23193
23418
|
var escapeHtml41 = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
23194
|
-
var
|
|
23195
|
-
var
|
|
23419
|
+
var getString15 = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
23420
|
+
var getNumber10 = (value) => {
|
|
23196
23421
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
23197
23422
|
return value;
|
|
23198
23423
|
}
|
|
@@ -23203,13 +23428,13 @@ var getNumber9 = (value) => {
|
|
|
23203
23428
|
return;
|
|
23204
23429
|
};
|
|
23205
23430
|
var parseStatus2 = (value) => {
|
|
23206
|
-
const text =
|
|
23431
|
+
const text = getString15(value);
|
|
23207
23432
|
return text === "pending" || text === "delivered" || text === "failed" || text === "skipped" || text === "all" ? text : undefined;
|
|
23208
23433
|
};
|
|
23209
23434
|
var resolveVoiceTraceDeliveryFilter = (query = {}, base = {}) => ({
|
|
23210
23435
|
...base,
|
|
23211
|
-
limit:
|
|
23212
|
-
q:
|
|
23436
|
+
limit: getNumber10(query.limit) ?? base.limit,
|
|
23437
|
+
q: getString15(query.q) ?? base.q,
|
|
23213
23438
|
status: parseStatus2(query.status) ?? base.status
|
|
23214
23439
|
});
|
|
23215
23440
|
var deliverySearchText2 = (delivery) => [
|
|
@@ -23298,7 +23523,7 @@ var createVoiceTraceDeliveryRoutes = (options) => {
|
|
|
23298
23523
|
const path = options.path ?? "/api/voice-trace-deliveries";
|
|
23299
23524
|
const htmlPath = options.htmlPath === undefined ? "/traces/deliveries" : options.htmlPath;
|
|
23300
23525
|
const workerPath = options.workerPath === undefined ? `${path}/drain` : options.workerPath;
|
|
23301
|
-
const routes = new
|
|
23526
|
+
const routes = new Elysia40({
|
|
23302
23527
|
name: options.name ?? "absolutejs-voice-trace-deliveries"
|
|
23303
23528
|
}).get(path, createVoiceTraceDeliveryJSONHandler(options));
|
|
23304
23529
|
if (htmlPath !== false) {
|
|
@@ -23922,7 +24147,7 @@ var createVoiceMemoryStore = () => {
|
|
|
23922
24147
|
return { get, getOrCreate, list, remove, set };
|
|
23923
24148
|
};
|
|
23924
24149
|
// src/opsWebhook.ts
|
|
23925
|
-
import { Elysia as
|
|
24150
|
+
import { Elysia as Elysia41 } from "elysia";
|
|
23926
24151
|
var toHex6 = (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
23927
24152
|
var signVoiceOpsWebhookBody = async (input) => {
|
|
23928
24153
|
const encoder = new TextEncoder;
|
|
@@ -24052,7 +24277,7 @@ var verifyVoiceOpsWebhookSignature = async (input) => {
|
|
|
24052
24277
|
};
|
|
24053
24278
|
var createVoiceOpsWebhookReceiverRoutes = (options = {}) => {
|
|
24054
24279
|
const path = options.path ?? "/api/voice-ops/webhook";
|
|
24055
|
-
return new
|
|
24280
|
+
return new Elysia41().post(path, async ({ body, request, set }) => {
|
|
24056
24281
|
const bodyText = typeof body === "string" ? body : JSON.stringify(body);
|
|
24057
24282
|
if (options.signingSecret) {
|
|
24058
24283
|
const verification = await verifyVoiceOpsWebhookSignature({
|
|
@@ -25200,6 +25425,7 @@ export {
|
|
|
25200
25425
|
createVoiceIntegrationSinkWorker,
|
|
25201
25426
|
createVoiceIntegrationHTTPSink,
|
|
25202
25427
|
createVoiceIntegrationEvent,
|
|
25428
|
+
createVoiceIncidentBundleRoutes,
|
|
25203
25429
|
createVoiceHubSpotTaskUpdateSink,
|
|
25204
25430
|
createVoiceHubSpotTaskSyncSinks,
|
|
25205
25431
|
createVoiceHubSpotTaskSink,
|
|
@@ -25309,6 +25535,7 @@ export {
|
|
|
25309
25535
|
buildVoiceOpsConsoleReport,
|
|
25310
25536
|
buildVoiceOpsActionHistoryReport,
|
|
25311
25537
|
buildVoiceOperationsRecord,
|
|
25538
|
+
buildVoiceIncidentBundle,
|
|
25312
25539
|
buildVoiceDiagnosticsMarkdown,
|
|
25313
25540
|
buildVoiceDemoReadyReport,
|
|
25314
25541
|
buildVoiceDeliverySinkReport,
|
|
@@ -86,6 +86,7 @@ export type VoiceProductionReadinessReport = {
|
|
|
86
86
|
handoffs?: string;
|
|
87
87
|
handoffRetry?: string;
|
|
88
88
|
liveLatency?: string;
|
|
89
|
+
operationsRecords?: string;
|
|
89
90
|
opsActions?: string;
|
|
90
91
|
phoneAgentSmoke?: string;
|
|
91
92
|
providerContracts?: string;
|
|
@@ -98,6 +99,7 @@ export type VoiceProductionReadinessReport = {
|
|
|
98
99
|
};
|
|
99
100
|
profile?: VoiceProductionReadinessProfileExplanation;
|
|
100
101
|
proofSources?: Record<string, VoiceProductionReadinessProofSource>;
|
|
102
|
+
operationsRecords?: VoiceProductionReadinessOperationsRecordLinks;
|
|
101
103
|
status: VoiceProductionReadinessStatus;
|
|
102
104
|
summary: {
|
|
103
105
|
agentSquadContracts?: {
|
|
@@ -174,6 +176,18 @@ export type VoiceProductionReadinessReport = {
|
|
|
174
176
|
traceDeliveries?: VoiceProductionReadinessTraceDeliverySummary;
|
|
175
177
|
};
|
|
176
178
|
};
|
|
179
|
+
export type VoiceProductionReadinessOperationsRecordLink = {
|
|
180
|
+
detail?: string;
|
|
181
|
+
href: string;
|
|
182
|
+
label: string;
|
|
183
|
+
sessionId: string;
|
|
184
|
+
status: VoiceProductionReadinessStatus;
|
|
185
|
+
};
|
|
186
|
+
export type VoiceProductionReadinessOperationsRecordLinks = {
|
|
187
|
+
failedSessions: VoiceProductionReadinessOperationsRecordLink[];
|
|
188
|
+
failingLatency: VoiceProductionReadinessOperationsRecordLink[];
|
|
189
|
+
providerErrors: VoiceProductionReadinessOperationsRecordLink[];
|
|
190
|
+
};
|
|
177
191
|
export type VoiceProductionReadinessAuditRequirement = {
|
|
178
192
|
label?: string;
|
|
179
193
|
maxAgeMs?: number;
|