@absolutejs/voice 0.0.22-beta.640 → 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
  }
@@ -5030,7 +5022,7 @@ var createVoiceSession = (options) => {
5030
5022
  }
5031
5023
  await commitTurnInternal(reason);
5032
5024
  };
5033
- const failInternal = async (error) => {
5025
+ const failInternal = async (error, code) => {
5034
5026
  clearSilenceTimer();
5035
5027
  let didFail = false;
5036
5028
  const session = await writeSession((currentSession) => {
@@ -5054,6 +5046,7 @@ var createVoiceSession = (options) => {
5054
5046
  const resolvedError = toError(error);
5055
5047
  await appendTrace({
5056
5048
  payload: {
5049
+ ...code === undefined ? {} : { code },
5057
5050
  error: resolvedError.message,
5058
5051
  recoverable: false
5059
5052
  },
@@ -5369,6 +5362,10 @@ var createVoiceSession = (options) => {
5369
5362
  });
5370
5363
  };
5371
5364
  const handleError = async (event) => {
5365
+ if (!event.recoverable) {
5366
+ await failInternal(event.error, event.code);
5367
+ return;
5368
+ }
5372
5369
  await appendTrace({
5373
5370
  payload: {
5374
5371
  code: event.code,
@@ -5382,9 +5379,6 @@ var createVoiceSession = (options) => {
5382
5379
  recoverable: event.recoverable,
5383
5380
  type: "error"
5384
5381
  });
5385
- if (!event.recoverable) {
5386
- await failInternal(event.error);
5387
- }
5388
5382
  };
5389
5383
  const handleClose = async (event) => {
5390
5384
  const session = await readSession();
@@ -5673,6 +5667,7 @@ var createVoiceSession = (options) => {
5673
5667
  };
5674
5668
  };
5675
5669
  const handlePartial = async (transcript) => {
5670
+ sttDeafConfirmedAt = 0;
5676
5671
  if (transcript.text.trim()) {
5677
5672
  kickStuckCloseWatchdog();
5678
5673
  kickIdleRepromptWatchdog(true);
@@ -5771,6 +5766,7 @@ var createVoiceSession = (options) => {
5771
5766
  };
5772
5767
  const handleFinal = async (transcript) => {
5773
5768
  sttReconnectCount = 0;
5769
+ sttDeafConfirmedAt = 0;
5774
5770
  if (backchannelBargeInGuard && backchannelSuppressedAt !== null && Date.now() - backchannelSuppressedAt < BACKCHANNEL_DROP_WINDOW_MS && isBackchannelUtterance(transcript.text.trim())) {
5775
5771
  backchannelSuppressedAt = null;
5776
5772
  return;
@@ -6985,6 +6981,7 @@ var createVoiceSession = (options) => {
6985
6981
  lastSpeechEnergyAt = nowMs;
6986
6982
  const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
6987
6983
  if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
6984
+ sttDeafConfirmedAt = nowMs;
6988
6985
  sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
6989
6986
  lastSttReconnectAt = nowMs;
6990
6987
  sttHealthPhaseStart = nowMs;
@@ -6994,6 +6991,7 @@ var createVoiceSession = (options) => {
6994
6991
  payload: {
6995
6992
  action: "stt-health-reconnect",
6996
6993
  attempt: sttReconnectCount,
6994
+ classification: "stt-deaf",
6997
6995
  reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
6998
6996
  },
6999
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
  }
@@ -7662,7 +7665,7 @@ var createVoiceSession = (options) => {
7662
7665
  }
7663
7666
  await commitTurnInternal(reason);
7664
7667
  };
7665
- const failInternal = async (error) => {
7668
+ const failInternal = async (error, code) => {
7666
7669
  clearSilenceTimer();
7667
7670
  let didFail = false;
7668
7671
  const session = await writeSession((currentSession) => {
@@ -7686,6 +7689,7 @@ var createVoiceSession = (options) => {
7686
7689
  const resolvedError = toError(error);
7687
7690
  await appendTrace({
7688
7691
  payload: {
7692
+ ...code === undefined ? {} : { code },
7689
7693
  error: resolvedError.message,
7690
7694
  recoverable: false
7691
7695
  },
@@ -8001,6 +8005,10 @@ var createVoiceSession = (options) => {
8001
8005
  });
8002
8006
  };
8003
8007
  const handleError = async (event) => {
8008
+ if (!event.recoverable) {
8009
+ await failInternal(event.error, event.code);
8010
+ return;
8011
+ }
8004
8012
  await appendTrace({
8005
8013
  payload: {
8006
8014
  code: event.code,
@@ -8014,9 +8022,6 @@ var createVoiceSession = (options) => {
8014
8022
  recoverable: event.recoverable,
8015
8023
  type: "error"
8016
8024
  });
8017
- if (!event.recoverable) {
8018
- await failInternal(event.error);
8019
- }
8020
8025
  };
8021
8026
  const handleClose = async (event) => {
8022
8027
  const session = await readSession();
@@ -8305,6 +8310,7 @@ var createVoiceSession = (options) => {
8305
8310
  };
8306
8311
  };
8307
8312
  const handlePartial = async (transcript) => {
8313
+ sttDeafConfirmedAt = 0;
8308
8314
  if (transcript.text.trim()) {
8309
8315
  kickStuckCloseWatchdog();
8310
8316
  kickIdleRepromptWatchdog(true);
@@ -8403,6 +8409,7 @@ var createVoiceSession = (options) => {
8403
8409
  };
8404
8410
  const handleFinal = async (transcript) => {
8405
8411
  sttReconnectCount = 0;
8412
+ sttDeafConfirmedAt = 0;
8406
8413
  if (backchannelBargeInGuard && backchannelSuppressedAt !== null && Date.now() - backchannelSuppressedAt < BACKCHANNEL_DROP_WINDOW_MS && isBackchannelUtterance(transcript.text.trim())) {
8407
8414
  backchannelSuppressedAt = null;
8408
8415
  return;
@@ -9617,6 +9624,7 @@ var createVoiceSession = (options) => {
9617
9624
  lastSpeechEnergyAt = nowMs;
9618
9625
  const lastTranscriptAt = latest.currentTurn.lastTranscriptAt ?? 0;
9619
9626
  if (!options.realtime && sttSession && lastTranscriptAt < sttHealthPhaseStart && nowMs - sttHealthPhaseStart >= STT_HEALTH_STALE_MS) {
9627
+ sttDeafConfirmedAt = nowMs;
9620
9628
  sttReconnectCount = nowMs - lastSttReconnectAt < STT_RECONNECT_FLAP_WINDOW_MS ? sttReconnectCount + 1 : 1;
9621
9629
  lastSttReconnectAt = nowMs;
9622
9630
  sttHealthPhaseStart = nowMs;
@@ -9626,6 +9634,7 @@ var createVoiceSession = (options) => {
9626
9634
  payload: {
9627
9635
  action: "stt-health-reconnect",
9628
9636
  attempt: sttReconnectCount,
9637
+ classification: "stt-deaf",
9629
9638
  reason: `no transcript for ${STT_HEALTH_STALE_MS}ms of continuous speech`
9630
9639
  },
9631
9640
  session: latest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.640",
3
+ "version": "0.0.22-beta.642",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",