@absolutejs/voice 0.0.22-beta.581 → 0.0.22-beta.583

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.
@@ -22,9 +22,16 @@ type MinimalGainNode = {
22
22
  value: number;
23
23
  };
24
24
  };
25
+ type MinimalAnalyserNode = {
26
+ connect?: (destination: unknown) => void;
27
+ disconnect?: () => void;
28
+ fftSize: number;
29
+ getByteTimeDomainData: (array: Uint8Array) => void;
30
+ };
25
31
  type MinimalAudioContext = {
26
32
  baseLatency?: number;
27
33
  close: () => Promise<void>;
34
+ createAnalyser?: () => MinimalAnalyserNode;
28
35
  createBuffer: (numberOfChannels: number, length: number, sampleRate: number) => MinimalAudioBuffer;
29
36
  createBufferSource: () => MinimalAudioBufferSourceNode;
30
37
  createGain?: () => MinimalGainNode;
@@ -1693,6 +1693,8 @@ var DEFAULT_PLAYBACK_RATE = 1;
1693
1693
  var MIN_PLAYBACK_RATE = 0.5;
1694
1694
  var MAX_PLAYBACK_RATE = 2;
1695
1695
  var STRETCH_BYPASS_EPSILON = 0.01;
1696
+ var ANALYSER_FFT_SIZE = 256;
1697
+ var PCM_BYTE_MIDPOINT = 128;
1696
1698
  var createInitialState3 = () => ({
1697
1699
  activeSourceCount: 0,
1698
1700
  error: null,
@@ -1753,6 +1755,8 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1753
1755
  let state = createInitialState3();
1754
1756
  let audioContext = null;
1755
1757
  let outputNode = null;
1758
+ let analyserNode = null;
1759
+ let analyserBuffer = null;
1756
1760
  let volume = clampVolume(options.volume);
1757
1761
  let playbackRate = clampPlaybackRate(options.playbackRate);
1758
1762
  let stretcher = null;
@@ -1849,6 +1853,12 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1849
1853
  if (audioContext.createGain) {
1850
1854
  outputNode = audioContext.createGain();
1851
1855
  outputNode.connect?.(audioContext.destination);
1856
+ if (audioContext.createAnalyser) {
1857
+ analyserNode = audioContext.createAnalyser();
1858
+ analyserNode.fftSize = ANALYSER_FFT_SIZE;
1859
+ analyserBuffer = new Uint8Array(analyserNode.fftSize);
1860
+ outputNode.connect?.(analyserNode);
1861
+ }
1852
1862
  }
1853
1863
  queueEndTime = audioContext.currentTime;
1854
1864
  return audioContext;
@@ -1973,6 +1983,9 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1973
1983
  audioContext = null;
1974
1984
  outputNode?.disconnect?.();
1975
1985
  outputNode = null;
1986
+ analyserNode?.disconnect?.();
1987
+ analyserNode = null;
1988
+ analyserBuffer = null;
1976
1989
  queueEndTime = 0;
1977
1990
  setState({
1978
1991
  activeSourceCount: 0,
@@ -1983,6 +1996,18 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1983
1996
  get error() {
1984
1997
  return state.error;
1985
1998
  },
1999
+ getOutputLevel: () => {
2000
+ if (!analyserNode || !analyserBuffer) {
2001
+ return 0;
2002
+ }
2003
+ analyserNode.getByteTimeDomainData(analyserBuffer);
2004
+ let sumSquares = 0;
2005
+ for (const sample of analyserBuffer) {
2006
+ const centered = (sample - PCM_BYTE_MIDPOINT) / PCM_BYTE_MIDPOINT;
2007
+ sumSquares += centered * centered;
2008
+ }
2009
+ return Math.sqrt(sumSquares / analyserBuffer.length);
2010
+ },
1986
2011
  getSnapshot: () => state,
1987
2012
  interrupt: async () => {
1988
2013
  const startedAt = Date.now();
@@ -529,6 +529,8 @@ var DEFAULT_PLAYBACK_RATE = 1;
529
529
  var MIN_PLAYBACK_RATE = 0.5;
530
530
  var MAX_PLAYBACK_RATE = 2;
531
531
  var STRETCH_BYPASS_EPSILON = 0.01;
532
+ var ANALYSER_FFT_SIZE = 256;
533
+ var PCM_BYTE_MIDPOINT = 128;
532
534
  var createInitialState = () => ({
533
535
  activeSourceCount: 0,
534
536
  error: null,
@@ -589,6 +591,8 @@ var createVoiceAudioPlayer = (source, options = {}) => {
589
591
  let state = createInitialState();
590
592
  let audioContext = null;
591
593
  let outputNode = null;
594
+ let analyserNode = null;
595
+ let analyserBuffer = null;
592
596
  let volume = clampVolume(options.volume);
593
597
  let playbackRate = clampPlaybackRate(options.playbackRate);
594
598
  let stretcher = null;
@@ -685,6 +689,12 @@ var createVoiceAudioPlayer = (source, options = {}) => {
685
689
  if (audioContext.createGain) {
686
690
  outputNode = audioContext.createGain();
687
691
  outputNode.connect?.(audioContext.destination);
692
+ if (audioContext.createAnalyser) {
693
+ analyserNode = audioContext.createAnalyser();
694
+ analyserNode.fftSize = ANALYSER_FFT_SIZE;
695
+ analyserBuffer = new Uint8Array(analyserNode.fftSize);
696
+ outputNode.connect?.(analyserNode);
697
+ }
688
698
  }
689
699
  queueEndTime = audioContext.currentTime;
690
700
  return audioContext;
@@ -809,6 +819,9 @@ var createVoiceAudioPlayer = (source, options = {}) => {
809
819
  audioContext = null;
810
820
  outputNode?.disconnect?.();
811
821
  outputNode = null;
822
+ analyserNode?.disconnect?.();
823
+ analyserNode = null;
824
+ analyserBuffer = null;
812
825
  queueEndTime = 0;
813
826
  setState({
814
827
  activeSourceCount: 0,
@@ -819,6 +832,18 @@ var createVoiceAudioPlayer = (source, options = {}) => {
819
832
  get error() {
820
833
  return state.error;
821
834
  },
835
+ getOutputLevel: () => {
836
+ if (!analyserNode || !analyserBuffer) {
837
+ return 0;
838
+ }
839
+ analyserNode.getByteTimeDomainData(analyserBuffer);
840
+ let sumSquares = 0;
841
+ for (const sample of analyserBuffer) {
842
+ const centered = (sample - PCM_BYTE_MIDPOINT) / PCM_BYTE_MIDPOINT;
843
+ sumSquares += centered * centered;
844
+ }
845
+ return Math.sqrt(sumSquares / analyserBuffer.length);
846
+ },
822
847
  getSnapshot: () => state,
823
848
  interrupt: async () => {
824
849
  const startedAt = Date.now();
@@ -0,0 +1,11 @@
1
+ export declare const logVoiceTiming: (sessionId: string, stage: string, elapsedMs: number, detail?: Record<string, unknown>) => void;
2
+ /**
3
+ * A per-turn stopwatch. `stamp(stage, detail?)` logs the elapsed since the timer
4
+ * was created, so one timer per turn lays every stage out on a single timeline:
5
+ *
6
+ * const stamp = startVoiceTimer(session.id);
7
+ * stamp("agent.system-resolved", { chars });
8
+ * stamp("agent.round0.generate-done", { ms });
9
+ */
10
+ export declare const startVoiceTimer: (sessionId: string) => (stage: string, detail?: Record<string, unknown>) => void;
11
+ export declare const voiceTimingEnabled: () => boolean;
@@ -1331,6 +1331,9 @@ export type VoiceAudioPlayerSource = {
1331
1331
  export type VoiceAudioPlayer = {
1332
1332
  close: () => Promise<void>;
1333
1333
  error: string | null;
1334
+ /** Instantaneous RMS amplitude (0..1) of the assistant's audio output — for
1335
+ * driving a visualizer from the actual voice. 0 when idle / no analyser. */
1336
+ getOutputLevel: () => number;
1334
1337
  getSnapshot: () => VoiceAudioPlayerState;
1335
1338
  activeSourceCount: number;
1336
1339
  isActive: boolean;
package/dist/index.d.ts CHANGED
@@ -71,6 +71,7 @@ export { createVoiceSessionListRoutes, createVoiceSessionReplayHTMLHandler, crea
71
71
  export { createVoiceAgent, createVoiceAgentSquad, createVoiceAgentTool, } from "./core/agent";
72
72
  export { createPersonaVoiceCaller, createScriptedVoiceCaller, renderVoiceSimulationTranscript, runVoiceConversationSimulation, } from "./core/conversationSimulator";
73
73
  export type { RunVoiceConversationSimulationInput, VoiceConversationSimulationEndedReason, VoiceConversationSimulationResult, VoicePersonaCallerCompletion, VoiceScriptedCallerStep, VoiceSimulatedSpeaker, VoiceSimulatedTurn, VoiceSimulatorCaller, VoiceSimulatorCallerModel, VoiceSimulatorCallerReply, } from "./core/conversationSimulator";
74
+ export { logVoiceTiming, startVoiceTimer, voiceTimingEnabled, } from "./core/debugTiming";
74
75
  export { createVoiceMCPToolset } from "./core/mcpToolset";
75
76
  export type { CreateVoiceMCPToolsetOptions, MCPClientLike, MCPToolCallResult, MCPToolContentBlock, MCPToolDefinition, VoiceMCPToolResult, } from "./core/mcpToolset";
76
77
  export { createAIVoiceModel } from "./core/aiVoiceModel";
package/dist/index.js CHANGED
@@ -3091,6 +3091,21 @@ var toVoiceSessionSummary = (session) => ({
3091
3091
  // src/core/session.ts
3092
3092
  import { Buffer as Buffer2 } from "buffer";
3093
3093
 
3094
+ // src/core/debugTiming.ts
3095
+ var timingEnabled = () => process.env.ABSOLUTEJS_VOICE_TIMING === "1" || process.env.ABSOLUTEJS_VOICE_TIMING === "true";
3096
+ var emitTiming = (sessionId, stage, elapsedMs, detail) => {
3097
+ if (!timingEnabled())
3098
+ return;
3099
+ const extra = detail ? ` ${JSON.stringify(detail)}` : "";
3100
+ console.info(`[voice][timing] session=${sessionId} ${stage} +${Math.round(elapsedMs)}ms${extra}`);
3101
+ };
3102
+ var logVoiceTiming = (sessionId, stage, elapsedMs, detail) => emitTiming(sessionId, stage, elapsedMs, detail);
3103
+ var startVoiceTimer = (sessionId) => {
3104
+ const startedAt = Date.now();
3105
+ return (stage, detail) => emitTiming(sessionId, stage, Date.now() - startedAt, detail);
3106
+ };
3107
+ var voiceTimingEnabled = () => timingEnabled();
3108
+
3094
3109
  // src/core/backchannel.ts
3095
3110
  var DEFAULT_CUES = [
3096
3111
  { text: "mm-hmm" },
@@ -5534,6 +5549,7 @@ var createVoiceSession = (options) => {
5534
5549
  const onTurnTimeoutMs = options.routeOnTurnTimeoutMs ?? 45000;
5535
5550
  let committedOutput;
5536
5551
  const onTurnStartedAt = Date.now();
5552
+ logVoiceTiming(session.id, "session.commit-to-onturn", onTurnStartedAt - (turn.committedAt || onTurnStartedAt), { fillerScheduled: fillerTimer !== null });
5537
5553
  try {
5538
5554
  const onTurnPromise = options.route.onTurn({
5539
5555
  api,
@@ -7446,7 +7462,9 @@ var createVoiceAgent = (options) => {
7446
7462
  const maxToolRounds = Math.max(0, options.maxToolRounds ?? 2);
7447
7463
  const audit = resolveVoiceAgentAuditLogger(options.audit);
7448
7464
  const run = async (input) => {
7465
+ const stamp = startVoiceTimer(input.session.id);
7449
7466
  const messages = input.messages ?? createHistoryMessages(input.session, input.turn);
7467
+ stamp("agent.history-built", { messages: messages.length });
7450
7468
  const toolResults = [];
7451
7469
  const baseSystem = typeof options.system === "function" ? await options.system({
7452
7470
  context: input.context,
@@ -7456,9 +7474,11 @@ var createVoiceAgent = (options) => {
7456
7474
  const system = [baseSystem, input.system].filter((value) => Boolean(value?.trim())).join(`
7457
7475
 
7458
7476
  `) || undefined;
7477
+ stamp("agent.system-resolved", { systemChars: system?.length ?? 0 });
7459
7478
  let output = {};
7460
7479
  for (let round = 0;round <= maxToolRounds; round += 1) {
7461
7480
  const modelStartedAt = Date.now();
7481
+ stamp(`agent.round${round}.generate-start`);
7462
7482
  try {
7463
7483
  output = await options.model.generate({
7464
7484
  agentId: options.id,
@@ -7474,6 +7494,11 @@ var createVoiceAgent = (options) => {
7474
7494
  })),
7475
7495
  turn: input.turn
7476
7496
  });
7497
+ stamp(`agent.round${round}.generate-done`, {
7498
+ ms: Date.now() - modelStartedAt,
7499
+ textChars: output.assistantText?.length ?? 0,
7500
+ toolCalls: output.toolCalls?.length ?? 0
7501
+ });
7477
7502
  await audit?.providerCall({
7478
7503
  actor: {
7479
7504
  id: options.id,
@@ -7487,6 +7512,9 @@ var createVoiceAgent = (options) => {
7487
7512
  sessionId: input.session.id
7488
7513
  });
7489
7514
  } catch (error) {
7515
+ stamp(`agent.round${round}.generate-error`, {
7516
+ ms: Date.now() - modelStartedAt
7517
+ });
7490
7518
  await audit?.providerCall({
7491
7519
  actor: {
7492
7520
  id: options.id,
@@ -45368,6 +45396,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
45368
45396
  const timeoutMs = options.timeoutMs ?? 60000;
45369
45397
  return {
45370
45398
  generate: async (input) => {
45399
+ const stamp = startVoiceTimer(input.session.id);
45371
45400
  const ac = new AbortController;
45372
45401
  const timer = setTimeout(() => {
45373
45402
  ac.abort(new Error(`OpenAI /responses timed out after ${timeoutMs}ms (no completion event received)`));
@@ -45408,6 +45437,10 @@ var createOpenAIVoiceAssistantModel = (options) => {
45408
45437
  clearTimeout(timer);
45409
45438
  throw error;
45410
45439
  }
45440
+ stamp("openai.fetch-returned", {
45441
+ messages: input.messages.length,
45442
+ status: response.status
45443
+ });
45411
45444
  if (!response.ok) {
45412
45445
  clearTimeout(timer);
45413
45446
  throw createHTTPError("OpenAI", response);
@@ -45415,11 +45448,23 @@ var createOpenAIVoiceAssistantModel = (options) => {
45415
45448
  let assistantText;
45416
45449
  let toolCalls;
45417
45450
  let usage;
45451
+ let firstDeltaSeen = false;
45452
+ const onTextDelta = input.onTextDelta ? (delta) => {
45453
+ if (!firstDeltaSeen) {
45454
+ firstDeltaSeen = true;
45455
+ stamp("openai.first-delta");
45456
+ }
45457
+ input.onTextDelta?.(delta);
45458
+ } : undefined;
45418
45459
  try {
45419
- ({ assistantText, toolCalls, usage } = await consumeOpenAIResponsesStream(response, input.onTextDelta, {
45460
+ ({ assistantText, toolCalls, usage } = await consumeOpenAIResponsesStream(response, onTextDelta, {
45420
45461
  signal: ac.signal,
45421
45462
  inactivityMs: 1e4
45422
45463
  }));
45464
+ stamp("openai.stream-done", {
45465
+ textChars: assistantText?.length ?? 0,
45466
+ toolCalls: toolCalls.length
45467
+ });
45423
45468
  } finally {
45424
45469
  clearTimeout(timer);
45425
45470
  }
@@ -52391,6 +52436,7 @@ export {
52391
52436
  wrapVoiceHTMLInHTMXContainer,
52392
52437
  withVoiceOpsTaskId,
52393
52438
  withVoiceIntegrationEventId,
52439
+ voiceTimingEnabled,
52394
52440
  voiceTelephonyOutcomeToRouteResult,
52395
52441
  voiceObservabilityExportSchemaVersion,
52396
52442
  voiceObservabilityExportSchemaId,
@@ -52448,6 +52494,7 @@ export {
52448
52494
  summarizeVoiceAuditSinkDeliveries,
52449
52495
  summarizeVoiceAssistantRuns,
52450
52496
  summarizeVoiceAssistantHealth,
52497
+ startVoiceTimer,
52451
52498
  startVoiceOpsTask,
52452
52499
  signVoiceWebhookBody,
52453
52500
  signVoiceTwilioWebhook,
@@ -52648,6 +52695,7 @@ export {
52648
52695
  matchesVoiceOpsTaskAssignmentRule,
52649
52696
  markVoiceOpsTaskSLABreached,
52650
52697
  mapVoiceProofTargetsWithConcurrency,
52698
+ logVoiceTiming,
52651
52699
  loadVoiceRealCallProfileEvidenceFromTraceStore,
52652
52700
  loadVoiceRealCallProfileEvidenceFromStore,
52653
52701
  loadVoiceObservabilityExportReplaySource,
@@ -1736,6 +1736,8 @@ var DEFAULT_PLAYBACK_RATE = 1;
1736
1736
  var MIN_PLAYBACK_RATE = 0.5;
1737
1737
  var MAX_PLAYBACK_RATE = 2;
1738
1738
  var STRETCH_BYPASS_EPSILON = 0.01;
1739
+ var ANALYSER_FFT_SIZE = 256;
1740
+ var PCM_BYTE_MIDPOINT = 128;
1739
1741
  var createInitialState = () => ({
1740
1742
  activeSourceCount: 0,
1741
1743
  error: null,
@@ -1796,6 +1798,8 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1796
1798
  let state = createInitialState();
1797
1799
  let audioContext = null;
1798
1800
  let outputNode = null;
1801
+ let analyserNode = null;
1802
+ let analyserBuffer = null;
1799
1803
  let volume = clampVolume(options.volume);
1800
1804
  let playbackRate = clampPlaybackRate(options.playbackRate);
1801
1805
  let stretcher = null;
@@ -1892,6 +1896,12 @@ var createVoiceAudioPlayer = (source, options = {}) => {
1892
1896
  if (audioContext.createGain) {
1893
1897
  outputNode = audioContext.createGain();
1894
1898
  outputNode.connect?.(audioContext.destination);
1899
+ if (audioContext.createAnalyser) {
1900
+ analyserNode = audioContext.createAnalyser();
1901
+ analyserNode.fftSize = ANALYSER_FFT_SIZE;
1902
+ analyserBuffer = new Uint8Array(analyserNode.fftSize);
1903
+ outputNode.connect?.(analyserNode);
1904
+ }
1895
1905
  }
1896
1906
  queueEndTime = audioContext.currentTime;
1897
1907
  return audioContext;
@@ -2016,6 +2026,9 @@ var createVoiceAudioPlayer = (source, options = {}) => {
2016
2026
  audioContext = null;
2017
2027
  outputNode?.disconnect?.();
2018
2028
  outputNode = null;
2029
+ analyserNode?.disconnect?.();
2030
+ analyserNode = null;
2031
+ analyserBuffer = null;
2019
2032
  queueEndTime = 0;
2020
2033
  setState({
2021
2034
  activeSourceCount: 0,
@@ -2026,6 +2039,18 @@ var createVoiceAudioPlayer = (source, options = {}) => {
2026
2039
  get error() {
2027
2040
  return state.error;
2028
2041
  },
2042
+ getOutputLevel: () => {
2043
+ if (!analyserNode || !analyserBuffer) {
2044
+ return 0;
2045
+ }
2046
+ analyserNode.getByteTimeDomainData(analyserBuffer);
2047
+ let sumSquares = 0;
2048
+ for (const sample of analyserBuffer) {
2049
+ const centered = (sample - PCM_BYTE_MIDPOINT) / PCM_BYTE_MIDPOINT;
2050
+ sumSquares += centered * centered;
2051
+ }
2052
+ return Math.sqrt(sumSquares / analyserBuffer.length);
2053
+ },
2029
2054
  getSnapshot: () => state,
2030
2055
  interrupt: async () => {
2031
2056
  const startedAt = Date.now();
@@ -4170,6 +4195,21 @@ var createVoiceIOProviderFailureSimulator = (options) => {
4170
4195
  run
4171
4196
  };
4172
4197
  };
4198
+ // src/core/debugTiming.ts
4199
+ var timingEnabled = () => process.env.ABSOLUTEJS_VOICE_TIMING === "1" || process.env.ABSOLUTEJS_VOICE_TIMING === "true";
4200
+ var emitTiming = (sessionId, stage, elapsedMs, detail) => {
4201
+ if (!timingEnabled())
4202
+ return;
4203
+ const extra = detail ? ` ${JSON.stringify(detail)}` : "";
4204
+ console.info(`[voice][timing] session=${sessionId} ${stage} +${Math.round(elapsedMs)}ms${extra}`);
4205
+ };
4206
+ var logVoiceTiming = (sessionId, stage, elapsedMs, detail) => emitTiming(sessionId, stage, elapsedMs, detail);
4207
+ var startVoiceTimer = (sessionId) => {
4208
+ const startedAt = Date.now();
4209
+ return (stage, detail) => emitTiming(sessionId, stage, Date.now() - startedAt, detail);
4210
+ };
4211
+ var voiceTimingEnabled = () => timingEnabled();
4212
+
4173
4213
  // src/core/modelAdapters.ts
4174
4214
  var isVoiceProviderRoutingPolicyPreset = (value) => value === "balanced" || value === "cost-cap" || value === "cost-first" || value === "latency-first" || value === "quality-first";
4175
4215
  var resolveVoiceProviderRoutingPolicyPreset = (preset, options = {}) => {
@@ -4880,6 +4920,7 @@ var createOpenAIVoiceAssistantModel = (options) => {
4880
4920
  const timeoutMs = options.timeoutMs ?? 60000;
4881
4921
  return {
4882
4922
  generate: async (input) => {
4923
+ const stamp = startVoiceTimer(input.session.id);
4883
4924
  const ac = new AbortController;
4884
4925
  const timer = setTimeout(() => {
4885
4926
  ac.abort(new Error(`OpenAI /responses timed out after ${timeoutMs}ms (no completion event received)`));
@@ -4920,6 +4961,10 @@ var createOpenAIVoiceAssistantModel = (options) => {
4920
4961
  clearTimeout(timer);
4921
4962
  throw error;
4922
4963
  }
4964
+ stamp("openai.fetch-returned", {
4965
+ messages: input.messages.length,
4966
+ status: response.status
4967
+ });
4923
4968
  if (!response.ok) {
4924
4969
  clearTimeout(timer);
4925
4970
  throw createHTTPError("OpenAI", response);
@@ -4927,11 +4972,23 @@ var createOpenAIVoiceAssistantModel = (options) => {
4927
4972
  let assistantText;
4928
4973
  let toolCalls;
4929
4974
  let usage;
4975
+ let firstDeltaSeen = false;
4976
+ const onTextDelta = input.onTextDelta ? (delta) => {
4977
+ if (!firstDeltaSeen) {
4978
+ firstDeltaSeen = true;
4979
+ stamp("openai.first-delta");
4980
+ }
4981
+ input.onTextDelta?.(delta);
4982
+ } : undefined;
4930
4983
  try {
4931
- ({ assistantText, toolCalls, usage } = await consumeOpenAIResponsesStream(response, input.onTextDelta, {
4984
+ ({ assistantText, toolCalls, usage } = await consumeOpenAIResponsesStream(response, onTextDelta, {
4932
4985
  signal: ac.signal,
4933
4986
  inactivityMs: 1e4
4934
4987
  }));
4988
+ stamp("openai.stream-done", {
4989
+ textChars: assistantText?.length ?? 0,
4990
+ toolCalls: toolCalls.length
4991
+ });
4935
4992
  } finally {
4936
4993
  clearTimeout(timer);
4937
4994
  }
@@ -7651,6 +7708,7 @@ var createVoiceSession = (options) => {
7651
7708
  const onTurnTimeoutMs = options.routeOnTurnTimeoutMs ?? 45000;
7652
7709
  let committedOutput;
7653
7710
  const onTurnStartedAt = Date.now();
7711
+ logVoiceTiming(session.id, "session.commit-to-onturn", onTurnStartedAt - (turn.committedAt || onTurnStartedAt), { fillerScheduled: fillerTimer !== null });
7654
7712
  try {
7655
7713
  const onTurnPromise = options.route.onTurn({
7656
7714
  api,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.581",
3
+ "version": "0.0.22-beta.583",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",