@absolutejs/voice 0.0.22-beta.137 → 0.0.22-beta.139

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.
@@ -905,10 +905,34 @@ var createVoiceStream = (path, options = {}) => {
905
905
  const notify = () => {
906
906
  subscribers.forEach((subscriber) => subscriber());
907
907
  };
908
+ const reportReconnect = () => {
909
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
910
+ return;
911
+ }
912
+ const snapshot = store.getSnapshot();
913
+ const body = JSON.stringify({
914
+ at: Date.now(),
915
+ reconnect: snapshot.reconnect,
916
+ scenarioId: snapshot.scenarioId,
917
+ sessionId: connection.getSessionId(),
918
+ turnIds: snapshot.turns.map((turn) => turn.id)
919
+ });
920
+ fetch(options.reconnectReportPath, {
921
+ body,
922
+ headers: {
923
+ "Content-Type": "application/json"
924
+ },
925
+ keepalive: true,
926
+ method: "POST"
927
+ }).catch(() => {});
928
+ };
908
929
  const unsubscribeConnection = connection.subscribe((message) => {
909
930
  const action = serverMessageToAction(message);
910
931
  if (action) {
911
932
  store.dispatch(action);
933
+ if (message.type === "connection") {
934
+ reportReconnect();
935
+ }
912
936
  notify();
913
937
  }
914
938
  });
@@ -684,10 +684,34 @@ var createVoiceStream = (path, options = {}) => {
684
684
  const notify = () => {
685
685
  subscribers.forEach((subscriber) => subscriber());
686
686
  };
687
+ const reportReconnect = () => {
688
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
689
+ return;
690
+ }
691
+ const snapshot = store.getSnapshot();
692
+ const body = JSON.stringify({
693
+ at: Date.now(),
694
+ reconnect: snapshot.reconnect,
695
+ scenarioId: snapshot.scenarioId,
696
+ sessionId: connection.getSessionId(),
697
+ turnIds: snapshot.turns.map((turn) => turn.id)
698
+ });
699
+ fetch(options.reconnectReportPath, {
700
+ body,
701
+ headers: {
702
+ "Content-Type": "application/json"
703
+ },
704
+ keepalive: true,
705
+ method: "POST"
706
+ }).catch(() => {});
707
+ };
687
708
  const unsubscribeConnection = connection.subscribe((message) => {
688
709
  const action = serverMessageToAction(message);
689
710
  if (action) {
690
711
  store.dispatch(action);
712
+ if (message.type === "connection") {
713
+ reportReconnect();
714
+ }
691
715
  notify();
692
716
  }
693
717
  });
@@ -1871,6 +1895,7 @@ var initVoiceHTMXRoot = (root) => {
1871
1895
  const guidedPrompts = parsePromptList(root.dataset.voiceGuidedPrompts);
1872
1896
  const guidedLabel = root.dataset.voiceGuidedLabel ?? DEFAULT_GUIDED_LABEL;
1873
1897
  const generalLabel = root.dataset.voiceGeneralLabel ?? DEFAULT_GENERAL_LABEL;
1898
+ const reconnectReportPath = root.dataset.voiceReconnectReportPath;
1874
1899
  const bargeInPath = root.dataset.voiceBargeInPath;
1875
1900
  const bargeInMonitor = bargeInPath ? createVoiceBargeInMonitor({
1876
1901
  path: bargeInPath,
@@ -1917,6 +1942,9 @@ var initVoiceHTMXRoot = (root) => {
1917
1942
  renderWave();
1918
1943
  }
1919
1944
  },
1945
+ connection: {
1946
+ reconnectReportPath
1947
+ },
1920
1948
  preset: "guided-intake"
1921
1949
  });
1922
1950
  const generalVoice = createVoiceController(generalPath, {
@@ -1934,6 +1962,9 @@ var initVoiceHTMXRoot = (root) => {
1934
1962
  renderWave();
1935
1963
  }
1936
1964
  },
1965
+ connection: {
1966
+ reconnectReportPath
1967
+ },
1937
1968
  preset: "dictation"
1938
1969
  });
1939
1970
  const stopGuidedBinding = guidedVoice.bindHTMX({ element: syncElement });
@@ -958,10 +958,34 @@ var createVoiceStream = (path, options = {}) => {
958
958
  const notify = () => {
959
959
  subscribers.forEach((subscriber) => subscriber());
960
960
  };
961
+ const reportReconnect = () => {
962
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
963
+ return;
964
+ }
965
+ const snapshot = store.getSnapshot();
966
+ const body = JSON.stringify({
967
+ at: Date.now(),
968
+ reconnect: snapshot.reconnect,
969
+ scenarioId: snapshot.scenarioId,
970
+ sessionId: connection.getSessionId(),
971
+ turnIds: snapshot.turns.map((turn) => turn.id)
972
+ });
973
+ fetch(options.reconnectReportPath, {
974
+ body,
975
+ headers: {
976
+ "Content-Type": "application/json"
977
+ },
978
+ keepalive: true,
979
+ method: "POST"
980
+ }).catch(() => {});
981
+ };
961
982
  const unsubscribeConnection = connection.subscribe((message) => {
962
983
  const action = serverMessageToAction(message);
963
984
  if (action) {
964
985
  store.dispatch(action);
986
+ if (message.type === "connection") {
987
+ reportReconnect();
988
+ }
965
989
  notify();
966
990
  }
967
991
  });
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { buildVoiceAuditExport, exportVoiceAuditTrail, redactVoiceAuditEvent, re
9
9
  export { createVoiceAuditHTTPSink, createVoiceAuditSinkDeliveryId, createVoiceAuditSinkDeliveryRecord, createVoiceAuditSinkDeliveryWorker, createVoiceAuditSinkDeliveryWorkerLoop, createVoiceAuditSinkStore, createVoiceMemoryAuditSinkDeliveryStore, deliverVoiceAuditEventsToSinks, summarizeVoiceAuditSinkDeliveries } from './auditSinks';
10
10
  export { buildVoiceAuditDeliveryReport, createVoiceAuditDeliveryHTMLHandler, createVoiceAuditDeliveryJSONHandler, createVoiceAuditDeliveryRoutes, renderVoiceAuditDeliveryHTML, resolveVoiceAuditDeliveryFilter } from './auditDeliveryRoutes';
11
11
  export { createVoiceBargeInRoutes, renderVoiceBargeInHTML, summarizeVoiceBargeIn } from './bargeInRoutes';
12
- export { createVoiceReconnectContractRoutes, renderVoiceReconnectContractHTML, runVoiceReconnectContract } from './reconnectContract';
12
+ export { createVoiceReconnectContractRoutes, renderVoiceReconnectContractHTML, summarizeVoiceReconnectContractSnapshots, runVoiceReconnectContract } from './reconnectContract';
13
13
  export { buildVoiceDiagnosticsMarkdown, createVoiceDiagnosticsRoutes, resolveVoiceDiagnosticsTraceFilter } from './diagnosticsRoutes';
14
14
  export { buildVoiceDemoReadyReport, createVoiceDemoReadyRoutes, renderVoiceDemoReadyHTML } from './demoReadyRoutes';
15
15
  export { applyVoiceDataRetentionPolicy, buildVoiceDataRetentionPlan } from './dataControl';
package/dist/index.js CHANGED
@@ -9999,6 +9999,21 @@ var createVoiceBargeInRoutes = (options) => {
9999
9999
  import { Elysia as Elysia8 } from "elysia";
10000
10000
  var escapeHtml11 = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
10001
10001
  var unique = (values) => [...new Set(values)];
10002
+ var isReconnectPayload = (value) => {
10003
+ if (!value || typeof value !== "object") {
10004
+ return false;
10005
+ }
10006
+ const payload = value;
10007
+ return typeof payload.at === "number" && !!payload.reconnect && typeof payload.reconnect === "object" && typeof payload.reconnect.attempts === "number" && typeof payload.reconnect.maxAttempts === "number" && typeof payload.reconnect.status === "string";
10008
+ };
10009
+ var summarizeVoiceReconnectContractSnapshots = (events, options = {}) => events.filter((event) => event.type === "client.reconnect" && (!options.sessionId || event.sessionId === options.sessionId) && isReconnectPayload(event.payload)).map((event) => {
10010
+ const payload = event.payload;
10011
+ return {
10012
+ at: typeof payload.at === "number" ? payload.at : event.at,
10013
+ reconnect: payload.reconnect,
10014
+ turnIds: Array.isArray(payload.turnIds) ? payload.turnIds.filter((turnId) => typeof turnId === "string") : undefined
10015
+ };
10016
+ }).sort((left, right) => left.at - right.at);
10002
10017
  var findDuplicateTurnIds = (snapshots) => {
10003
10018
  const duplicates = new Set;
10004
10019
  for (const snapshot of snapshots) {
@@ -22769,6 +22784,7 @@ export {
22769
22784
  summarizeVoiceSessionReplay,
22770
22785
  summarizeVoiceRoutingSessions,
22771
22786
  summarizeVoiceRoutingDecision,
22787
+ summarizeVoiceReconnectContractSnapshots,
22772
22788
  summarizeVoiceProviderHealth,
22773
22789
  summarizeVoiceProviderFallbackRecovery,
22774
22790
  summarizeVoiceProviderCapabilities,
@@ -3042,10 +3042,34 @@ var createVoiceStream = (path, options = {}) => {
3042
3042
  const notify = () => {
3043
3043
  subscribers.forEach((subscriber) => subscriber());
3044
3044
  };
3045
+ const reportReconnect = () => {
3046
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
3047
+ return;
3048
+ }
3049
+ const snapshot = store.getSnapshot();
3050
+ const body = JSON.stringify({
3051
+ at: Date.now(),
3052
+ reconnect: snapshot.reconnect,
3053
+ scenarioId: snapshot.scenarioId,
3054
+ sessionId: connection.getSessionId(),
3055
+ turnIds: snapshot.turns.map((turn) => turn.id)
3056
+ });
3057
+ fetch(options.reconnectReportPath, {
3058
+ body,
3059
+ headers: {
3060
+ "Content-Type": "application/json"
3061
+ },
3062
+ keepalive: true,
3063
+ method: "POST"
3064
+ }).catch(() => {});
3065
+ };
3045
3066
  const unsubscribeConnection = connection.subscribe((message) => {
3046
3067
  const action = serverMessageToAction(message);
3047
3068
  if (action) {
3048
3069
  store.dispatch(action);
3070
+ if (message.type === "connection") {
3071
+ reportReconnect();
3072
+ }
3049
3073
  notify();
3050
3074
  }
3051
3075
  });
@@ -1,5 +1,6 @@
1
1
  import { Elysia } from 'elysia';
2
2
  import type { VoiceReconnectClientState } from './types';
3
+ import type { StoredVoiceTraceEvent } from './trace';
3
4
  export type VoiceReconnectContractSnapshot = {
4
5
  at: number;
5
6
  reconnect: VoiceReconnectClientState;
@@ -39,6 +40,9 @@ export type VoiceReconnectContractRoutesOptions = Omit<VoiceReconnectContractOpt
39
40
  path?: string;
40
41
  render?: (report: VoiceReconnectContractReport) => string | Promise<string>;
41
42
  };
43
+ export declare const summarizeVoiceReconnectContractSnapshots: (events: readonly StoredVoiceTraceEvent[], options?: {
44
+ sessionId?: string;
45
+ }) => VoiceReconnectContractSnapshot[];
42
46
  export declare const runVoiceReconnectContract: (options: VoiceReconnectContractOptions) => VoiceReconnectContractReport;
43
47
  export declare const renderVoiceReconnectContractHTML: (report: VoiceReconnectContractReport) => string;
44
48
  export declare const createVoiceReconnectContractRoutes: (options: VoiceReconnectContractRoutesOptions) => Elysia<"", {
@@ -1340,10 +1340,34 @@ var createVoiceStream = (path, options = {}) => {
1340
1340
  const notify = () => {
1341
1341
  subscribers.forEach((subscriber) => subscriber());
1342
1342
  };
1343
+ const reportReconnect = () => {
1344
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
1345
+ return;
1346
+ }
1347
+ const snapshot = store.getSnapshot();
1348
+ const body = JSON.stringify({
1349
+ at: Date.now(),
1350
+ reconnect: snapshot.reconnect,
1351
+ scenarioId: snapshot.scenarioId,
1352
+ sessionId: connection.getSessionId(),
1353
+ turnIds: snapshot.turns.map((turn) => turn.id)
1354
+ });
1355
+ fetch(options.reconnectReportPath, {
1356
+ body,
1357
+ headers: {
1358
+ "Content-Type": "application/json"
1359
+ },
1360
+ keepalive: true,
1361
+ method: "POST"
1362
+ }).catch(() => {});
1363
+ };
1343
1364
  const unsubscribeConnection = connection.subscribe((message) => {
1344
1365
  const action = serverMessageToAction(message);
1345
1366
  if (action) {
1346
1367
  store.dispatch(action);
1368
+ if (message.type === "connection") {
1369
+ reportReconnect();
1370
+ }
1347
1371
  notify();
1348
1372
  }
1349
1373
  });
@@ -2601,10 +2601,34 @@ var createVoiceStream = (path, options = {}) => {
2601
2601
  const notify = () => {
2602
2602
  subscribers.forEach((subscriber) => subscriber());
2603
2603
  };
2604
+ const reportReconnect = () => {
2605
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
2606
+ return;
2607
+ }
2608
+ const snapshot = store.getSnapshot();
2609
+ const body = JSON.stringify({
2610
+ at: Date.now(),
2611
+ reconnect: snapshot.reconnect,
2612
+ scenarioId: snapshot.scenarioId,
2613
+ sessionId: connection.getSessionId(),
2614
+ turnIds: snapshot.turns.map((turn) => turn.id)
2615
+ });
2616
+ fetch(options.reconnectReportPath, {
2617
+ body,
2618
+ headers: {
2619
+ "Content-Type": "application/json"
2620
+ },
2621
+ keepalive: true,
2622
+ method: "POST"
2623
+ }).catch(() => {});
2624
+ };
2604
2625
  const unsubscribeConnection = connection.subscribe((message) => {
2605
2626
  const action = serverMessageToAction(message);
2606
2627
  if (action) {
2607
2628
  store.dispatch(action);
2629
+ if (message.type === "connection") {
2630
+ reportReconnect();
2631
+ }
2608
2632
  notify();
2609
2633
  }
2610
2634
  });
package/dist/trace.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.handoff' | 'call.lifecycle' | 'client.barge_in' | 'client.live_latency' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn_latency.stage' | 'turn.transcript' | 'workflow.contract';
1
+ export type VoiceTraceEventType = 'assistant.guardrail' | 'assistant.memory' | 'assistant.run' | 'agent.handoff' | 'agent.model' | 'agent.result' | 'agent.tool' | 'call.handoff' | 'call.lifecycle' | 'client.barge_in' | 'client.live_latency' | 'client.reconnect' | 'session.error' | 'turn.assistant' | 'turn.committed' | 'turn.cost' | 'turn_latency.stage' | 'turn.transcript' | 'workflow.contract';
2
2
  export type VoiceTraceEvent<TPayload extends Record<string, unknown> = Record<string, unknown>> = {
3
3
  at: number;
4
4
  id?: string;
package/dist/types.d.ts CHANGED
@@ -755,6 +755,7 @@ export type VoiceConnectionOptions = {
755
755
  protocols?: string[];
756
756
  scenarioId?: string;
757
757
  reconnect?: boolean;
758
+ reconnectReportPath?: string;
758
759
  maxReconnectAttempts?: number;
759
760
  pingInterval?: number;
760
761
  sessionId?: string;
package/dist/vue/index.js CHANGED
@@ -2813,10 +2813,34 @@ var createVoiceStream = (path, options = {}) => {
2813
2813
  const notify = () => {
2814
2814
  subscribers.forEach((subscriber) => subscriber());
2815
2815
  };
2816
+ const reportReconnect = () => {
2817
+ if (!options.reconnectReportPath || typeof fetch === "undefined") {
2818
+ return;
2819
+ }
2820
+ const snapshot = store.getSnapshot();
2821
+ const body = JSON.stringify({
2822
+ at: Date.now(),
2823
+ reconnect: snapshot.reconnect,
2824
+ scenarioId: snapshot.scenarioId,
2825
+ sessionId: connection.getSessionId(),
2826
+ turnIds: snapshot.turns.map((turn) => turn.id)
2827
+ });
2828
+ fetch(options.reconnectReportPath, {
2829
+ body,
2830
+ headers: {
2831
+ "Content-Type": "application/json"
2832
+ },
2833
+ keepalive: true,
2834
+ method: "POST"
2835
+ }).catch(() => {});
2836
+ };
2816
2837
  const unsubscribeConnection = connection.subscribe((message) => {
2817
2838
  const action = serverMessageToAction(message);
2818
2839
  if (action) {
2819
2840
  store.dispatch(action);
2841
+ if (message.type === "connection") {
2842
+ reportReconnect();
2843
+ }
2820
2844
  notify();
2821
2845
  }
2822
2846
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.137",
3
+ "version": "0.0.22-beta.139",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",