@absolutejs/voice 0.0.22-beta.558 → 0.0.22-beta.559

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.
@@ -923,6 +923,14 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
923
923
  * Set to "" to opt out entirely.
924
924
  */
925
925
  defaultSilentTurnAck?: string;
926
+ /**
927
+ * Hard timeout on a single `route.onTurn` call. If onTurn hasn't resolved
928
+ * in this many ms, it's rejected with a hard-timeout error which falls
929
+ * through to defaultSilentTurnAck. Default 45s — generous for normal
930
+ * conversational LLM calls (1-3s typical), but catches hangs where the
931
+ * model adapter's own timeout doesn't fire. Set to 0 to disable.
932
+ */
933
+ routeOnTurnTimeoutMs?: number;
926
934
  assistantMode?: import("./assistantMode").VoiceAssistantMode;
927
935
  modalities?: ReadonlyArray<"audio" | "text">;
928
936
  prosody?: VoiceTTSProsody;
package/dist/index.js CHANGED
@@ -5324,10 +5324,11 @@ var createVoiceSession = (options) => {
5324
5324
  });
5325
5325
  }, fillerDelayMs);
5326
5326
  }
5327
+ const onTurnTimeoutMs = options.routeOnTurnTimeoutMs ?? 45000;
5327
5328
  let committedOutput;
5328
5329
  const onTurnStartedAt = Date.now();
5329
5330
  try {
5330
- committedOutput = await options.route.onTurn({
5331
+ const onTurnPromise = options.route.onTurn({
5331
5332
  api,
5332
5333
  context: options.context,
5333
5334
  liveOps: liveOpsControl ? {
@@ -5338,6 +5339,25 @@ var createVoiceSession = (options) => {
5338
5339
  session,
5339
5340
  turn
5340
5341
  });
5342
+ if (onTurnTimeoutMs > 0) {
5343
+ let timer = null;
5344
+ const timeoutPromise = new Promise((_resolve, reject) => {
5345
+ timer = setTimeout(() => {
5346
+ reject(new Error(`route.onTurn hard-timeout after ${onTurnTimeoutMs}ms`));
5347
+ }, onTurnTimeoutMs);
5348
+ });
5349
+ try {
5350
+ committedOutput = await Promise.race([
5351
+ onTurnPromise,
5352
+ timeoutPromise
5353
+ ]);
5354
+ } finally {
5355
+ if (timer)
5356
+ clearTimeout(timer);
5357
+ }
5358
+ } else {
5359
+ committedOutput = await onTurnPromise;
5360
+ }
5341
5361
  } catch (error) {
5342
5362
  const message = toError(error).message;
5343
5363
  logger.warn("voice route.onTurn failed", {
@@ -7161,10 +7161,11 @@ var createVoiceSession = (options) => {
7161
7161
  });
7162
7162
  }, fillerDelayMs);
7163
7163
  }
7164
+ const onTurnTimeoutMs = options.routeOnTurnTimeoutMs ?? 45000;
7164
7165
  let committedOutput;
7165
7166
  const onTurnStartedAt = Date.now();
7166
7167
  try {
7167
- committedOutput = await options.route.onTurn({
7168
+ const onTurnPromise = options.route.onTurn({
7168
7169
  api,
7169
7170
  context: options.context,
7170
7171
  liveOps: liveOpsControl ? {
@@ -7175,6 +7176,25 @@ var createVoiceSession = (options) => {
7175
7176
  session,
7176
7177
  turn
7177
7178
  });
7179
+ if (onTurnTimeoutMs > 0) {
7180
+ let timer = null;
7181
+ const timeoutPromise = new Promise((_resolve, reject) => {
7182
+ timer = setTimeout(() => {
7183
+ reject(new Error(`route.onTurn hard-timeout after ${onTurnTimeoutMs}ms`));
7184
+ }, onTurnTimeoutMs);
7185
+ });
7186
+ try {
7187
+ committedOutput = await Promise.race([
7188
+ onTurnPromise,
7189
+ timeoutPromise
7190
+ ]);
7191
+ } finally {
7192
+ if (timer)
7193
+ clearTimeout(timer);
7194
+ }
7195
+ } else {
7196
+ committedOutput = await onTurnPromise;
7197
+ }
7178
7198
  } catch (error) {
7179
7199
  const message = toError(error).message;
7180
7200
  logger.warn("voice route.onTurn failed", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.558",
3
+ "version": "0.0.22-beta.559",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",