@absolutejs/voice 0.0.22-beta.641 → 0.0.22-beta.643

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.
@@ -1,3 +1 @@
1
- export declare const hardenFetch: (baseFetch?: typeof fetch) => ((input: Parameters<typeof fetch>[0], init: Parameters<typeof fetch>[1]) => Promise<Response>) & {
2
- preconnect: typeof fetch.preconnect;
3
- };
1
+ export declare const hardenFetch: (baseFetch?: typeof fetch) => (input: Parameters<typeof fetch>[0], init: Parameters<typeof fetch>[1]) => Promise<Response>;
package/dist/index.js CHANGED
@@ -4297,6 +4297,7 @@ var createVoiceSession = (options) => {
4297
4297
  let lastSttReconnectAt = 0;
4298
4298
  let lastSpeechEnergyAt = 0;
4299
4299
  let sttHealthPhaseStart = 0;
4300
+ let sttDeafConfirmedAt = 0;
4300
4301
  let lastSttRecoverySpokenAt = 0;
4301
4302
  let activeTTSTurnId;
4302
4303
  let assistantSpeechEndsAt = 0;
@@ -4431,30 +4432,21 @@ var createVoiceSession = (options) => {
4431
4432
  stuckCloseFired = true;
4432
4433
  const reason = `no caller progress for ${stuckCloseAfterMs}ms`;
4433
4434
  const { lastSpeechAt, lastTranscriptAt } = snapshot.currentTurn;
4434
- const speechWithoutTranscript = lastSpeechAt !== undefined && (lastTranscriptAt === undefined || lastSpeechAt > lastTranscriptAt);
4435
+ const sttDeafConfirmed = sttDeafConfirmedAt > 0 && (lastTranscriptAt === undefined || sttDeafConfirmedAt > lastTranscriptAt);
4435
4436
  const diagnostic = {
4436
4437
  action: "stuck-call-close",
4437
- classification: speechWithoutTranscript ? "stt-deaf" : "caller-idle",
4438
+ classification: sttDeafConfirmed ? "stt-deaf" : "caller-idle",
4438
4439
  lastAudioAt: snapshot.currentTurn.lastAudioAt,
4439
4440
  lastSpeechAt,
4440
4441
  lastTranscriptAt,
4441
4442
  reason,
4442
4443
  turnCount: snapshot.turns.length
4443
4444
  };
4444
- if (speechWithoutTranscript) {
4445
- const error = `caller speech received but STT produced no transcript for ${stuckCloseAfterMs}ms`;
4446
- await appendTrace({
4447
- payload: { ...diagnostic, error },
4448
- session: snapshot,
4449
- type: "session.error"
4450
- });
4451
- } else {
4452
- await appendTrace({
4453
- payload: diagnostic,
4454
- session: snapshot,
4455
- type: "call.lifecycle"
4456
- });
4457
- }
4445
+ await appendTrace({
4446
+ payload: diagnostic,
4447
+ session: snapshot,
4448
+ type: "call.lifecycle"
4449
+ });
4458
4450
  if (stuckCloseConfig?.line) {
4459
4451
  await speakResolvedLine(stuckCloseConfig.line, snapshot);
4460
4452
  }
@@ -5675,6 +5667,7 @@ var createVoiceSession = (options) => {
5675
5667
  };
5676
5668
  };
5677
5669
  const handlePartial = async (transcript) => {
5670
+ sttDeafConfirmedAt = 0;
5678
5671
  if (transcript.text.trim()) {
5679
5672
  kickStuckCloseWatchdog();
5680
5673
  kickIdleRepromptWatchdog(true);
@@ -5773,6 +5766,7 @@ var createVoiceSession = (options) => {
5773
5766
  };
5774
5767
  const handleFinal = async (transcript) => {
5775
5768
  sttReconnectCount = 0;
5769
+ sttDeafConfirmedAt = 0;
5776
5770
  if (backchannelBargeInGuard && backchannelSuppressedAt !== null && Date.now() - backchannelSuppressedAt < BACKCHANNEL_DROP_WINDOW_MS && isBackchannelUtterance(transcript.text.trim())) {
5777
5771
  backchannelSuppressedAt = null;
5778
5772
  return;
@@ -6987,6 +6981,7 @@ var createVoiceSession = (options) => {
6987
6981
  lastSpeechEnergyAt = nowMs;
6988
6982
  const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
6989
6983
  if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
6984
+ sttDeafConfirmedAt = nowMs;
6990
6985
  sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
6991
6986
  lastSttReconnectAt = nowMs;
6992
6987
  sttHealthPhaseStart = nowMs;
@@ -6996,6 +6991,7 @@ var createVoiceSession = (options) => {
6996
6991
  payload: {
6997
6992
  action: "stt-health-reconnect",
6998
6993
  attempt: sttReconnectCount,
6994
+ classification: "stt-deaf",
6999
6995
  reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
7000
6996
  },
7001
6997
  session: latest,
@@ -41824,16 +41820,21 @@ var oneAttempt = async (baseFetch, input, init) => {
41824
41820
  callerSignal?.removeEventListener("abort", onCallerAbort);
41825
41821
  }
41826
41822
  };
41827
- var hardenFetch = (baseFetch = globalThis.fetch) => Object.assign(async (input, init) => {
41828
- try {
41829
- return await oneAttempt(baseFetch, input, init);
41830
- } catch (error) {
41831
- if (init?.signal?.aborted)
41832
- throw error;
41833
- console.warn(`[voice] hardened fetch retrying on a fresh connection: ${error instanceof Error ? error.message : String(error)}`);
41834
- return oneAttempt(baseFetch, input, init);
41835
- }
41836
- }, { preconnect: baseFetch.preconnect.bind(baseFetch) });
41823
+ var hardenFetch = (baseFetch = globalThis.fetch) => {
41824
+ const hardenedFetch = async (input, init) => {
41825
+ try {
41826
+ return await oneAttempt(baseFetch, input, init);
41827
+ } catch (error) {
41828
+ if (init?.signal?.aborted)
41829
+ throw error;
41830
+ console.warn(`[voice] hardened fetch retrying on a fresh connection: ${error instanceof Error ? error.message : String(error)}`);
41831
+ return oneAttempt(baseFetch, input, init);
41832
+ }
41833
+ };
41834
+ return typeof baseFetch.preconnect === "function" ? Object.assign(hardenedFetch, {
41835
+ preconnect: baseFetch.preconnect.bind(baseFetch)
41836
+ }) : hardenedFetch;
41837
+ };
41837
41838
  // src/core/mcpToolset.ts
41838
41839
  var flattenContent = (result) => {
41839
41840
  const blocks = result.content ?? [];
@@ -4754,16 +4754,21 @@ var oneAttempt = async (baseFetch, input, init) => {
4754
4754
  callerSignal?.removeEventListener("abort", onCallerAbort);
4755
4755
  }
4756
4756
  };
4757
- var hardenFetch = (baseFetch = globalThis.fetch) => Object.assign(async (input, init) => {
4758
- try {
4759
- return await oneAttempt(baseFetch, input, init);
4760
- } catch (error) {
4761
- if (init?.signal?.aborted)
4762
- throw error;
4763
- console.warn(`[voice] hardened fetch retrying on a fresh connection: ${error instanceof Error ? error.message : String(error)}`);
4764
- return oneAttempt(baseFetch, input, init);
4765
- }
4766
- }, { preconnect: baseFetch.preconnect.bind(baseFetch) });
4757
+ var hardenFetch = (baseFetch = globalThis.fetch) => {
4758
+ const hardenedFetch = async (input, init) => {
4759
+ try {
4760
+ return await oneAttempt(baseFetch, input, init);
4761
+ } catch (error) {
4762
+ if (init?.signal?.aborted)
4763
+ throw error;
4764
+ console.warn(`[voice] hardened fetch retrying on a fresh connection: ${error instanceof Error ? error.message : String(error)}`);
4765
+ return oneAttempt(baseFetch, input, init);
4766
+ }
4767
+ };
4768
+ return typeof baseFetch.preconnect === "function" ? Object.assign(hardenedFetch, {
4769
+ preconnect: baseFetch.preconnect.bind(baseFetch)
4770
+ }) : hardenedFetch;
4771
+ };
4767
4772
 
4768
4773
  // src/core/modelAdapters.ts
4769
4774
  var normalizeVoiceUsage = (provider, model, raw) => {
@@ -6929,6 +6934,7 @@ var createVoiceSession = (options) => {
6929
6934
  let lastSttReconnectAt = 0;
6930
6935
  let lastSpeechEnergyAt = 0;
6931
6936
  let sttHealthPhaseStart = 0;
6937
+ let sttDeafConfirmedAt = 0;
6932
6938
  let lastSttRecoverySpokenAt = 0;
6933
6939
  let activeTTSTurnId;
6934
6940
  let assistantSpeechEndsAt = 0;
@@ -7063,30 +7069,21 @@ var createVoiceSession = (options) => {
7063
7069
  stuckCloseFired = true;
7064
7070
  const reason = `no caller progress for ${stuckCloseAfterMs}ms`;
7065
7071
  const { lastSpeechAt, lastTranscriptAt } = snapshot.currentTurn;
7066
- const speechWithoutTranscript = lastSpeechAt !== undefined && (lastTranscriptAt === undefined || lastSpeechAt > lastTranscriptAt);
7072
+ const sttDeafConfirmed = sttDeafConfirmedAt > 0 && (lastTranscriptAt === undefined || sttDeafConfirmedAt > lastTranscriptAt);
7067
7073
  const diagnostic = {
7068
7074
  action: "stuck-call-close",
7069
- classification: speechWithoutTranscript ? "stt-deaf" : "caller-idle",
7075
+ classification: sttDeafConfirmed ? "stt-deaf" : "caller-idle",
7070
7076
  lastAudioAt: snapshot.currentTurn.lastAudioAt,
7071
7077
  lastSpeechAt,
7072
7078
  lastTranscriptAt,
7073
7079
  reason,
7074
7080
  turnCount: snapshot.turns.length
7075
7081
  };
7076
- if (speechWithoutTranscript) {
7077
- const error = `caller speech received but STT produced no transcript for ${stuckCloseAfterMs}ms`;
7078
- await appendTrace({
7079
- payload: { ...diagnostic, error },
7080
- session: snapshot,
7081
- type: "session.error"
7082
- });
7083
- } else {
7084
- await appendTrace({
7085
- payload: diagnostic,
7086
- session: snapshot,
7087
- type: "call.lifecycle"
7088
- });
7089
- }
7082
+ await appendTrace({
7083
+ payload: diagnostic,
7084
+ session: snapshot,
7085
+ type: "call.lifecycle"
7086
+ });
7090
7087
  if (stuckCloseConfig?.line) {
7091
7088
  await speakResolvedLine(stuckCloseConfig.line, snapshot);
7092
7089
  }
@@ -8307,6 +8304,7 @@ var createVoiceSession = (options) => {
8307
8304
  };
8308
8305
  };
8309
8306
  const handlePartial = async (transcript) => {
8307
+ sttDeafConfirmedAt = 0;
8310
8308
  if (transcript.text.trim()) {
8311
8309
  kickStuckCloseWatchdog();
8312
8310
  kickIdleRepromptWatchdog(true);
@@ -8405,6 +8403,7 @@ var createVoiceSession = (options) => {
8405
8403
  };
8406
8404
  const handleFinal = async (transcript) => {
8407
8405
  sttReconnectCount = 0;
8406
+ sttDeafConfirmedAt = 0;
8408
8407
  if (backchannelBargeInGuard && backchannelSuppressedAt !== null && Date.now() - backchannelSuppressedAt < BACKCHANNEL_DROP_WINDOW_MS && isBackchannelUtterance(transcript.text.trim())) {
8409
8408
  backchannelSuppressedAt = null;
8410
8409
  return;
@@ -9619,6 +9618,7 @@ var createVoiceSession = (options) => {
9619
9618
  lastSpeechEnergyAt = nowMs;
9620
9619
  const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
9621
9620
  if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
9621
+ sttDeafConfirmedAt = nowMs;
9622
9622
  sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
9623
9623
  lastSttReconnectAt = nowMs;
9624
9624
  sttHealthPhaseStart = nowMs;
@@ -9628,6 +9628,7 @@ var createVoiceSession = (options) => {
9628
9628
  payload: {
9629
9629
  action: "stt-health-reconnect",
9630
9630
  attempt: sttReconnectCount,
9631
+ classification: "stt-deaf",
9631
9632
  reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
9632
9633
  },
9633
9634
  session: latest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.641",
3
+ "version": "0.0.22-beta.643",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -117,7 +117,7 @@
117
117
  "@absolutejs/absolute": ">=0.19.0-beta.646",
118
118
  "@absolutejs/ai": ">=0.0.5",
119
119
  "@angular/core": ">=21.0.0",
120
- "drizzle-orm": ">=1.0.0-rc.1",
120
+ "drizzle-orm": ">=1.0.0-rc.4 <2",
121
121
  "elysia": ">=1.4.18",
122
122
  "react": ">=19.0.0",
123
123
  "vue": ">=3.5.0"
@@ -154,7 +154,7 @@
154
154
  "@types/bun": "1.3.9",
155
155
  "@types/react": "19.2.0",
156
156
  "@typescript-eslint/parser": "^8.57.2",
157
- "drizzle-orm": "1.0.0-rc.3",
157
+ "drizzle-orm": "1.0.0-rc.4",
158
158
  "elysia": "1.4.18",
159
159
  "eslint": "^10.1.0",
160
160
  "eslint-plugin-absolute": "0.11.0-beta.3",