@volley/recognition-client-sdk 0.1.385 → 0.1.418

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
@@ -1,4 +1,4 @@
1
- // ../../node_modules/.pnpm/zod@3.22.5/node_modules/zod/lib/index.mjs
1
+ // ../../node_modules/.pnpm/zod@3.22.4/node_modules/zod/lib/index.mjs
2
2
  var util;
3
3
  (function(util2) {
4
4
  util2.assertEqual = (val) => val;
@@ -3797,6 +3797,7 @@ var RecognitionResultTypeV1;
3797
3797
  RecognitionResultTypeV12["METADATA"] = "Metadata";
3798
3798
  RecognitionResultTypeV12["ERROR"] = "Error";
3799
3799
  RecognitionResultTypeV12["CLIENT_CONTROL_MESSAGE"] = "ClientControlMessage";
3800
+ RecognitionResultTypeV12["AUDIO_METRICS"] = "AudioMetrics";
3800
3801
  })(RecognitionResultTypeV1 || (RecognitionResultTypeV1 = {}));
3801
3802
  var TranscriptionResultSchemaV1 = z.object({
3802
3803
  type: z.literal(RecognitionResultTypeV1.TRANSCRIPTION),
@@ -3821,6 +3822,12 @@ var FunctionCallResultSchemaV1 = z.object({
3821
3822
  functionName: z.string(),
3822
3823
  functionArgJson: z.string()
3823
3824
  });
3825
+ var TranscriptOutcomeType;
3826
+ (function(TranscriptOutcomeType2) {
3827
+ TranscriptOutcomeType2["WITH_CONTENT"] = "with_content";
3828
+ TranscriptOutcomeType2["EMPTY"] = "empty";
3829
+ TranscriptOutcomeType2["NEVER_SENT"] = "never_sent";
3830
+ })(TranscriptOutcomeType || (TranscriptOutcomeType = {}));
3824
3831
  var MetadataResultSchemaV1 = z.object({
3825
3832
  type: z.literal(RecognitionResultTypeV1.METADATA),
3826
3833
  audioUtteranceId: z.string(),
@@ -3840,7 +3847,9 @@ var MetadataResultSchemaV1 = z.object({
3840
3847
  // ASR configuration as JSON string (no type validation)
3841
3848
  asrConfig: z.string().optional(),
3842
3849
  // Raw ASR metadata payload as provided by the provider (stringified if needed)
3843
- rawAsrMetadata: z.string().optional()
3850
+ rawAsrMetadata: z.string().optional(),
3851
+ // Transcript outcome - categorizes the final transcript state
3852
+ transcriptOutcome: z.nativeEnum(TranscriptOutcomeType).optional()
3844
3853
  });
3845
3854
  var ErrorTypeV1;
3846
3855
  (function(ErrorTypeV12) {
@@ -3873,6 +3882,22 @@ var ClientControlMessageSchemaV1 = z.object({
3873
3882
  action: ClientControlActionsV1
3874
3883
  // The control action to perform
3875
3884
  });
3885
+ var AudioMetricsResultSchemaV1 = z.object({
3886
+ type: z.literal(RecognitionResultTypeV1.AUDIO_METRICS),
3887
+ valid: z.boolean(),
3888
+ audioBeginMs: z.number(),
3889
+ audioEndMs: z.number(),
3890
+ maxVolume: z.number(),
3891
+ minVolume: z.number(),
3892
+ avgVolume: z.number(),
3893
+ silenceRatio: z.number(),
3894
+ clippingRatio: z.number(),
3895
+ snrEstimate: z.number().nullable(),
3896
+ lastNonSilenceMs: z.number(),
3897
+ timestamp: z.string(),
3898
+ isFinal: z.boolean().optional()
3899
+ // true if this is the final metrics (STOP_RECORDING signal), false for streaming
3900
+ });
3876
3901
  var RecognitionResultSchemaV1 = z.discriminatedUnion("type", [
3877
3902
  // P0
3878
3903
  TranscriptionResultSchemaV1,
@@ -4541,6 +4566,7 @@ var PlumbingType;
4541
4566
  PlumbingType2["PROVIDER_VAD_SIGNAL"] = "provider_vad_signal";
4542
4567
  PlumbingType2["PROVIDER_TIMER_SIGNAL"] = "provider_timer_signal";
4543
4568
  PlumbingType2["PROVIDER_RAW_MESSAGE"] = "provider_raw_message";
4569
+ PlumbingType2["AUDIO_METRICS"] = "audio_metrics";
4544
4570
  })(PlumbingType || (PlumbingType = {}));
4545
4571
 
4546
4572
  // ../../libs/types/dist/game-id.types.js
@@ -4565,6 +4591,21 @@ var STRING_TO_GAME_ID_MAP = {
4565
4591
  "twenty-questions": GameId.TWENTY_QUESTIONS,
4566
4592
  "emoji": GameId.GUESS_THE_EMOJI
4567
4593
  };
4594
+ var GAME_ID_ALIAS_MAP = {
4595
+ // Song Quiz aliases
4596
+ "songquiz": GameId.SONG_QUIZ,
4597
+ "sq": GameId.SONG_QUIZ,
4598
+ // Wheel of Fortune aliases
4599
+ "wof": GameId.WHEEL_OF_FORTUNE,
4600
+ "wheeloffortune": GameId.WHEEL_OF_FORTUNE,
4601
+ // Twenty Questions aliases
4602
+ "20q": GameId.TWENTY_QUESTIONS,
4603
+ "twentyquestions": GameId.TWENTY_QUESTIONS,
4604
+ "20questions": GameId.TWENTY_QUESTIONS,
4605
+ // Guess the Emoji aliases
4606
+ "guesstheemoji": GameId.GUESS_THE_EMOJI,
4607
+ "gte": GameId.GUESS_THE_EMOJI
4608
+ };
4568
4609
 
4569
4610
  // ../../libs/types/dist/gemini-types.js
4570
4611
  var GeminiModel;
@@ -4770,7 +4811,7 @@ var WebSocketAudioClient = class {
4770
4811
  // ../../libs/websocket/dist/core/audio-upload-websocket-server.js
4771
4812
  import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
4772
4813
 
4773
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.js
4814
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/stringify.js
4774
4815
  var byteToHex = [];
4775
4816
  for (let i = 0; i < 256; ++i) {
4776
4817
  byteToHex.push((i + 256).toString(16).slice(1));
@@ -4779,7 +4820,7 @@ function unsafeStringify(arr, offset = 0) {
4779
4820
  return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
4780
4821
  }
4781
4822
 
4782
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/rng.js
4823
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/rng.js
4783
4824
  var getRandomValues;
4784
4825
  var rnds8 = new Uint8Array(16);
4785
4826
  function rng() {
@@ -4792,27 +4833,21 @@ function rng() {
4792
4833
  return getRandomValues(rnds8);
4793
4834
  }
4794
4835
 
4795
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.js
4836
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/native.js
4796
4837
  var randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
4797
4838
  var native_default = { randomUUID };
4798
4839
 
4799
- // ../../node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.js
4840
+ // ../../node_modules/.pnpm/uuid@11.0.0/node_modules/uuid/dist/esm-browser/v4.js
4800
4841
  function v4(options, buf, offset) {
4801
4842
  if (native_default.randomUUID && !buf && !options) {
4802
4843
  return native_default.randomUUID();
4803
4844
  }
4804
4845
  options = options || {};
4805
- const rnds = options.random ?? options.rng?.() ?? rng();
4806
- if (rnds.length < 16) {
4807
- throw new Error("Random bytes length must be >= 16");
4808
- }
4846
+ const rnds = options.random || (options.rng || rng)();
4809
4847
  rnds[6] = rnds[6] & 15 | 64;
4810
4848
  rnds[8] = rnds[8] & 63 | 128;
4811
4849
  if (buf) {
4812
4850
  offset = offset || 0;
4813
- if (offset < 0 || offset + 16 > buf.length) {
4814
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
4815
- }
4816
4851
  for (let i = 0; i < 16; ++i) {
4817
4852
  buf[offset + i] = rnds[i];
4818
4853
  }
@@ -4941,8 +4976,11 @@ function buildWebSocketUrl(config) {
4941
4976
  if (config.platform) {
4942
4977
  url.searchParams.set("platform", config.platform);
4943
4978
  }
4944
- if (config.gameContext) {
4945
- url.searchParams.set("gameId", config.gameContext.gameId);
4979
+ const gameId = config.gameId ?? config.gameContext?.gameId;
4980
+ if (gameId) {
4981
+ url.searchParams.set("gameId", gameId);
4982
+ }
4983
+ if (config.gameContext?.gamePhase) {
4946
4984
  url.searchParams.set("gamePhase", config.gameContext.gamePhase);
4947
4985
  }
4948
4986
  return url.toString();
@@ -4978,7 +5016,7 @@ var AudioRingBuffer = class {
4978
5016
  this.hasWrapped = true;
4979
5017
  this.overflowCount++;
4980
5018
  if (this.logger) {
4981
- this.logger("debug", "Buffer overflow detected", {
5019
+ this.logger("debug", "[RecogSDK] Buffer overflow detected", {
4982
5020
  bufferSize: this.bufferSize,
4983
5021
  totalOverflows: this.overflowCount,
4984
5022
  droppedChunk: this.buffer[this.readIndex]?.timestamp
@@ -5059,7 +5097,7 @@ var AudioRingBuffer = class {
5059
5097
  this.chunksBuffered = 0;
5060
5098
  this.totalBufferedBytes = 0;
5061
5099
  if (this.logger) {
5062
- this.logger("debug", "Audio buffer cleared");
5100
+ this.logger("debug", "[RecogSDK] Audio buffer cleared");
5063
5101
  }
5064
5102
  }
5065
5103
  /**
@@ -5094,7 +5132,7 @@ var MessageHandler = class {
5094
5132
  */
5095
5133
  handleMessage(msg) {
5096
5134
  if (this.callbacks.logger) {
5097
- this.callbacks.logger("debug", "Received WebSocket message", {
5135
+ this.callbacks.logger("debug", "[RecogSDK] Received WebSocket message", {
5098
5136
  msgType: msg.type,
5099
5137
  msgDataType: msg.data && typeof msg.data === "object" && "type" in msg.data ? msg.data.type : "N/A",
5100
5138
  fullMessage: msg
@@ -5102,7 +5140,7 @@ var MessageHandler = class {
5102
5140
  }
5103
5141
  if (msg.data && typeof msg.data !== "object") {
5104
5142
  if (this.callbacks.logger) {
5105
- this.callbacks.logger("error", "Received primitive msg.data from server", {
5143
+ this.callbacks.logger("error", "[RecogSDK] Received primitive msg.data from server", {
5106
5144
  dataType: typeof msg.data,
5107
5145
  data: msg.data,
5108
5146
  fullMessage: msg
@@ -5129,7 +5167,7 @@ var MessageHandler = class {
5129
5167
  break;
5130
5168
  default:
5131
5169
  if (this.callbacks.logger) {
5132
- this.callbacks.logger("debug", "Unknown message type", { type: msgType });
5170
+ this.callbacks.logger("debug", "[RecogSDK] Unknown message type", { type: msgType });
5133
5171
  }
5134
5172
  }
5135
5173
  }
@@ -5142,7 +5180,7 @@ var MessageHandler = class {
5142
5180
  this.firstTranscriptTime = Date.now();
5143
5181
  const timeToFirstTranscript = this.firstTranscriptTime - this.sessionStartTime;
5144
5182
  if (this.callbacks.logger) {
5145
- this.callbacks.logger("debug", "First transcript received", {
5183
+ this.callbacks.logger("debug", "[RecogSDK] First transcript received", {
5146
5184
  timeToFirstTranscriptMs: timeToFirstTranscript
5147
5185
  });
5148
5186
  }
@@ -5237,7 +5275,8 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
5237
5275
  ...config.accountId && { accountId: config.accountId },
5238
5276
  ...config.questionAnswerId && { questionAnswerId: config.questionAnswerId },
5239
5277
  ...config.platform && { platform: config.platform },
5240
- ...config.gameContext && { gameContext: config.gameContext }
5278
+ ...config.gameContext && { gameContext: config.gameContext },
5279
+ ...config.gameId && { gameId: config.gameId }
5241
5280
  });
5242
5281
  super({
5243
5282
  url,
@@ -5315,7 +5354,7 @@ var RealTimeTwoWayWebSocketRecognitionClient = class _RealTimeTwoWayWebSocketRec
5315
5354
  return;
5316
5355
  }
5317
5356
  if (this.config.logger) {
5318
- this.config.logger(level, `[SDK] ${message}`, data);
5357
+ this.config.logger(level, `[RecogSDK] ${message}`, data);
5319
5358
  }
5320
5359
  }
5321
5360
  /**
@@ -5757,6 +5796,14 @@ var ConfigBuilder = class {
5757
5796
  this.config.gameContext = context;
5758
5797
  return this;
5759
5798
  }
5799
+ /**
5800
+ * Set game ID directly (takes precedence over gameContext.gameId)
5801
+ * Use this when you only need to identify the game without full context.
5802
+ */
5803
+ gameId(id) {
5804
+ this.config.gameId = id;
5805
+ return this;
5806
+ }
5760
5807
  /**
5761
5808
  * Set audio utterance ID
5762
5809
  */
@@ -6036,6 +6083,16 @@ function updateStateOnStop(currentState) {
6036
6083
  finalRecordingTimestamp: (/* @__PURE__ */ new Date()).toISOString()
6037
6084
  };
6038
6085
  }
6086
+ function resetSessionState(currentState) {
6087
+ return {
6088
+ ...currentState,
6089
+ audioUtteranceId: v4_default(),
6090
+ transcriptionStatus: TranscriptionStatus.NOT_STARTED,
6091
+ startRecordingStatus: RecordingStatus.READY,
6092
+ recognitionActionProcessingState: RecognitionActionProcessingState.NOT_STARTED,
6093
+ finalTranscript: void 0
6094
+ };
6095
+ }
6039
6096
  function generateUUID() {
6040
6097
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
6041
6098
  const r = Math.random() * 16 | 0;
@@ -6048,26 +6105,21 @@ function generateUUID() {
6048
6105
  var SimplifiedVGFRecognitionClient = class {
6049
6106
  constructor(config) {
6050
6107
  this.isRecordingAudio = false;
6108
+ this.lastSentTerminalUuid = null;
6051
6109
  const { onStateChange, initialState, ...clientConfig } = config;
6052
6110
  this.stateChangeCallback = onStateChange;
6053
6111
  this.logger = clientConfig.logger;
6054
6112
  if (initialState) {
6055
6113
  const needsNewUuid = !initialState.audioUtteranceId || initialState.audioUtteranceId === "" || initialState.transcriptionStatus === TranscriptionStatus.ABORTED || initialState.transcriptionStatus === TranscriptionStatus.FINALIZED || initialState.transcriptionStatus === TranscriptionStatus.ERROR || initialState.recognitionActionProcessingState !== void 0 && initialState.recognitionActionProcessingState !== RecognitionActionProcessingState.COMPLETED;
6056
6114
  if (needsNewUuid) {
6057
- const newUUID = v4_default();
6115
+ this.state = resetSessionState(initialState);
6116
+ const newUUID = this.state.audioUtteranceId;
6058
6117
  if (clientConfig.logger) {
6059
6118
  const reason = !initialState.audioUtteranceId ? "Missing UUID" : initialState.audioUtteranceId === "" ? "Empty UUID" : `Terminal session (${initialState.transcriptionStatus})`;
6060
6119
  clientConfig.logger("info", `${reason} detected, generating new UUID: ${newUUID}`);
6061
6120
  }
6062
- this.state = {
6063
- ...initialState,
6064
- audioUtteranceId: newUUID,
6065
- transcriptionStatus: TranscriptionStatus.NOT_STARTED,
6066
- startRecordingStatus: RecordingStatus.READY,
6067
- recognitionActionProcessingState: RecognitionActionProcessingState.NOT_STARTED,
6068
- finalTranscript: void 0
6069
- };
6070
6121
  clientConfig.audioUtteranceId = newUUID;
6122
+ this.lastSentTerminalUuid = null;
6071
6123
  if (onStateChange) {
6072
6124
  onStateChange(this.state);
6073
6125
  }
@@ -6102,11 +6154,17 @@ var SimplifiedVGFRecognitionClient = class {
6102
6154
  if (this.logger) {
6103
6155
  this.logger(
6104
6156
  "warn",
6105
- `[VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
6157
+ `[RecogSDK:VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
6106
6158
  );
6107
6159
  }
6108
- if (clientConfig.onTranscript) {
6109
- clientConfig.onTranscript(result);
6160
+ return;
6161
+ }
6162
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6163
+ if (this.logger) {
6164
+ this.logger(
6165
+ "info",
6166
+ `[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
6167
+ );
6110
6168
  }
6111
6169
  return;
6112
6170
  }
@@ -6121,7 +6179,7 @@ var SimplifiedVGFRecognitionClient = class {
6121
6179
  if (this.logger) {
6122
6180
  this.logger(
6123
6181
  "warn",
6124
- `[VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
6182
+ `[RecogSDK:VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
6125
6183
  );
6126
6184
  }
6127
6185
  return;
@@ -6140,11 +6198,14 @@ var SimplifiedVGFRecognitionClient = class {
6140
6198
  if (this.logger) {
6141
6199
  this.logger(
6142
6200
  "warn",
6143
- `[VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
6201
+ `[RecogSDK:VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
6144
6202
  );
6145
6203
  }
6146
6204
  return;
6147
6205
  }
6206
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6207
+ return;
6208
+ }
6148
6209
  this.isRecordingAudio = false;
6149
6210
  this.state = mapErrorToState(this.state, error);
6150
6211
  this.notifyStateChange();
@@ -6186,6 +6247,24 @@ var SimplifiedVGFRecognitionClient = class {
6186
6247
  this.isRecordingAudio = false;
6187
6248
  this.state = updateStateOnStop(this.state);
6188
6249
  this.notifyStateChange();
6250
+ if (this.state.transcriptionStatus === TranscriptionStatus.NOT_STARTED) {
6251
+ if (this.logger) {
6252
+ this.logger(
6253
+ "info",
6254
+ `[RecogSDK:VGF] Early termination detected (transcriptionStatus: NOT_STARTED) - emitting synthetic finalization`
6255
+ );
6256
+ }
6257
+ this.state = {
6258
+ ...this.state,
6259
+ transcriptionStatus: TranscriptionStatus.FINALIZED,
6260
+ finalTranscript: "",
6261
+ finalConfidence: 0,
6262
+ pendingTranscript: "",
6263
+ pendingConfidence: void 0,
6264
+ finalTranscriptionTimestamp: (/* @__PURE__ */ new Date()).toISOString()
6265
+ };
6266
+ this.notifyStateChange();
6267
+ }
6189
6268
  await this.client.stopRecording();
6190
6269
  }
6191
6270
  stopAbnormally() {
@@ -6235,10 +6314,26 @@ var SimplifiedVGFRecognitionClient = class {
6235
6314
  getVGFState() {
6236
6315
  return { ...this.state };
6237
6316
  }
6317
+ isTerminalStatus(status) {
6318
+ return status === TranscriptionStatus.FINALIZED || status === TranscriptionStatus.ABORTED || status === TranscriptionStatus.ERROR;
6319
+ }
6238
6320
  notifyStateChange() {
6239
- if (this.stateChangeCallback) {
6240
- this.stateChangeCallback({ ...this.state });
6321
+ if (this.isTerminalStatus(this.state.transcriptionStatus)) {
6322
+ if (this.lastSentTerminalUuid === this.expectedUuid) {
6323
+ if (this.logger) {
6324
+ this.logger(
6325
+ "info",
6326
+ `[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
6327
+ );
6328
+ }
6329
+ return;
6330
+ }
6331
+ this.lastSentTerminalUuid = this.expectedUuid;
6332
+ }
6333
+ if (!this.stateChangeCallback) {
6334
+ return;
6241
6335
  }
6336
+ this.stateChangeCallback({ ...this.state });
6242
6337
  }
6243
6338
  };
6244
6339
  function createSimplifiedVGFClient(config) {
@@ -6293,6 +6388,7 @@ export {
6293
6388
  isExceptionImmediatelyAvailable,
6294
6389
  isNormalDisconnection,
6295
6390
  isValidRecordingStatusTransition,
6296
- normalizeStage
6391
+ normalizeStage,
6392
+ resetSessionState
6297
6393
  };
6298
6394
  //# sourceMappingURL=index.js.map