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

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/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,
@@ -328,7 +328,12 @@ var applyVoiceAudioCondition = (fixture, condition) => {
328
328
  for (let index = 0;index < output.length; index += 1)
329
329
  output[index] = clamp(output[index] + random() * Math.sqrt(3) * noiseRms);
330
330
  }
331
- return { ...fixture, audio: bytes(output), id: `${fixture.id}--${condition.id}`, tags: [...fixture.tags ?? [], "conditioned", condition.id] };
331
+ return {
332
+ ...fixture,
333
+ audio: bytes(output),
334
+ id: `${fixture.id}--${condition.id}`,
335
+ tags: [...fixture.tags ?? [], "conditioned", condition.id]
336
+ };
332
337
  };
333
338
  var buildVoiceAudioMatrix = (fixtures, conditions) => fixtures.flatMap((fixture) => conditions.map((condition) => applyVoiceAudioCondition(fixture, condition)));
334
339
  // src/testing/stt.ts
@@ -6005,9 +6010,15 @@ var stableBenchmarkJson = (value) => {
6005
6010
  };
6006
6011
  var buildVoiceBenchmarkArtifact = (manifest, report) => {
6007
6012
  const payload = { manifest, report };
6008
- return { ...payload, artifactSha256: sha256Bytes(stableBenchmarkJson(payload)) };
6013
+ return {
6014
+ ...payload,
6015
+ artifactSha256: sha256Bytes(stableBenchmarkJson(payload))
6016
+ };
6009
6017
  };
6010
- var verifyVoiceBenchmarkArtifact = (artifact) => artifact.artifactSha256 === sha256Bytes(stableBenchmarkJson({ manifest: artifact.manifest, report: artifact.report }));
6018
+ var verifyVoiceBenchmarkArtifact = (artifact) => artifact.artifactSha256 === sha256Bytes(stableBenchmarkJson({
6019
+ manifest: artifact.manifest,
6020
+ report: artifact.report
6021
+ }));
6011
6022
  // src/core/memoryStore.ts
6012
6023
  var createVoiceMemoryStore = () => {
6013
6024
  const sessions = new Map;
@@ -6929,6 +6940,7 @@ var createVoiceSession = (options) => {
6929
6940
  let lastSttReconnectAt = 0;
6930
6941
  let lastSpeechEnergyAt = 0;
6931
6942
  let sttHealthPhaseStart = 0;
6943
+ let sttDeafConfirmedAt = 0;
6932
6944
  let lastSttRecoverySpokenAt = 0;
6933
6945
  let activeTTSTurnId;
6934
6946
  let assistantSpeechEndsAt = 0;
@@ -7063,30 +7075,21 @@ var createVoiceSession = (options) => {
7063
7075
  stuckCloseFired = true;
7064
7076
  const reason = `no caller progress for ${stuckCloseAfterMs}ms`;
7065
7077
  const { lastSpeechAt, lastTranscriptAt } = snapshot.currentTurn;
7066
- const speechWithoutTranscript = lastSpeechAt !== undefined && (lastTranscriptAt === undefined || lastSpeechAt > lastTranscriptAt);
7078
+ const sttDeafConfirmed = sttDeafConfirmedAt > 0 && (lastTranscriptAt === undefined || sttDeafConfirmedAt > lastTranscriptAt);
7067
7079
  const diagnostic = {
7068
7080
  action: "stuck-call-close",
7069
- classification: speechWithoutTranscript ? "stt-deaf" : "caller-idle",
7081
+ classification: sttDeafConfirmed ? "stt-deaf" : "caller-idle",
7070
7082
  lastAudioAt: snapshot.currentTurn.lastAudioAt,
7071
7083
  lastSpeechAt,
7072
7084
  lastTranscriptAt,
7073
7085
  reason,
7074
7086
  turnCount: snapshot.turns.length
7075
7087
  };
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
- }
7088
+ await appendTrace({
7089
+ payload: diagnostic,
7090
+ session: snapshot,
7091
+ type: "call.lifecycle"
7092
+ });
7090
7093
  if (stuckCloseConfig?.line) {
7091
7094
  await speakResolvedLine(stuckCloseConfig.line, snapshot);
7092
7095
  }
@@ -8307,6 +8310,7 @@ var createVoiceSession = (options) => {
8307
8310
  };
8308
8311
  };
8309
8312
  const handlePartial = async (transcript) => {
8313
+ sttDeafConfirmedAt = 0;
8310
8314
  if (transcript.text.trim()) {
8311
8315
  kickStuckCloseWatchdog();
8312
8316
  kickIdleRepromptWatchdog(true);
@@ -8405,6 +8409,7 @@ var createVoiceSession = (options) => {
8405
8409
  };
8406
8410
  const handleFinal = async (transcript) => {
8407
8411
  sttReconnectCount = 0;
8412
+ sttDeafConfirmedAt = 0;
8408
8413
  if (backchannelBargeInGuard && backchannelSuppressedAt !== null && Date.now() - backchannelSuppressedAt < BACKCHANNEL_DROP_WINDOW_MS && isBackchannelUtterance(transcript.text.trim())) {
8409
8414
  backchannelSuppressedAt = null;
8410
8415
  return;
@@ -9619,6 +9624,7 @@ var createVoiceSession = (options) => {
9619
9624
  lastSpeechEnergyAt = nowMs;
9620
9625
  const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
9621
9626
  if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
9627
+ sttDeafConfirmedAt = nowMs;
9622
9628
  sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
9623
9629
  lastSttReconnectAt = nowMs;
9624
9630
  sttHealthPhaseStart = nowMs;
@@ -9628,6 +9634,7 @@ var createVoiceSession = (options) => {
9628
9634
  payload: {
9629
9635
  action: "stt-health-reconnect",
9630
9636
  attempt: sttReconnectCount,
9637
+ classification: "stt-deaf",
9631
9638
  reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
9632
9639
  },
9633
9640
  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.642",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",