@absolutejs/voice 0.0.22-beta.131 → 0.0.22-beta.133
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/client/htmxBootstrap.js +19 -0
- package/dist/index.js +34 -2
- package/dist/productionReadiness.d.ts +12 -0
- package/package.json +1 -1
|
@@ -1743,6 +1743,17 @@ var formatErrorMessage = (error) => {
|
|
|
1743
1743
|
}
|
|
1744
1744
|
return "Unexpected error";
|
|
1745
1745
|
};
|
|
1746
|
+
var formatReconnectState = (reconnect) => {
|
|
1747
|
+
const pieces = [reconnect.status];
|
|
1748
|
+
if (reconnect.attempts > 0 || reconnect.maxAttempts > 0) {
|
|
1749
|
+
pieces.push(`${reconnect.attempts}/${reconnect.maxAttempts} attempts`);
|
|
1750
|
+
}
|
|
1751
|
+
if (reconnect.nextAttemptAt) {
|
|
1752
|
+
const waitMs = Math.max(0, reconnect.nextAttemptAt - Date.now());
|
|
1753
|
+
pieces.push(`retry in ${Math.ceil(waitMs / 100) / 10}s`);
|
|
1754
|
+
}
|
|
1755
|
+
return pieces.join(" · ");
|
|
1756
|
+
};
|
|
1746
1757
|
var createInitialVoiceWaveLevels = (count = VOICE_WAVE_POINTS) => Array.from({ length: count }, () => 0);
|
|
1747
1758
|
var pushVoiceWaveLevel = (levels, nextLevel, count = VOICE_WAVE_POINTS) => {
|
|
1748
1759
|
const next = levels.slice(-(count - 1));
|
|
@@ -1806,6 +1817,10 @@ var parseOptionalNumber = (value) => {
|
|
|
1806
1817
|
const parsed = Number(value);
|
|
1807
1818
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
1808
1819
|
};
|
|
1820
|
+
var resolveElement2 = (root, selector, ctor) => {
|
|
1821
|
+
const value = selector ? document.querySelector(selector) : root.querySelector(selector ?? "");
|
|
1822
|
+
return value instanceof ctor ? value : null;
|
|
1823
|
+
};
|
|
1809
1824
|
var requireElement = (root, selector, ctor, name) => {
|
|
1810
1825
|
const value = selector ? document.querySelector(selector) : null;
|
|
1811
1826
|
if (value instanceof ctor) {
|
|
@@ -1868,6 +1883,7 @@ var initVoiceHTMXRoot = (root) => {
|
|
|
1868
1883
|
const errorStatus = requireElement(root, root.dataset.voiceError, HTMLElement, "status-error");
|
|
1869
1884
|
const microphoneStatus = requireElement(root, root.dataset.voiceMicrophone, HTMLElement, "status-mic");
|
|
1870
1885
|
const promptStatus = requireElement(root, root.dataset.voicePrompt, HTMLElement, "status-prompt");
|
|
1886
|
+
const reconnectStatus = resolveElement2(root, root.dataset.voiceReconnect, HTMLElement);
|
|
1871
1887
|
const chatList = requireElement(root, root.dataset.voiceChat, HTMLElement, "chat-list");
|
|
1872
1888
|
const startGuidedButton = requireElement(root, root.dataset.voiceStartGuided, HTMLButtonElement, "start-guided");
|
|
1873
1889
|
const startGeneralButton = requireElement(root, root.dataset.voiceStartGeneral, HTMLButtonElement, "start-general");
|
|
@@ -1948,6 +1964,9 @@ var initVoiceHTMXRoot = (root) => {
|
|
|
1948
1964
|
const status = voice.status;
|
|
1949
1965
|
connectionMetric.textContent = voice.isConnected ? "Connected" : "Waiting";
|
|
1950
1966
|
errorStatus.textContent = micError || voice.error || "None";
|
|
1967
|
+
if (reconnectStatus) {
|
|
1968
|
+
reconnectStatus.textContent = formatReconnectState(voice.reconnect);
|
|
1969
|
+
}
|
|
1951
1970
|
microphoneStatus.textContent = isCapturing ? DEFAULT_MIC_LIVE : DEFAULT_MIC_IDLE;
|
|
1952
1971
|
promptStatus.textContent = resolvePromptMessage({
|
|
1953
1972
|
guidedPrompts,
|
package/dist/index.js
CHANGED
|
@@ -19483,6 +19483,12 @@ var resolvePhoneAgentSmokes = async (options, input) => {
|
|
|
19483
19483
|
}
|
|
19484
19484
|
return typeof options.phoneAgentSmokes === "function" ? await options.phoneAgentSmokes(input) : options.phoneAgentSmokes;
|
|
19485
19485
|
};
|
|
19486
|
+
var resolveReconnectContracts = async (options, input) => {
|
|
19487
|
+
if (options.reconnectContracts === false || options.reconnectContracts === undefined) {
|
|
19488
|
+
return;
|
|
19489
|
+
}
|
|
19490
|
+
return typeof options.reconnectContracts === "function" ? await options.reconnectContracts(input) : options.reconnectContracts;
|
|
19491
|
+
};
|
|
19486
19492
|
var defaultAuditRequirements = [
|
|
19487
19493
|
{
|
|
19488
19494
|
label: "Provider-call audit",
|
|
@@ -19640,7 +19646,8 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19640
19646
|
carriers,
|
|
19641
19647
|
agentSquadContracts,
|
|
19642
19648
|
providerRoutingContracts,
|
|
19643
|
-
phoneAgentSmokes
|
|
19649
|
+
phoneAgentSmokes,
|
|
19650
|
+
reconnectContracts
|
|
19644
19651
|
] = await Promise.all([
|
|
19645
19652
|
evaluateVoiceQuality({ events }),
|
|
19646
19653
|
Promise.all([
|
|
@@ -19665,7 +19672,8 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19665
19672
|
resolveCarriers(options, { query, request }),
|
|
19666
19673
|
resolveAgentSquadContracts(options, { query, request }),
|
|
19667
19674
|
resolveProviderRoutingContracts(options, { query, request }),
|
|
19668
|
-
resolvePhoneAgentSmokes(options, { query, request })
|
|
19675
|
+
resolvePhoneAgentSmokes(options, { query, request }),
|
|
19676
|
+
resolveReconnectContracts(options, { query, request })
|
|
19669
19677
|
]);
|
|
19670
19678
|
const degradedProviders = providers.filter((provider) => provider.status === "degraded" || provider.status === "rate-limited" || provider.status === "suppressed").length;
|
|
19671
19679
|
const failedSessions = sessions.filter((session) => session.status === "failed").length;
|
|
@@ -19792,6 +19800,12 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19792
19800
|
status: phoneAgentSmokes.some((report) => !report.pass) ? "fail" : phoneAgentSmokes.length === 0 ? "warn" : "pass",
|
|
19793
19801
|
total: phoneAgentSmokes.length
|
|
19794
19802
|
} : undefined;
|
|
19803
|
+
const reconnectContractSummary = reconnectContracts ? {
|
|
19804
|
+
failed: reconnectContracts.filter((report) => !report.pass).length,
|
|
19805
|
+
passed: reconnectContracts.filter((report) => report.pass).length,
|
|
19806
|
+
status: reconnectContracts.some((report) => !report.pass) ? "fail" : reconnectContracts.length === 0 ? "warn" : "pass",
|
|
19807
|
+
total: reconnectContracts.length
|
|
19808
|
+
} : undefined;
|
|
19795
19809
|
if (agentSquadContractSummary) {
|
|
19796
19810
|
checks.push({
|
|
19797
19811
|
detail: agentSquadContractSummary.status === "pass" ? `${agentSquadContractSummary.passed} agent squad contract(s) are passing.` : agentSquadContractSummary.total === 0 ? "No agent squad contracts are configured." : `${agentSquadContractSummary.failed} agent squad contract(s) failed.`,
|
|
@@ -19840,6 +19854,22 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19840
19854
|
]
|
|
19841
19855
|
});
|
|
19842
19856
|
}
|
|
19857
|
+
if (reconnectContractSummary) {
|
|
19858
|
+
checks.push({
|
|
19859
|
+
detail: reconnectContractSummary.status === "pass" ? `${reconnectContractSummary.passed} reconnect contract(s) are passing.` : reconnectContractSummary.total === 0 ? "No reconnect contracts are configured." : `${reconnectContractSummary.failed} reconnect contract(s) failed.`,
|
|
19860
|
+
href: options.links?.reconnectContracts ?? options.links?.sessions ?? "/sessions",
|
|
19861
|
+
label: "Reconnect recovery contracts",
|
|
19862
|
+
status: reconnectContractSummary.status,
|
|
19863
|
+
value: `${reconnectContractSummary.passed}/${reconnectContractSummary.total}`,
|
|
19864
|
+
actions: reconnectContractSummary.status === "pass" ? [] : [
|
|
19865
|
+
{
|
|
19866
|
+
description: "Open reconnect proof and inspect disconnect, resume, and replay-safe turn state evidence.",
|
|
19867
|
+
href: options.links?.reconnectContracts ?? options.links?.sessions ?? "/sessions",
|
|
19868
|
+
label: "Open reconnect proof"
|
|
19869
|
+
}
|
|
19870
|
+
]
|
|
19871
|
+
});
|
|
19872
|
+
}
|
|
19843
19873
|
if (audit) {
|
|
19844
19874
|
const missingLabels = audit.missing.map((requirement) => requirement.label ?? requirement.type);
|
|
19845
19875
|
checks.push({
|
|
@@ -19919,6 +19949,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19919
19949
|
phoneAgentSmoke: "/sessions",
|
|
19920
19950
|
providerRoutingContracts: "/resilience",
|
|
19921
19951
|
quality: "/quality",
|
|
19952
|
+
reconnectContracts: "/sessions",
|
|
19922
19953
|
resilience: "/resilience",
|
|
19923
19954
|
sessions: "/sessions",
|
|
19924
19955
|
traceDeliveries: "/traces/deliveries",
|
|
@@ -19941,6 +19972,7 @@ var buildVoiceProductionReadinessReport = async (options, input = {}) => {
|
|
|
19941
19972
|
},
|
|
19942
19973
|
phoneAgentSmokes: phoneAgentSmokeSummary,
|
|
19943
19974
|
providerRoutingContracts: providerRoutingContractSummary,
|
|
19975
|
+
reconnectContracts: reconnectContractSummary,
|
|
19944
19976
|
quality: {
|
|
19945
19977
|
status: quality.status
|
|
19946
19978
|
},
|
|
@@ -5,6 +5,7 @@ import type { VoiceTraceSinkDeliveryStore } from './trace';
|
|
|
5
5
|
import type { VoiceAgentSquadContractReport } from './agentSquadContract';
|
|
6
6
|
import type { VoiceProviderRoutingContractReport } from './providerRoutingContract';
|
|
7
7
|
import type { VoicePhoneAgentProductionSmokeReport } from './phoneAgentProductionSmoke';
|
|
8
|
+
import type { VoiceReconnectContractReport } from './reconnectContract';
|
|
8
9
|
import type { VoiceAuditEventStore, VoiceAuditEventType, VoiceAuditOutcome } from './audit';
|
|
9
10
|
import { type VoiceAuditSinkDeliveryStore } from './auditSinks';
|
|
10
11
|
export type VoiceProductionReadinessStatus = 'fail' | 'pass' | 'warn';
|
|
@@ -36,6 +37,7 @@ export type VoiceProductionReadinessReport = {
|
|
|
36
37
|
phoneAgentSmoke?: string;
|
|
37
38
|
providerRoutingContracts?: string;
|
|
38
39
|
quality?: string;
|
|
40
|
+
reconnectContracts?: string;
|
|
39
41
|
resilience?: string;
|
|
40
42
|
sessions?: string;
|
|
41
43
|
traceDeliveries?: string;
|
|
@@ -84,6 +86,12 @@ export type VoiceProductionReadinessReport = {
|
|
|
84
86
|
status: VoiceProductionReadinessStatus;
|
|
85
87
|
total: number;
|
|
86
88
|
};
|
|
89
|
+
reconnectContracts?: {
|
|
90
|
+
failed: number;
|
|
91
|
+
passed: number;
|
|
92
|
+
status: VoiceProductionReadinessStatus;
|
|
93
|
+
total: number;
|
|
94
|
+
};
|
|
87
95
|
quality: {
|
|
88
96
|
status: 'fail' | 'pass';
|
|
89
97
|
};
|
|
@@ -181,6 +189,10 @@ export type VoiceProductionReadinessRoutesOptions = {
|
|
|
181
189
|
query: Record<string, unknown>;
|
|
182
190
|
request: Request;
|
|
183
191
|
}) => Promise<readonly VoiceProviderRoutingContractReport[]> | readonly VoiceProviderRoutingContractReport[]);
|
|
192
|
+
reconnectContracts?: false | readonly VoiceReconnectContractReport[] | ((input: {
|
|
193
|
+
query: Record<string, unknown>;
|
|
194
|
+
request: Request;
|
|
195
|
+
}) => Promise<readonly VoiceReconnectContractReport[]> | readonly VoiceReconnectContractReport[]);
|
|
184
196
|
render?: (report: VoiceProductionReadinessReport) => string | Promise<string>;
|
|
185
197
|
store: VoiceTraceEventStore;
|
|
186
198
|
sttProviders?: readonly string[];
|