@absolutejs/voice 0.0.22-beta.624 → 0.0.22-beta.626

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.
@@ -0,0 +1 @@
1
+ export declare const normalizeSpokenNumbers: (input: string) => string;
@@ -861,6 +861,7 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
861
861
  defaultSilentTurnAck?: string;
862
862
  routeOnTurnTimeoutMs?: number;
863
863
  audioConditioning?: VoiceAudioConditioningConfig;
864
+ normalizeNumbers?: boolean;
864
865
  noiseSuppressor?: VoiceNoiseSuppressor;
865
866
  noiseSuppressorFormat?: AudioFormat;
866
867
  logger?: VoiceLogger;
@@ -1131,6 +1132,7 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
1131
1132
  sttLifecycle: VoiceSTTLifecycle;
1132
1133
  turnDetection: VoiceResolvedTurnDetectionConfig;
1133
1134
  audioConditioning?: VoiceResolvedAudioConditioningConfig;
1135
+ normalizeNumbers?: boolean;
1134
1136
  noiseSuppressor?: VoiceNoiseSuppressor;
1135
1137
  noiseSuppressorFormat?: AudioFormat;
1136
1138
  handoff?: VoiceHandoffConfig<TContext, TSession, TResult>;
package/dist/index.d.ts CHANGED
@@ -77,6 +77,7 @@ export { createVoiceMCPToolset } from "./core/mcpToolset";
77
77
  export type { CreateVoiceMCPToolsetOptions, MCPClientLike, MCPToolCallResult, MCPToolContentBlock, MCPToolDefinition, VoiceMCPToolResult, } from "./core/mcpToolset";
78
78
  export { createAIVoiceModel } from "./core/aiVoiceModel";
79
79
  export type { CreateAIVoiceModelOptions } from "./core/aiVoiceModel";
80
+ export { normalizeSpokenNumbers } from "./core/numberNormalizer";
80
81
  export { createVoiceAIJudgeCompletion, createVoiceLLMJudge, } from "./core/llmJudge";
81
82
  export type { CreateVoiceAIJudgeCompletionOptions, CreateVoiceLLMJudgeOptions, VoiceLLMJudge, VoiceLLMJudgeCompletion, VoiceLLMJudgeCriterionVerdict, VoiceLLMJudgeInput, VoiceLLMJudgeRubric, VoiceLLMJudgeRubricCriterion, VoiceLLMJudgeVerdict, } from "./core/llmJudge";
82
83
  export { DEFAULT_VOICE_REDACTION_PATTERNS, createVoiceTranscriptRedactor, redactVoiceTranscript, } from "./core/redaction";
package/dist/index.js CHANGED
@@ -3096,6 +3096,191 @@ var toVoiceSessionSummary = (session) => ({
3096
3096
  // src/core/session.ts
3097
3097
  import { Buffer as Buffer2 } from "buffer";
3098
3098
 
3099
+ // src/core/numberNormalizer.ts
3100
+ var ONES = {
3101
+ eight: 8,
3102
+ eighteen: 18,
3103
+ eleven: 11,
3104
+ fifteen: 15,
3105
+ five: 5,
3106
+ four: 4,
3107
+ fourteen: 14,
3108
+ nine: 9,
3109
+ nineteen: 19,
3110
+ one: 1,
3111
+ seven: 7,
3112
+ seventeen: 17,
3113
+ six: 6,
3114
+ sixteen: 16,
3115
+ ten: 10,
3116
+ thirteen: 13,
3117
+ three: 3,
3118
+ twelve: 12,
3119
+ two: 2,
3120
+ zero: 0
3121
+ };
3122
+ var TENS = {
3123
+ eighty: 80,
3124
+ fifty: 50,
3125
+ forty: 40,
3126
+ ninety: 90,
3127
+ seventy: 70,
3128
+ sixty: 60,
3129
+ thirty: 30,
3130
+ twenty: 20
3131
+ };
3132
+ var SCALES = {
3133
+ billion: 1e9,
3134
+ million: 1e6,
3135
+ thousand: 1000,
3136
+ trillion: 1000000000000
3137
+ };
3138
+ var MAGNITUDE_WORDS = [
3139
+ [1000000000000, "trillion"],
3140
+ [1e9, "billion"],
3141
+ [1e6, "million"]
3142
+ ];
3143
+ var FILLER = new Set(["and", "a", "an"]);
3144
+ var DECIMAL_PLACES = 3;
3145
+ var isValueWord = (word) => (word in ONES) || (word in TENS) || word === "hundred";
3146
+ var isScaleWord = (word) => (word in SCALES);
3147
+ var isNumberWord = (word) => isValueWord(word) || isScaleWord(word) || word === "point" || FILLER.has(word);
3148
+ var trimNumber = (value) => {
3149
+ if (Number.isInteger(value))
3150
+ return value.toLocaleString("en-US");
3151
+ return String(Number(value.toFixed(DECIMAL_PLACES)));
3152
+ };
3153
+ var renderValue = (value, usedMagnitude) => {
3154
+ if (usedMagnitude) {
3155
+ for (const [scale, word] of MAGNITUDE_WORDS) {
3156
+ if (value >= scale) {
3157
+ const scaled = value / scale;
3158
+ if (Number(scaled.toFixed(DECIMAL_PLACES)) === scaled) {
3159
+ return `${trimNumber(scaled)} ${word}`;
3160
+ }
3161
+ }
3162
+ }
3163
+ }
3164
+ return trimNumber(value);
3165
+ };
3166
+ var parseNumberWords = (words) => {
3167
+ let total = 0;
3168
+ let current = 0;
3169
+ let usedMagnitude = false;
3170
+ let sawNumber = false;
3171
+ let decimal = null;
3172
+ const foldDecimal = () => {
3173
+ if (decimal && decimal.length > 0)
3174
+ current += Number(`0.${decimal}`);
3175
+ decimal = null;
3176
+ };
3177
+ for (const word of words) {
3178
+ if (word === "point") {
3179
+ decimal = "";
3180
+ continue;
3181
+ }
3182
+ const one = ONES[word];
3183
+ const ten = TENS[word];
3184
+ const scale = SCALES[word];
3185
+ if (decimal !== null) {
3186
+ if (one !== undefined && one <= 9) {
3187
+ decimal += String(one);
3188
+ sawNumber = true;
3189
+ continue;
3190
+ }
3191
+ foldDecimal();
3192
+ }
3193
+ if (FILLER.has(word))
3194
+ continue;
3195
+ if (one !== undefined) {
3196
+ current += one;
3197
+ sawNumber = true;
3198
+ } else if (ten !== undefined) {
3199
+ current += ten;
3200
+ sawNumber = true;
3201
+ } else if (word === "hundred") {
3202
+ current = (current === 0 ? 1 : current) * 100;
3203
+ sawNumber = true;
3204
+ } else if (scale !== undefined) {
3205
+ total += (current === 0 ? 1 : current) * scale;
3206
+ current = 0;
3207
+ sawNumber = true;
3208
+ usedMagnitude = true;
3209
+ }
3210
+ }
3211
+ foldDecimal();
3212
+ if (!sawNumber)
3213
+ return null;
3214
+ return { usedMagnitude, value: total + current };
3215
+ };
3216
+ var PERCENT_RE = /^(per ?cent|percent|percentage)$/;
3217
+ var CURRENCY_RE = /^(dollars?|bucks?|usd)$/;
3218
+ var WORD_RE = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
3219
+ var wordsOf = (token) => token.toLowerCase().split("-");
3220
+ var isNumberToken = (token) => WORD_RE.test(token) && wordsOf(token).every(isNumberWord);
3221
+ var startsNumber = (token) => WORD_RE.test(token) && wordsOf(token).some(isValueWord);
3222
+ var isSpace = (token) => /^\s+$/.test(token);
3223
+ var normalizeSpokenNumbers = (input) => {
3224
+ if (!input)
3225
+ return input;
3226
+ const parts = input.match(/[A-Za-z]+(?:-[A-Za-z]+)*|[^A-Za-z]+/g);
3227
+ if (!parts)
3228
+ return input;
3229
+ const at = (idx) => parts[idx] ?? "";
3230
+ const out = [];
3231
+ let i = 0;
3232
+ while (i < parts.length) {
3233
+ const token = at(i);
3234
+ const lower = token.toLowerCase();
3235
+ if (lower === "a" || lower === "an") {
3236
+ const nextWord = at(i + 2);
3237
+ const nextHead = wordsOf(nextWord)[0] ?? "";
3238
+ const nextIsScale = isSpace(at(i + 1)) && WORD_RE.test(nextWord) && (nextHead === "hundred" || isScaleWord(nextHead));
3239
+ if (!nextIsScale) {
3240
+ out.push(token);
3241
+ i += 1;
3242
+ continue;
3243
+ }
3244
+ } else if (!startsNumber(token)) {
3245
+ out.push(token);
3246
+ i += 1;
3247
+ continue;
3248
+ }
3249
+ const spanIdx = [i];
3250
+ let j = i + 1;
3251
+ while (isSpace(at(j)) && isNumberToken(at(j + 1))) {
3252
+ spanIdx.push(j + 1);
3253
+ j += 2;
3254
+ }
3255
+ const words = spanIdx.flatMap((k) => wordsOf(at(k)));
3256
+ while (words.length > 0 && FILLER.has(words[words.length - 1] ?? "")) {
3257
+ words.pop();
3258
+ }
3259
+ const parsed = parseNumberWords(words);
3260
+ if (!parsed) {
3261
+ out.push(token);
3262
+ i += 1;
3263
+ continue;
3264
+ }
3265
+ let rendered = renderValue(parsed.value, parsed.usedMagnitude);
3266
+ let lastIdx = spanIdx[spanIdx.length - 1] ?? i;
3267
+ const unitWord = at(lastIdx + 2);
3268
+ if (isSpace(at(lastIdx + 1)) && WORD_RE.test(unitWord)) {
3269
+ const unit = unitWord.toLowerCase();
3270
+ if (PERCENT_RE.test(unit)) {
3271
+ rendered = `${rendered}%`;
3272
+ lastIdx += 2;
3273
+ } else if (CURRENCY_RE.test(unit)) {
3274
+ rendered = rendered.startsWith("$") ? rendered : `$${rendered}`;
3275
+ lastIdx += 2;
3276
+ }
3277
+ }
3278
+ out.push(rendered);
3279
+ i = lastIdx + 1;
3280
+ }
3281
+ return out.join("");
3282
+ };
3283
+
3099
3284
  // src/core/debugTiming.ts
3100
3285
  var timingEnabled = () => process.env.ABSOLUTEJS_VOICE_TIMING === "1" || process.env.ABSOLUTEJS_VOICE_TIMING === "true";
3101
3286
  var emitTiming = (sessionId, stage, elapsedMs, detail) => {
@@ -5834,6 +6019,9 @@ var createVoiceSession = (options) => {
5834
6019
  };
5835
6020
  const completeTurn = async (session, turn) => {
5836
6021
  console.error(`[voice] completeTurn ENTER session=${options.id} turn=${turn.id} textLen=${turn.text?.length ?? 0}`);
6022
+ if (options.normalizeNumbers && turn.text) {
6023
+ turn.text = normalizeSpokenNumbers(turn.text);
6024
+ }
5837
6025
  kickStuckCloseWatchdog();
5838
6026
  kickIdleRepromptWatchdog(true);
5839
6027
  const liveOpsControl = await options.liveOps?.getControl(options.id);
@@ -25468,6 +25656,7 @@ var createTwilioMediaStreamBridge = (socket, options) => {
25468
25656
  const voiceSocket = createTwilioSocketAdapter(socket, () => bridgeState);
25469
25657
  sessionHandle = createVoiceSession({
25470
25658
  audioConditioning,
25659
+ normalizeNumbers: options.normalizeNumbers,
25471
25660
  context: options.context,
25472
25661
  costAccountant: options.costAccountant,
25473
25662
  costTelemetry: options.costTelemetry,
@@ -25487,6 +25676,9 @@ var createTwilioMediaStreamBridge = (socket, options) => {
25487
25676
  stt: options.stt,
25488
25677
  sttFallback: resolveSTTFallbackConfig(options.sttFallback),
25489
25678
  sttLifecycle: options.sttLifecycle ?? runtimePreset.sttLifecycle,
25679
+ sttRecoveryLine: options.sttRecoveryLine,
25680
+ stuckCallClose: options.stuckCallClose,
25681
+ idleReprompt: options.idleReprompt,
25490
25682
  ...options.semanticTurnDetector ? { semanticTurnDetector: options.semanticTurnDetector } : {},
25491
25683
  ...options.bargeInDetector ? { bargeInDetector: options.bargeInDetector } : {},
25492
25684
  ...options.fillerPhrases ? { fillerPhrases: options.fillerPhrases } : {},
@@ -39583,6 +39775,7 @@ var resolveSessionOptions = (config) => {
39583
39775
  const preset = resolveVoiceRuntimePreset(config.preset);
39584
39776
  return {
39585
39777
  audioConditioning: config.audioConditioning !== undefined ? resolveAudioConditioningConfig(config.audioConditioning) : preset.audioConditioning,
39778
+ normalizeNumbers: config.normalizeNumbers,
39586
39779
  noiseSuppressor: config.noiseSuppressor,
39587
39780
  noiseSuppressorFormat: config.noiseSuppressorFormat,
39588
39781
  costTelemetry: config.costTelemetry,
@@ -39796,6 +39989,7 @@ var voice = (config) => {
39796
39989
  });
39797
39990
  return createVoiceSession({
39798
39991
  audioConditioning: sessionOptions.audioConditioning,
39992
+ normalizeNumbers: sessionOptions.normalizeNumbers,
39799
39993
  noiseSuppressor: sessionOptions.noiseSuppressor,
39800
39994
  noiseSuppressorFormat: sessionOptions.noiseSuppressorFormat,
39801
39995
  context,
@@ -39804,6 +39998,7 @@ var voice = (config) => {
39804
39998
  resumeGreeting: config.resumeGreeting,
39805
39999
  sttRecoveryLine: config.sttRecoveryLine,
39806
40000
  stuckCallClose: config.stuckCallClose,
40001
+ idleReprompt: config.idleReprompt,
39807
40002
  handoff: config.handoff,
39808
40003
  languageStrategy: config.languageStrategy,
39809
40004
  lexicon,
@@ -50969,7 +51164,7 @@ var DEFAULT_VOICE_CAMPAIGN_TEMPLATE_FILTERS = {
50969
51164
  ssml: (value) => escapeSpeech(String(value ?? "")),
50970
51165
  upper: (value) => String(value ?? "").toUpperCase()
50971
51166
  };
50972
- var renderValue = (value, filters, filterChain) => {
51167
+ var renderValue2 = (value, filters, filterChain) => {
50973
51168
  let cursor = value;
50974
51169
  for (const segment of filterChain) {
50975
51170
  const parts2 = segment.split(":");
@@ -51014,7 +51209,7 @@ var resolveVoiceCampaignTemplate = (template, options) => {
51014
51209
  }
51015
51210
  return options.fallback ?? "";
51016
51211
  }
51017
- return renderValue(value, filters, segments.slice(1));
51212
+ return renderValue2(value, filters, segments.slice(1));
51018
51213
  });
51019
51214
  return { missingVariables: Array.from(missing), output };
51020
51215
  };
@@ -53647,6 +53842,7 @@ export {
53647
53842
  parseVoiceSessionSnapshot,
53648
53843
  parseVoiceAIScorecardResponse,
53649
53844
  normalizeVoiceProofTrendReport,
53845
+ normalizeSpokenNumbers,
53650
53846
  normalizePhoneNumber,
53651
53847
  muteVoiceMonitorIssue,
53652
53848
  matchesVoiceOpsTaskAssignmentRule,
@@ -5536,6 +5536,191 @@ var createVoiceMemoryStore = () => {
5536
5536
  // src/core/session.ts
5537
5537
  import { Buffer as Buffer2 } from "buffer";
5538
5538
 
5539
+ // src/core/numberNormalizer.ts
5540
+ var ONES = {
5541
+ eight: 8,
5542
+ eighteen: 18,
5543
+ eleven: 11,
5544
+ fifteen: 15,
5545
+ five: 5,
5546
+ four: 4,
5547
+ fourteen: 14,
5548
+ nine: 9,
5549
+ nineteen: 19,
5550
+ one: 1,
5551
+ seven: 7,
5552
+ seventeen: 17,
5553
+ six: 6,
5554
+ sixteen: 16,
5555
+ ten: 10,
5556
+ thirteen: 13,
5557
+ three: 3,
5558
+ twelve: 12,
5559
+ two: 2,
5560
+ zero: 0
5561
+ };
5562
+ var TENS = {
5563
+ eighty: 80,
5564
+ fifty: 50,
5565
+ forty: 40,
5566
+ ninety: 90,
5567
+ seventy: 70,
5568
+ sixty: 60,
5569
+ thirty: 30,
5570
+ twenty: 20
5571
+ };
5572
+ var SCALES = {
5573
+ billion: 1e9,
5574
+ million: 1e6,
5575
+ thousand: 1000,
5576
+ trillion: 1000000000000
5577
+ };
5578
+ var MAGNITUDE_WORDS = [
5579
+ [1000000000000, "trillion"],
5580
+ [1e9, "billion"],
5581
+ [1e6, "million"]
5582
+ ];
5583
+ var FILLER = new Set(["and", "a", "an"]);
5584
+ var DECIMAL_PLACES = 3;
5585
+ var isValueWord = (word) => (word in ONES) || (word in TENS) || word === "hundred";
5586
+ var isScaleWord = (word) => (word in SCALES);
5587
+ var isNumberWord = (word) => isValueWord(word) || isScaleWord(word) || word === "point" || FILLER.has(word);
5588
+ var trimNumber = (value) => {
5589
+ if (Number.isInteger(value))
5590
+ return value.toLocaleString("en-US");
5591
+ return String(Number(value.toFixed(DECIMAL_PLACES)));
5592
+ };
5593
+ var renderValue = (value, usedMagnitude) => {
5594
+ if (usedMagnitude) {
5595
+ for (const [scale, word] of MAGNITUDE_WORDS) {
5596
+ if (value >= scale) {
5597
+ const scaled = value / scale;
5598
+ if (Number(scaled.toFixed(DECIMAL_PLACES)) === scaled) {
5599
+ return `${trimNumber(scaled)} ${word}`;
5600
+ }
5601
+ }
5602
+ }
5603
+ }
5604
+ return trimNumber(value);
5605
+ };
5606
+ var parseNumberWords = (words) => {
5607
+ let total = 0;
5608
+ let current = 0;
5609
+ let usedMagnitude = false;
5610
+ let sawNumber = false;
5611
+ let decimal = null;
5612
+ const foldDecimal = () => {
5613
+ if (decimal && decimal.length > 0)
5614
+ current += Number(`0.${decimal}`);
5615
+ decimal = null;
5616
+ };
5617
+ for (const word of words) {
5618
+ if (word === "point") {
5619
+ decimal = "";
5620
+ continue;
5621
+ }
5622
+ const one = ONES[word];
5623
+ const ten = TENS[word];
5624
+ const scale = SCALES[word];
5625
+ if (decimal !== null) {
5626
+ if (one !== undefined && one <= 9) {
5627
+ decimal += String(one);
5628
+ sawNumber = true;
5629
+ continue;
5630
+ }
5631
+ foldDecimal();
5632
+ }
5633
+ if (FILLER.has(word))
5634
+ continue;
5635
+ if (one !== undefined) {
5636
+ current += one;
5637
+ sawNumber = true;
5638
+ } else if (ten !== undefined) {
5639
+ current += ten;
5640
+ sawNumber = true;
5641
+ } else if (word === "hundred") {
5642
+ current = (current === 0 ? 1 : current) * 100;
5643
+ sawNumber = true;
5644
+ } else if (scale !== undefined) {
5645
+ total += (current === 0 ? 1 : current) * scale;
5646
+ current = 0;
5647
+ sawNumber = true;
5648
+ usedMagnitude = true;
5649
+ }
5650
+ }
5651
+ foldDecimal();
5652
+ if (!sawNumber)
5653
+ return null;
5654
+ return { usedMagnitude, value: total + current };
5655
+ };
5656
+ var PERCENT_RE = /^(per ?cent|percent|percentage)$/;
5657
+ var CURRENCY_RE = /^(dollars?|bucks?|usd)$/;
5658
+ var WORD_RE = /^[A-Za-z]+(?:-[A-Za-z]+)*$/;
5659
+ var wordsOf = (token) => token.toLowerCase().split("-");
5660
+ var isNumberToken = (token) => WORD_RE.test(token) && wordsOf(token).every(isNumberWord);
5661
+ var startsNumber = (token) => WORD_RE.test(token) && wordsOf(token).some(isValueWord);
5662
+ var isSpace = (token) => /^\s+$/.test(token);
5663
+ var normalizeSpokenNumbers = (input) => {
5664
+ if (!input)
5665
+ return input;
5666
+ const parts = input.match(/[A-Za-z]+(?:-[A-Za-z]+)*|[^A-Za-z]+/g);
5667
+ if (!parts)
5668
+ return input;
5669
+ const at = (idx) => parts[idx] ?? "";
5670
+ const out = [];
5671
+ let i = 0;
5672
+ while (i < parts.length) {
5673
+ const token = at(i);
5674
+ const lower = token.toLowerCase();
5675
+ if (lower === "a" || lower === "an") {
5676
+ const nextWord = at(i + 2);
5677
+ const nextHead = wordsOf(nextWord)[0] ?? "";
5678
+ const nextIsScale = isSpace(at(i + 1)) && WORD_RE.test(nextWord) && (nextHead === "hundred" || isScaleWord(nextHead));
5679
+ if (!nextIsScale) {
5680
+ out.push(token);
5681
+ i += 1;
5682
+ continue;
5683
+ }
5684
+ } else if (!startsNumber(token)) {
5685
+ out.push(token);
5686
+ i += 1;
5687
+ continue;
5688
+ }
5689
+ const spanIdx = [i];
5690
+ let j = i + 1;
5691
+ while (isSpace(at(j)) && isNumberToken(at(j + 1))) {
5692
+ spanIdx.push(j + 1);
5693
+ j += 2;
5694
+ }
5695
+ const words = spanIdx.flatMap((k) => wordsOf(at(k)));
5696
+ while (words.length > 0 && FILLER.has(words[words.length - 1] ?? "")) {
5697
+ words.pop();
5698
+ }
5699
+ const parsed = parseNumberWords(words);
5700
+ if (!parsed) {
5701
+ out.push(token);
5702
+ i += 1;
5703
+ continue;
5704
+ }
5705
+ let rendered = renderValue(parsed.value, parsed.usedMagnitude);
5706
+ let lastIdx = spanIdx[spanIdx.length - 1] ?? i;
5707
+ const unitWord = at(lastIdx + 2);
5708
+ if (isSpace(at(lastIdx + 1)) && WORD_RE.test(unitWord)) {
5709
+ const unit = unitWord.toLowerCase();
5710
+ if (PERCENT_RE.test(unit)) {
5711
+ rendered = `${rendered}%`;
5712
+ lastIdx += 2;
5713
+ } else if (CURRENCY_RE.test(unit)) {
5714
+ rendered = rendered.startsWith("$") ? rendered : `$${rendered}`;
5715
+ lastIdx += 2;
5716
+ }
5717
+ }
5718
+ out.push(rendered);
5719
+ i = lastIdx + 1;
5720
+ }
5721
+ return out.join("");
5722
+ };
5723
+
5539
5724
  // src/core/backchannel.ts
5540
5725
  var DEFAULT_CUES = [
5541
5726
  { text: "mm-hmm" },
@@ -8154,6 +8339,9 @@ var createVoiceSession = (options) => {
8154
8339
  };
8155
8340
  const completeTurn = async (session, turn) => {
8156
8341
  console.error(`[voice] completeTurn ENTER session=${options.id} turn=${turn.id} textLen=${turn.text?.length ?? 0}`);
8342
+ if (options.normalizeNumbers && turn.text) {
8343
+ turn.text = normalizeSpokenNumbers(turn.text);
8344
+ }
8157
8345
  kickStuckCloseWatchdog();
8158
8346
  kickIdleRepromptWatchdog(true);
8159
8347
  const liveOpsControl = await options.liveOps?.getControl(options.id);
@@ -14434,6 +14622,7 @@ var createTwilioMediaStreamBridge = (socket, options) => {
14434
14622
  const voiceSocket = createTwilioSocketAdapter(socket, () => bridgeState);
14435
14623
  sessionHandle = createVoiceSession({
14436
14624
  audioConditioning,
14625
+ normalizeNumbers: options.normalizeNumbers,
14437
14626
  context: options.context,
14438
14627
  costAccountant: options.costAccountant,
14439
14628
  costTelemetry: options.costTelemetry,
@@ -14453,6 +14642,9 @@ var createTwilioMediaStreamBridge = (socket, options) => {
14453
14642
  stt: options.stt,
14454
14643
  sttFallback: resolveSTTFallbackConfig(options.sttFallback),
14455
14644
  sttLifecycle: options.sttLifecycle ?? runtimePreset.sttLifecycle,
14645
+ sttRecoveryLine: options.sttRecoveryLine,
14646
+ stuckCallClose: options.stuckCallClose,
14647
+ idleReprompt: options.idleReprompt,
14456
14648
  ...options.semanticTurnDetector ? { semanticTurnDetector: options.semanticTurnDetector } : {},
14457
14649
  ...options.bargeInDetector ? { bargeInDetector: options.bargeInDetector } : {},
14458
14650
  ...options.fillerPhrases ? { fillerPhrases: options.fillerPhrases } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.624",
3
+ "version": "0.0.22-beta.626",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",