@absolutejs/voice 0.0.22-beta.639 → 0.0.22-beta.640

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
@@ -4407,6 +4407,7 @@ var createVoiceSession = (options) => {
4407
4407
  const stuckCloseAfterMs = stuckCloseConfig && stuckCloseConfig.afterMs > 0 ? stuckCloseConfig.afterMs : undefined;
4408
4408
  let stuckCloseWatchdog = null;
4409
4409
  let stuckCloseFired = false;
4410
+ let assistantTurnInProgress = false;
4410
4411
  const clearStuckCloseWatchdog = () => {
4411
4412
  if (stuckCloseWatchdog) {
4412
4413
  clearTimeout(stuckCloseWatchdog);
@@ -4418,22 +4419,42 @@ var createVoiceSession = (options) => {
4418
4419
  if (stuckCloseFired) {
4419
4420
  return;
4420
4421
  }
4421
- stuckCloseFired = true;
4422
+ if (assistantTurnInProgress) {
4423
+ stuckCloseWatchdog = setTimeout(fireStuckClose, stuckCloseAfterMs);
4424
+ return;
4425
+ }
4422
4426
  runSerial("stuck-call-close", async () => {
4423
4427
  const snapshot = await readSession();
4424
4428
  if (snapshot.status === "completed" || snapshot.status === "failed" || snapshot.call?.endedAt) {
4425
4429
  return;
4426
4430
  }
4427
- const error = `no caller progress for ${stuckCloseAfterMs}ms`;
4428
- await appendTrace({
4429
- payload: {
4430
- action: "stuck-call-close",
4431
- error,
4432
- reason: error
4433
- },
4434
- session: snapshot,
4435
- type: "session.error"
4436
- });
4431
+ stuckCloseFired = true;
4432
+ const reason = `no caller progress for ${stuckCloseAfterMs}ms`;
4433
+ const { lastSpeechAt, lastTranscriptAt } = snapshot.currentTurn;
4434
+ const speechWithoutTranscript = lastSpeechAt !== undefined && (lastTranscriptAt === undefined || lastSpeechAt > lastTranscriptAt);
4435
+ const diagnostic = {
4436
+ action: "stuck-call-close",
4437
+ classification: speechWithoutTranscript ? "stt-deaf" : "caller-idle",
4438
+ lastAudioAt: snapshot.currentTurn.lastAudioAt,
4439
+ lastSpeechAt,
4440
+ lastTranscriptAt,
4441
+ reason,
4442
+ turnCount: snapshot.turns.length
4443
+ };
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
+ }
4437
4458
  if (stuckCloseConfig?.line) {
4438
4459
  await speakResolvedLine(stuckCloseConfig.line, snapshot);
4439
4460
  }
@@ -6128,12 +6149,12 @@ var createVoiceSession = (options) => {
6128
6149
  }
6129
6150
  };
6130
6151
  };
6131
- const completeTurn = async (session, turn) => {
6152
+ const completeTurnInternal = async (session, turn) => {
6132
6153
  console.error(`[voice] completeTurn ENTER session=${options.id} turn=${turn.id} textLen=${turn.text?.length ?? 0}`);
6133
6154
  if (options.normalizeNumbers && turn.text) {
6134
6155
  turn.text = normalizeSpokenNumbers(turn.text);
6135
6156
  }
6136
- kickStuckCloseWatchdog();
6157
+ clearStuckCloseWatchdog();
6137
6158
  kickIdleRepromptWatchdog(true);
6138
6159
  if (callerPaused) {
6139
6160
  await appendTrace({
@@ -6549,6 +6570,19 @@ var createVoiceSession = (options) => {
6549
6570
  await completeInternal(output.result);
6550
6571
  }
6551
6572
  };
6573
+ const completeTurn = async (session, turn) => {
6574
+ assistantTurnInProgress = true;
6575
+ clearStuckCloseWatchdog();
6576
+ try {
6577
+ await completeTurnInternal(session, turn);
6578
+ } finally {
6579
+ assistantTurnInProgress = false;
6580
+ const latest = await readSession();
6581
+ if (latest.status !== "completed" && latest.status !== "failed" && !latest.call?.endedAt) {
6582
+ kickStuckCloseWatchdog();
6583
+ }
6584
+ }
6585
+ };
6552
6586
  const commitTurnInternal = async (reason = "manual") => {
6553
6587
  clearSilenceTimer();
6554
6588
  lastTurnCompleteConfidence = null;
@@ -7039,6 +7039,7 @@ var createVoiceSession = (options) => {
7039
7039
  const stuckCloseAfterMs = stuckCloseConfig && stuckCloseConfig.afterMs > 0 ? stuckCloseConfig.afterMs : undefined;
7040
7040
  let stuckCloseWatchdog = null;
7041
7041
  let stuckCloseFired = false;
7042
+ let assistantTurnInProgress = false;
7042
7043
  const clearStuckCloseWatchdog = () => {
7043
7044
  if (stuckCloseWatchdog) {
7044
7045
  clearTimeout(stuckCloseWatchdog);
@@ -7050,22 +7051,42 @@ var createVoiceSession = (options) => {
7050
7051
  if (stuckCloseFired) {
7051
7052
  return;
7052
7053
  }
7053
- stuckCloseFired = true;
7054
+ if (assistantTurnInProgress) {
7055
+ stuckCloseWatchdog = setTimeout(fireStuckClose, stuckCloseAfterMs);
7056
+ return;
7057
+ }
7054
7058
  runSerial("stuck-call-close", async () => {
7055
7059
  const snapshot = await readSession();
7056
7060
  if (snapshot.status === "completed" || snapshot.status === "failed" || snapshot.call?.endedAt) {
7057
7061
  return;
7058
7062
  }
7059
- const error = `no caller progress for ${stuckCloseAfterMs}ms`;
7060
- await appendTrace({
7061
- payload: {
7062
- action: "stuck-call-close",
7063
- error,
7064
- reason: error
7065
- },
7066
- session: snapshot,
7067
- type: "session.error"
7068
- });
7063
+ stuckCloseFired = true;
7064
+ const reason = `no caller progress for ${stuckCloseAfterMs}ms`;
7065
+ const { lastSpeechAt, lastTranscriptAt } = snapshot.currentTurn;
7066
+ const speechWithoutTranscript = lastSpeechAt !== undefined && (lastTranscriptAt === undefined || lastSpeechAt > lastTranscriptAt);
7067
+ const diagnostic = {
7068
+ action: "stuck-call-close",
7069
+ classification: speechWithoutTranscript ? "stt-deaf" : "caller-idle",
7070
+ lastAudioAt: snapshot.currentTurn.lastAudioAt,
7071
+ lastSpeechAt,
7072
+ lastTranscriptAt,
7073
+ reason,
7074
+ turnCount: snapshot.turns.length
7075
+ };
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
+ }
7069
7090
  if (stuckCloseConfig?.line) {
7070
7091
  await speakResolvedLine(stuckCloseConfig.line, snapshot);
7071
7092
  }
@@ -8760,12 +8781,12 @@ var createVoiceSession = (options) => {
8760
8781
  }
8761
8782
  };
8762
8783
  };
8763
- const completeTurn = async (session, turn) => {
8784
+ const completeTurnInternal = async (session, turn) => {
8764
8785
  console.error(`[voice] completeTurn ENTER session=${options.id} turn=${turn.id} textLen=${turn.text?.length ?? 0}`);
8765
8786
  if (options.normalizeNumbers && turn.text) {
8766
8787
  turn.text = normalizeSpokenNumbers(turn.text);
8767
8788
  }
8768
- kickStuckCloseWatchdog();
8789
+ clearStuckCloseWatchdog();
8769
8790
  kickIdleRepromptWatchdog(true);
8770
8791
  if (callerPaused) {
8771
8792
  await appendTrace({
@@ -9181,6 +9202,19 @@ var createVoiceSession = (options) => {
9181
9202
  await completeInternal(output.result);
9182
9203
  }
9183
9204
  };
9205
+ const completeTurn = async (session, turn) => {
9206
+ assistantTurnInProgress = true;
9207
+ clearStuckCloseWatchdog();
9208
+ try {
9209
+ await completeTurnInternal(session, turn);
9210
+ } finally {
9211
+ assistantTurnInProgress = false;
9212
+ const latest = await readSession();
9213
+ if (latest.status !== "completed" && latest.status !== "failed" && !latest.call?.endedAt) {
9214
+ kickStuckCloseWatchdog();
9215
+ }
9216
+ }
9217
+ };
9184
9218
  const commitTurnInternal = async (reason = "manual") => {
9185
9219
  clearSilenceTimer();
9186
9220
  lastTurnCompleteConfidence = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.639",
3
+ "version": "0.0.22-beta.640",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",