@volley/recognition-client-sdk 0.1.424 → 0.1.622

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.
@@ -33,7 +33,7 @@
33
33
  * ```
34
34
  */
35
35
  import { WebSocketAudioClient } from '@recog/websocket';
36
- import { type TranscriptionResultV1 } from '@recog/shared-types';
36
+ import { type TranscriptionResultV1, type GameContextV1 } from '@recog/shared-types';
37
37
  import { ClientState } from './recognition-client.types.js';
38
38
  import type { IRecognitionClient, IRecognitionClientStats, RealTimeTwoWayWebSocketRecognitionClientConfig } from './recognition-client.types.js';
39
39
  /**
@@ -55,8 +55,11 @@ export type { RealTimeTwoWayWebSocketRecognitionClientConfig } from './recogniti
55
55
  */
56
56
  export declare class RealTimeTwoWayWebSocketRecognitionClient extends WebSocketAudioClient<number, any, any> implements IRecognitionClient {
57
57
  private static readonly PROTOCOL_VERSION;
58
+ private static readonly MAX_PREFIX_BUFFER_BYTES;
58
59
  private config;
59
60
  private audioBuffer;
61
+ private prefixBuffer;
62
+ private prefixBufferBytes;
60
63
  private messageHandler;
61
64
  private state;
62
65
  private connectionPromise;
@@ -101,6 +104,8 @@ export declare class RealTimeTwoWayWebSocketRecognitionClient extends WebSocketA
101
104
  isStopping(): boolean;
102
105
  isTranscriptionFinished(): boolean;
103
106
  isBufferOverflowing(): boolean;
107
+ isServerReady(): boolean;
108
+ sendGameContext(context: GameContextV1): void;
104
109
  getStats(): IRecognitionClientStats;
105
110
  protected onConnected(): void;
106
111
  protected onDisconnected(code: number, reason: string): void;
@@ -124,5 +129,27 @@ export declare class RealTimeTwoWayWebSocketRecognitionClient extends WebSocketA
124
129
  * @param audioData - Audio data to send
125
130
  */
126
131
  private sendAudioNow;
132
+ /**
133
+ * Send prefix audio to the server.
134
+ * Prefix audio is sent before user audio and is used for context/priming.
135
+ * The server will process it but adjust timing so transcripts reflect user audio timing.
136
+ *
137
+ * Note: Prefix audio is buffered until READY state, then flushed before user audio.
138
+ * This ensures proper ordering even if called before server is ready.
139
+ *
140
+ * @param audioData - Prefix audio data (ArrayBuffer, ArrayBufferView, or Blob)
141
+ */
142
+ sendPrefixAudio(audioData: ArrayBuffer | ArrayBufferView | Blob): void;
143
+ /**
144
+ * Internal method to handle prefix audio with buffering
145
+ * Buffers if not READY, sends immediately if READY
146
+ */
147
+ private sendPrefixAudioInternal;
148
+ /**
149
+ * Send prefix audio immediately to the server (without buffering)
150
+ * Uses encoding offset to mark as prefix audio
151
+ * @param audioData - Prefix audio data to send
152
+ */
153
+ private sendPrefixAudioNow;
127
154
  }
128
155
  //# sourceMappingURL=recognition-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"recognition-client.d.ts","sourceRoot":"","sources":["../src/recognition-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAML,KAAK,qBAAqB,EAS3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EACV,kBAAkB,EAClB,uBAAuB,EACvB,8CAA8C,EAE/C,MAAM,+BAA+B,CAAC;AAUvC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAgCD;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAGxD,YAAY,EAAE,8CAA8C,EAAE,MAAM,+BAA+B,CAAC;AAgCpG;;;;;GAKG;AACH,qBAAa,wCACX,SAAQ,oBAAoB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAC7C,YAAW,kBAAkB;IAE7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAK;IAE7C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,iBAAiB,CAA4B;IAGrD,OAAO,CAAC,iBAAiB,CAAS;IAGlC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,qBAAqB,CAAO;IACpC,OAAO,CAAC,iBAAiB,CAAK;gBAElB,MAAM,EAAE,8CAA8C;IA+ElE;;;;;;OAMG;IACH,OAAO,CAAC,GAAG;IAWX;;;OAGG;IACH,OAAO,CAAC,OAAO;IAmBA,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA6BvC;;;OAGG;YACW,gBAAgB;IAkIrB,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI;IAiBzE,OAAO,CAAC,iBAAiB;IAsCzB;;;OAGG;IAEG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCpC,cAAc,IAAI,IAAI;IAwBtB,mBAAmB,IAAI,MAAM;IAI7B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,WAAW;IAIvB,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,OAAO;IAIrB,uBAAuB,IAAI,OAAO;IAIlC,mBAAmB,IAAI,OAAO;IAI9B,QAAQ,IAAI,uBAAuB;IAgBnC,SAAS,CAAC,WAAW,IAAI,IAAI;IAiE7B,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IA8C5D;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAwB/B,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;cAYlB,SAAS,CAAC,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,GAAG,IAAI;IAQ/E;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;;OAGG;IACH,OAAO,CAAC,YAAY;CAuBrB"}
1
+ {"version":3,"file":"recognition-client.d.ts","sourceRoot":"","sources":["../src/recognition-client.ts"],"names":[],"mappings":"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"}
@@ -243,6 +243,26 @@ export interface IRecognitionClient {
243
243
  * @returns WebSocket URL string
244
244
  */
245
245
  getUrl(): string;
246
+ /**
247
+ * Send game context after connection is established (for preconnect flow).
248
+ *
249
+ * Preconnect flow: Create client with asrRequestConfig (useContext: true) but
250
+ * WITHOUT gameContext → call connect() → WS opens, ASRRequest sent, server
251
+ * waits in PENDING_CONTEXT → later call sendGameContext() with slotMap →
252
+ * server attaches provider and sends READY.
253
+ *
254
+ * This enables connecting early (before slotMap is known) and sending
255
+ * game context later when question data is available.
256
+ *
257
+ * @param context - Game context including slotMap for keyword boosting
258
+ */
259
+ sendGameContext(context: GameContextV1): void;
260
+ /**
261
+ * Check if server has sent READY signal (provider is connected and ready for audio).
262
+ * In preconnect flow, this becomes true after sendGameContext() triggers provider attachment.
263
+ * @returns true if server is ready to receive audio
264
+ */
265
+ isServerReady(): boolean;
246
266
  }
247
267
  /**
248
268
  * Client statistics interface
@@ -1 +1 @@
1
- {"version":3,"file":"recognition-client.types.d.ts","sourceRoot":"","sources":["../src/recognition-client.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recognition-client.types.d.ts","sourceRoot":"","sources":["../src/recognition-client.types.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@
9
9
  */
10
10
  import { RecognitionState } from './vgf-recognition-state.js';
11
11
  import { IRecognitionClientConfig, ClientState } from './recognition-client.types.js';
12
+ import { type GameContextV1 } from '@recog/shared-types';
12
13
  /**
13
14
  * Configuration for SimplifiedVGFRecognitionClient
14
15
  */
@@ -89,6 +90,20 @@ export interface ISimplifiedVGFRecognitionClient {
89
90
  * Check if the audio buffer has overflowed
90
91
  */
91
92
  isBufferOverflowing(): boolean;
93
+ /**
94
+ * Send game context after connection is established (for preconnect flow).
95
+ *
96
+ * Preconnect flow: Create client with asrRequestConfig (useContext: true) but
97
+ * WITHOUT gameContext → call connect() → later call sendGameContext() with slotMap.
98
+ *
99
+ * @param context - Game context including slotMap for keyword boosting
100
+ */
101
+ sendGameContext(context: GameContextV1): void;
102
+ /**
103
+ * Check if server has sent READY signal (provider connected, ready for audio).
104
+ * In preconnect flow, this becomes true after sendGameContext() triggers provider attachment.
105
+ */
106
+ isServerReady(): boolean;
92
107
  /**
93
108
  * Get the audio utterance ID for this session
94
109
  */
@@ -127,6 +142,8 @@ export declare class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRec
127
142
  isStopping(): boolean;
128
143
  isTranscriptionFinished(): boolean;
129
144
  isBufferOverflowing(): boolean;
145
+ sendGameContext(context: GameContextV1): void;
146
+ isServerReady(): boolean;
130
147
  getVGFState(): RecognitionState;
131
148
  private isTerminalStatus;
132
149
  private notifyStateChange;
@@ -1 +1 @@
1
- {"version":3,"file":"simplified-vgf-recognition-client.d.ts","sourceRoot":"","sources":["../src/simplified-vgf-recognition-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,gBAAgB,EAInB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,wBAAwB,EACxB,WAAW,EACd,MAAM,+BAA+B,CAAC;AAWvC;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAElD;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAE5C;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAEjE;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,IAAI,IAAI,CAAC;IAGvB;;;OAGG;IACH,WAAW,IAAI,gBAAgB,CAAC;IAGhC;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC;IAEtB;;OAEG;IACH,uBAAuB,IAAI,OAAO,CAAC;IAEnC;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC;IAG/B;;OAEG;IACH,mBAAmB,IAAI,MAAM,CAAC;IAE9B;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,IAAI,WAAW,CAAC;CAE3B;AAED;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,+BAA+B;IAClF,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkD;IAC7E,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,oBAAoB,CAAuB;gBAEvC,MAAM,EAAE,yBAAyB;IAmKvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI;IAc1D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BpC,cAAc,IAAI,IAAI;IAiCtB,mBAAmB,IAAI,MAAM;IAI7B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,WAAW;IAIvB,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,OAAO;IAIrB,uBAAuB,IAAI,OAAO;IAIlC,mBAAmB,IAAI,OAAO;IAM9B,WAAW,IAAI,gBAAgB;IAI/B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,iBAAiB;CA8B5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,+BAA+B,CAE5G"}
1
+ {"version":3,"file":"simplified-vgf-recognition-client.d.ts","sourceRoot":"","sources":["../src/simplified-vgf-recognition-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,gBAAgB,EAInB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAEH,wBAAwB,EACxB,WAAW,EACd,MAAM,+BAA+B,CAAC;AASvC,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,wBAAwB;IACvE;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAElD;;;OAGG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,+BAA+B;IAE5C;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB;;;OAGG;IACH,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;IAEjE;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;OAgBG;IACH,cAAc,IAAI,IAAI,CAAC;IAGvB;;;OAGG;IACH,WAAW,IAAI,gBAAgB,CAAC;IAGhC;;OAEG;IACH,WAAW,IAAI,OAAO,CAAC;IAEvB;;OAEG;IACH,YAAY,IAAI,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC;IAEtB;;OAEG;IACH,uBAAuB,IAAI,OAAO,CAAC;IAEnC;;OAEG;IACH,mBAAmB,IAAI,OAAO,CAAC;IAG/B;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC;IAE9C;;;OAGG;IACH,aAAa,IAAI,OAAO,CAAC;IAGzB;;OAEG;IACH,mBAAmB,IAAI,MAAM,CAAC;IAE9B;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,IAAI,WAAW,CAAC;CAE3B;AAED;;;GAGG;AACH,qBAAa,8BAA+B,YAAW,+BAA+B;IAClF,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,mBAAmB,CAAkD;IAC7E,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,oBAAoB,CAAuB;gBAEvC,MAAM,EAAE,yBAAyB;IAqKvC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,SAAS,CAAC,SAAS,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,GAAG,IAAI;IAc1D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BpC,cAAc,IAAI,IAAI;IAiCtB,mBAAmB,IAAI,MAAM;IAI7B,MAAM,IAAI,MAAM;IAIhB,QAAQ,IAAI,WAAW;IAIvB,WAAW,IAAI,OAAO;IAItB,YAAY,IAAI,OAAO;IAIvB,UAAU,IAAI,OAAO;IAIrB,uBAAuB,IAAI,OAAO;IAIlC,mBAAmB,IAAI,OAAO;IAI9B,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAI7C,aAAa,IAAI,OAAO;IAMxB,WAAW,IAAI,gBAAgB;IAI/B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,iBAAiB;CA8B5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,+BAA+B,CAE5G"}
@@ -1 +1 @@
1
- {"version":3,"file":"vgf-recognition-mapper.d.ts","sourceRoot":"","sources":["../src/vgf-recognition-mapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,gBAAgB,EAKnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACH,WAAW,EACX,wBAAwB,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,qBAAqB,EACrB,aAAa,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAmBhF;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CACzC,YAAY,EAAE,gBAAgB,EAC9B,MAAM,EAAE,qBAAqB,EAC7B,WAAW,EAAE,OAAO,GACrB,gBAAgB,CAgDlB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC3B,YAAY,EAAE,gBAAgB,EAC9B,KAAK,EAAE,aAAa,GACrB,gBAAgB,CAOlB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,CAU3F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CAMlF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CASzF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CAKnF;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAC7C,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,GAAG,GAClB;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBnD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACvC,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD,gBAAgB,CAOlB"}
1
+ {"version":3,"file":"vgf-recognition-mapper.d.ts","sourceRoot":"","sources":["../src/vgf-recognition-mapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACH,gBAAgB,EAKnB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACH,WAAW,EACX,wBAAwB,EAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACH,qBAAqB,EACrB,aAAa,EAChB,MAAM,qBAAqB,CAAC;AAE7B;;GAEG;AACH,wBAAgB,+BAA+B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAmBhF;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CACzC,YAAY,EAAE,gBAAgB,EAC9B,MAAM,EAAE,qBAAqB,EAC7B,WAAW,EAAE,OAAO,GACrB,gBAAgB,CAgElB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC3B,YAAY,EAAE,gBAAgB,EAC9B,KAAK,EAAE,aAAa,GACrB,gBAAgB,CAOlB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,wBAAwB,GAAG,gBAAgB,CAU3F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CAMlF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CAWzF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,gBAAgB,GAAG,gBAAgB,CAKnF;AAED;;;GAGG;AACH,wBAAgB,iCAAiC,CAC7C,UAAU,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,GAAG,GAClB;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBnD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACvC,YAAY,EAAE,gBAAgB,EAC9B,YAAY,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD,gBAAgB,CAOlB"}
@@ -18,6 +18,8 @@ export declare const RecognitionVGFStateSchema: z.ZodObject<{
18
18
  transcriptionStatus: z.ZodOptional<z.ZodString>;
19
19
  finalTranscript: z.ZodOptional<z.ZodString>;
20
20
  finalConfidence: z.ZodOptional<z.ZodNumber>;
21
+ voiceEnd: z.ZodOptional<z.ZodNumber>;
22
+ lastNonSilence: z.ZodOptional<z.ZodNumber>;
21
23
  asrConfig: z.ZodOptional<z.ZodString>;
22
24
  startRecordingTimestamp: z.ZodOptional<z.ZodString>;
23
25
  finalRecordingTimestamp: z.ZodOptional<z.ZodString>;
@@ -36,6 +38,8 @@ export declare const RecognitionVGFStateSchema: z.ZodObject<{
36
38
  transcriptionStatus?: string | undefined;
37
39
  finalTranscript?: string | undefined;
38
40
  finalConfidence?: number | undefined;
41
+ voiceEnd?: number | undefined;
42
+ lastNonSilence?: number | undefined;
39
43
  asrConfig?: string | undefined;
40
44
  startRecordingTimestamp?: string | undefined;
41
45
  finalRecordingTimestamp?: string | undefined;
@@ -52,6 +56,8 @@ export declare const RecognitionVGFStateSchema: z.ZodObject<{
52
56
  transcriptionStatus?: string | undefined;
53
57
  finalTranscript?: string | undefined;
54
58
  finalConfidence?: number | undefined;
59
+ voiceEnd?: number | undefined;
60
+ lastNonSilence?: number | undefined;
55
61
  asrConfig?: string | undefined;
56
62
  startRecordingTimestamp?: string | undefined;
57
63
  finalRecordingTimestamp?: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"vgf-recognition-state.d.ts","sourceRoot":"","sources":["../src/vgf-recognition-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BpC,CAAA;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAGxE,eAAO,MAAM,eAAe;;;;;CAKlB,CAAA;AAEV,MAAM,MAAM,mBAAmB,GAAG,OAAO,eAAe,CAAC,MAAM,OAAO,eAAe,CAAC,CAAA;AAEtF,eAAO,MAAM,mBAAmB;;;;;;CAMtB,CAAA;AAEV,MAAM,MAAM,uBAAuB,GAAG,OAAO,mBAAmB,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAA;AAElG,eAAO,MAAM,gCAAgC;;;;CAInC,CAAA;AAEV,MAAM,MAAM,oCAAoC,GAAG,OAAO,gCAAgC,CAAC,MAAM,OAAO,gCAAgC,CAAC,CAAA;AAGzI,wBAAgB,6BAA6B,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAQxF;AAGD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAa9F"}
1
+ {"version":3,"file":"vgf-recognition-state.d.ts","sourceRoot":"","sources":["../src/vgf-recognition-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiCpC,CAAA;AAEF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAGxE,eAAO,MAAM,eAAe;;;;;CAKlB,CAAA;AAEV,MAAM,MAAM,mBAAmB,GAAG,OAAO,eAAe,CAAC,MAAM,OAAO,eAAe,CAAC,CAAA;AAEtF,eAAO,MAAM,mBAAmB;;;;;;CAMtB,CAAA;AAEV,MAAM,MAAM,uBAAuB,GAAG,OAAO,mBAAmB,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAA;AAElG,eAAO,MAAM,gCAAgC;;;;CAInC,CAAA;AAEV,MAAM,MAAM,oCAAoC,GAAG,OAAO,gCAAgC,CAAC,MAAM,OAAO,gCAAgC,CAAC,CAAA;AAGzI,wBAAgB,6BAA6B,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAQxF;AAGD,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAa9F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volley/recognition-client-sdk",
3
- "version": "0.1.424",
3
+ "version": "0.1.622",
4
4
  "description": "Recognition Service TypeScript/Node.js Client SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -43,21 +43,21 @@
43
43
  "@semantic-release/github": "12.0.0",
44
44
  "@semantic-release/npm": "13.1.1",
45
45
  "@semantic-release/release-notes-generator": "14.1.0",
46
- "@types/jest": "30.0.0",
47
- "@types/node": "20.4.5",
46
+ "@types/jest": "29.5.14",
47
+ "@types/node": "20.11.5",
48
48
  "@types/uuid": "10.0.0",
49
49
  "@types/ws": "8.5.5",
50
50
  "esbuild": "0.25.0",
51
- "jest": "29.6.1",
51
+ "jest": "29.7.0",
52
52
  "rollup": "4.52.5",
53
53
  "rollup-plugin-dts": "6.2.3",
54
54
  "semantic-release": "25.0.1",
55
- "ts-jest": "29.4.5",
55
+ "ts-jest": "29.2.5",
56
56
  "typescript": "5.1.6",
57
- "@recog/shared-types": "1.0.0",
58
57
  "@recog/shared-config": "1.0.0",
59
- "@recog/shared-utils": "1.0.0",
60
- "@recog/websocket": "1.0.0"
58
+ "@recog/shared-types": "1.0.0",
59
+ "@recog/websocket": "1.0.0",
60
+ "@recog/shared-utils": "1.0.0"
61
61
  },
62
62
  "keywords": [
63
63
  "recognition",
package/src/index.ts CHANGED
@@ -103,6 +103,9 @@ export {
103
103
  GoogleModel,
104
104
  GeminiModel,
105
105
  OpenAIModel,
106
+ OpenAIRealtimeModel,
107
+ MistralVoxtralModel,
108
+ DashScopeModel,
106
109
  Language,
107
110
  SampleRate,
108
111
 
@@ -48,7 +48,8 @@ import {
48
48
  type ASRRequestConfig,
49
49
  type ASRRequestV1,
50
50
  type GameContextV1,
51
- SampleRate
51
+ SampleRate,
52
+ PREFIX_AUDIO_ENCODING_OFFSET,
52
53
  } from '@recog/shared-types';
53
54
  import { v4 as uuidv4 } from 'uuid';
54
55
  import { ClientState } from './recognition-client.types.js';
@@ -155,9 +156,12 @@ export class RealTimeTwoWayWebSocketRecognitionClient
155
156
  implements IRecognitionClient
156
157
  {
157
158
  private static readonly PROTOCOL_VERSION = 1;
159
+ private static readonly MAX_PREFIX_BUFFER_BYTES = 10 * 1024 * 1024; // 10MB max (~5+ minutes of audio)
158
160
 
159
161
  private config: InternalConfig;
160
162
  private audioBuffer: AudioRingBuffer;
163
+ private prefixBuffer: (ArrayBuffer | ArrayBufferView)[] = []; // Buffer prefix audio until READY
164
+ private prefixBufferBytes = 0; // Track total bytes in prefix buffer
161
165
  private messageHandler: MessageHandler;
162
166
  private state: ClientState = ClientState.INITIAL;
163
167
  private connectionPromise: Promise<void> | undefined;
@@ -275,8 +279,10 @@ export class RealTimeTwoWayWebSocketRecognitionClient
275
279
  private cleanup(): void {
276
280
  this.log('debug', 'Cleaning up resources');
277
281
 
278
- // Clear audio buffer to free memory
282
+ // Clear audio buffers to free memory
279
283
  this.audioBuffer.clear();
284
+ this.prefixBuffer = [];
285
+ this.prefixBufferBytes = 0;
280
286
 
281
287
  // Reset stats
282
288
  this.audioBytesSent = 0;
@@ -363,7 +369,7 @@ export class RealTimeTwoWayWebSocketRecognitionClient
363
369
  const timeout = setTimeout(() => {
364
370
  if (settled) return;
365
371
  settled = true;
366
- this.log('warn', 'Connection timeout', { timeout: connectionTimeout, attempt });
372
+ this.log('warn', `Connection timeout url=${this.config.url}`, { timeout: connectionTimeout, attempt });
367
373
  this.state = ClientState.FAILED;
368
374
  reject(new Error(`Connection timeout after ${connectionTimeout}ms`));
369
375
  }, connectionTimeout);
@@ -392,7 +398,7 @@ export class RealTimeTwoWayWebSocketRecognitionClient
392
398
  settled = true;
393
399
  clearTimeout(timeout);
394
400
 
395
- this.log('warn', 'Connection error', { error, attempt });
401
+ this.log('warn', `Connection error url=${this.config.url}`, { error, attempt });
396
402
  this.state = ClientState.FAILED;
397
403
 
398
404
  // Don't call originalOnError - it expects ErrorResultV1, not WebSocket Event
@@ -418,7 +424,7 @@ export class RealTimeTwoWayWebSocketRecognitionClient
418
424
  // Not the last attempt - wait before retry
419
425
  // Use info for first 2 retries (attempts 2-3), warn for 3rd retry (attempt 4)
420
426
  const logLevel = attempt < 3 ? 'info' : 'warn';
421
- this.log(logLevel, `Connection attempt ${attempt} failed, retrying after ${delayMs}ms`, {
427
+ this.log(logLevel, `Connection attempt ${attempt} failed, retrying after ${delayMs}ms url=${this.config.url}`, {
422
428
  error: lastError.message,
423
429
  nextAttempt: attempt + 1
424
430
  });
@@ -430,7 +436,7 @@ export class RealTimeTwoWayWebSocketRecognitionClient
430
436
  await new Promise(resolve => setTimeout(resolve, delayMs));
431
437
  } else {
432
438
  // Last attempt failed - all retries exhausted
433
- this.log('warn', `All ${maxAttempts} connection attempts failed`, {
439
+ this.log('warn', `All ${maxAttempts} connection attempts failed url=${this.config.url}`, {
434
440
  error: lastError.message
435
441
  });
436
442
  }
@@ -606,6 +612,29 @@ export class RealTimeTwoWayWebSocketRecognitionClient
606
612
  return this.audioBuffer.isOverflowing();
607
613
  }
608
614
 
615
+ isServerReady(): boolean {
616
+ return this.state === ClientState.READY;
617
+ }
618
+
619
+ sendGameContext(context: GameContextV1): void {
620
+ if (this.state !== ClientState.CONNECTED && this.state !== ClientState.READY) {
621
+ this.log('warn', 'sendGameContext called in wrong state', { state: this.state });
622
+ return;
623
+ }
624
+
625
+ this.log('debug', 'Sending game context (deferred)', {
626
+ gameId: context.gameId,
627
+ gamePhase: context.gamePhase,
628
+ hasSlotMap: !!context.slotMap
629
+ });
630
+
631
+ super.sendMessage(
632
+ RealTimeTwoWayWebSocketRecognitionClient.PROTOCOL_VERSION,
633
+ 'message',
634
+ context
635
+ );
636
+ }
637
+
609
638
  getStats(): IRecognitionClientStats {
610
639
  const bufferStats = this.audioBuffer.getStats();
611
640
  return {
@@ -639,6 +668,9 @@ export class RealTimeTwoWayWebSocketRecognitionClient
639
668
  this.log('debug', 'Sending ASR request', this.config.asrRequestConfig);
640
669
  }
641
670
 
671
+ // Extract fallbackModels if present
672
+ const fallbackModels = (this.config.asrRequestConfig as any).fallbackModels;
673
+
642
674
  const asrRequest: ASRRequestV1 = {
643
675
  type: RecognitionContextTypeV1.ASR_REQUEST,
644
676
  audioUtteranceId: this.config.audioUtteranceId,
@@ -660,7 +692,20 @@ export class RealTimeTwoWayWebSocketRecognitionClient
660
692
  ...(this.config.asrRequestConfig.finalTranscriptStability && {
661
693
  finalTranscriptStability: this.config.asrRequestConfig.finalTranscriptStability
662
694
  }),
663
- ...(debugCommand && { debugCommand })
695
+ // Include fallbackModels if provided (for circuit breaker fallback)
696
+ ...(fallbackModels && { fallbackModels }),
697
+ ...(debugCommand && { debugCommand }),
698
+ // Include prefix mode if provided (for server-side stored prefix injection)
699
+ ...(this.config.asrRequestConfig.prefixMode && {
700
+ prefixMode: this.config.asrRequestConfig.prefixMode
701
+ }),
702
+ ...(this.config.asrRequestConfig.prefixId && {
703
+ prefixId: this.config.asrRequestConfig.prefixId
704
+ }),
705
+ // Include prefix text to remove if provided (for server-side prefix text removal)
706
+ ...(this.config.asrRequestConfig.prefixTextToRemove && {
707
+ prefixTextToRemove: this.config.asrRequestConfig.prefixTextToRemove
708
+ })
664
709
  };
665
710
 
666
711
  super.sendMessage(
@@ -791,7 +836,15 @@ export class RealTimeTwoWayWebSocketRecognitionClient
791
836
  this.state = ClientState.READY;
792
837
  this.messageHandler.setSessionStartTime(Date.now());
793
838
 
794
- // Flush buffered audio now that server is ready
839
+ // Flush buffered PREFIX audio FIRST (must be sent before user audio)
840
+ if (this.prefixBuffer.length > 0) {
841
+ this.log('debug', 'Flushing buffered prefix audio', { chunks: this.prefixBuffer.length });
842
+ this.prefixBuffer.forEach((chunk) => this.sendPrefixAudioNow(chunk));
843
+ this.prefixBuffer = [];
844
+ this.prefixBufferBytes = 0;
845
+ }
846
+
847
+ // Then flush buffered user audio
795
848
  const bufferedChunks = this.audioBuffer.flush();
796
849
  if (bufferedChunks.length > 0) {
797
850
  this.log('debug', 'Flushing buffered audio', { chunks: bufferedChunks.length });
@@ -836,4 +889,101 @@ export class RealTimeTwoWayWebSocketRecognitionClient
836
889
  this.audioBytesSent += byteLength;
837
890
  this.audioChunksSent++;
838
891
  }
892
+
893
+ /**
894
+ * Send prefix audio to the server.
895
+ * Prefix audio is sent before user audio and is used for context/priming.
896
+ * The server will process it but adjust timing so transcripts reflect user audio timing.
897
+ *
898
+ * Note: Prefix audio is buffered until READY state, then flushed before user audio.
899
+ * This ensures proper ordering even if called before server is ready.
900
+ *
901
+ * @param audioData - Prefix audio data (ArrayBuffer, ArrayBufferView, or Blob)
902
+ */
903
+ sendPrefixAudio(audioData: ArrayBuffer | ArrayBufferView | Blob): void {
904
+ // Handle Blob by converting to ArrayBuffer asynchronously
905
+ if (audioData instanceof Blob) {
906
+ blobToArrayBuffer(audioData)
907
+ .then((arrayBuffer) => {
908
+ this.sendPrefixAudioInternal(arrayBuffer);
909
+ })
910
+ .catch((error) => {
911
+ this.log('error', 'Failed to convert Blob to ArrayBuffer for prefix audio', error);
912
+ });
913
+ return;
914
+ }
915
+
916
+ // Handle ArrayBuffer and ArrayBufferView synchronously
917
+ this.sendPrefixAudioInternal(audioData);
918
+ }
919
+
920
+ /**
921
+ * Internal method to handle prefix audio with buffering
922
+ * Buffers if not READY, sends immediately if READY
923
+ */
924
+ private sendPrefixAudioInternal(audioData: ArrayBuffer | ArrayBufferView): void {
925
+ const bytes = ArrayBuffer.isView(audioData) ? audioData.byteLength : audioData.byteLength;
926
+ if (bytes === 0) return;
927
+
928
+ // Guard against stale async callbacks after cleanup (e.g., Blob conversion completing after disconnect)
929
+ if (this.state === ClientState.STOPPED || this.state === ClientState.FAILED) {
930
+ this.log('debug', 'Ignoring prefix audio in terminal state', { bytes, state: this.state });
931
+ return;
932
+ }
933
+
934
+ // Buffer if not ready, send immediately if ready
935
+ if (this.state === ClientState.READY) {
936
+ this.log('debug', 'Sending prefix audio immediately', { bytes });
937
+ this.sendPrefixAudioNow(audioData);
938
+ } else {
939
+ // Check buffer size limit to prevent OOM
940
+ if (
941
+ this.prefixBufferBytes + bytes >
942
+ RealTimeTwoWayWebSocketRecognitionClient.MAX_PREFIX_BUFFER_BYTES
943
+ ) {
944
+ this.log('warn', 'Prefix buffer limit exceeded, dropping chunk', {
945
+ bytes,
946
+ current: this.prefixBufferBytes,
947
+ max: RealTimeTwoWayWebSocketRecognitionClient.MAX_PREFIX_BUFFER_BYTES,
948
+ });
949
+ return;
950
+ }
951
+ this.log('debug', 'Buffering prefix audio until READY', { bytes, state: this.state });
952
+ this.prefixBuffer.push(audioData);
953
+ this.prefixBufferBytes += bytes;
954
+ }
955
+ }
956
+
957
+ /**
958
+ * Send prefix audio immediately to the server (without buffering)
959
+ * Uses encoding offset to mark as prefix audio
960
+ * @param audioData - Prefix audio data to send
961
+ */
962
+ private sendPrefixAudioNow(audioData: ArrayBuffer | ArrayBufferView): void {
963
+ const byteLength = ArrayBuffer.isView(audioData)
964
+ ? audioData.byteLength
965
+ : audioData.byteLength;
966
+
967
+ if (byteLength === 0) return;
968
+
969
+ const baseEncodingId = (this.config.asrRequestConfig?.encoding ||
970
+ AudioEncoding.LINEAR16) as AudioEncoding;
971
+
972
+ // Add offset to mark as prefix audio
973
+ const prefixEncodingId = baseEncodingId + PREFIX_AUDIO_ENCODING_OFFSET;
974
+
975
+ const sampleRate =
976
+ typeof this.config.asrRequestConfig?.sampleRate === 'number'
977
+ ? this.config.asrRequestConfig.sampleRate
978
+ : SampleRate.RATE_16000;
979
+
980
+ this.log('debug', 'Sending prefix audio', { bytes: byteLength, encoding: prefixEncodingId });
981
+
982
+ super.sendAudio(
983
+ audioData,
984
+ RealTimeTwoWayWebSocketRecognitionClient.PROTOCOL_VERSION,
985
+ prefixEncodingId,
986
+ sampleRate
987
+ );
988
+ }
839
989
  }
@@ -301,6 +301,28 @@ export interface IRecognitionClient {
301
301
  * @returns WebSocket URL string
302
302
  */
303
303
  getUrl(): string;
304
+
305
+ /**
306
+ * Send game context after connection is established (for preconnect flow).
307
+ *
308
+ * Preconnect flow: Create client with asrRequestConfig (useContext: true) but
309
+ * WITHOUT gameContext → call connect() → WS opens, ASRRequest sent, server
310
+ * waits in PENDING_CONTEXT → later call sendGameContext() with slotMap →
311
+ * server attaches provider and sends READY.
312
+ *
313
+ * This enables connecting early (before slotMap is known) and sending
314
+ * game context later when question data is available.
315
+ *
316
+ * @param context - Game context including slotMap for keyword boosting
317
+ */
318
+ sendGameContext(context: GameContextV1): void;
319
+
320
+ /**
321
+ * Check if server has sent READY signal (provider is connected and ready for audio).
322
+ * In preconnect flow, this becomes true after sendGameContext() triggers provider attachment.
323
+ * @returns true if server is ready to receive audio
324
+ */
325
+ isServerReady(): boolean;
304
326
  }
305
327
 
306
328
  /**
@@ -331,6 +353,7 @@ export interface IRecognitionClientStats {
331
353
  * This extends IRecognitionClientConfig and is the main configuration interface
332
354
  * for creating a new RealTimeTwoWayWebSocketRecognitionClient instance.
333
355
  */
356
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Backward compatibility alias
334
357
  export interface RealTimeTwoWayWebSocketRecognitionClientConfig extends IRecognitionClientConfig {
335
358
  // All fields are inherited from IRecognitionClientConfig
336
359
  // This interface exists for backward compatibility and clarity
@@ -19,8 +19,12 @@ import {
19
19
  TranscriptionStatus,
20
20
  RecordingStatus
21
21
  } from './vgf-recognition-state.js';
22
+ import { ClientState } from './recognition-client.types.js';
22
23
  import { AudioEncoding } from '@recog/shared-types';
23
24
 
25
+ // Track the current mock state - can be changed per test
26
+ let mockClientState: ClientState = ClientState.READY;
27
+
24
28
  // Mock the underlying client
25
29
  jest.mock('./recognition-client.js', () => {
26
30
  const mockClient = {
@@ -30,7 +34,7 @@ jest.mock('./recognition-client.js', () => {
30
34
  stopAbnormally: jest.fn(),
31
35
  getAudioUtteranceId: jest.fn().mockReturnValue('mock-uuid'),
32
36
  getUrl: jest.fn().mockReturnValue('wss://mock-url'),
33
- getState: jest.fn().mockReturnValue('IDLE'),
37
+ getState: jest.fn().mockImplementation(() => mockClientState),
34
38
  isConnected: jest.fn().mockReturnValue(true),
35
39
  isConnecting: jest.fn().mockReturnValue(false),
36
40
  isStopping: jest.fn().mockReturnValue(false),
@@ -46,6 +50,8 @@ jest.mock('./recognition-client.js', () => {
46
50
  describe('SimplifiedVGFRecognitionClient Integration - State Transitions', () => {
47
51
  beforeEach(() => {
48
52
  jest.clearAllMocks();
53
+ // Reset to default READY state
54
+ mockClientState = ClientState.READY;
49
55
  });
50
56
 
51
57
  describe('Normal Recognition Flow', () => {
@@ -238,6 +244,9 @@ describe('SimplifiedVGFRecognitionClient Integration - State Transitions', () =>
238
244
 
239
245
  describe('Early Termination with Synthetic Finalization', () => {
240
246
  it('should handle stopRecording without ever sending audio', async () => {
247
+ // Mock client in CONNECTED state (not yet READY) - synthetic finalization should trigger
248
+ mockClientState = ClientState.CONNECTED;
249
+
241
250
  let stateChangeCounter = 0;
242
251
 
243
252
  const trackingCallback = jest.fn((state: RecognitionState) => {
@@ -264,7 +273,7 @@ describe('SimplifiedVGFRecognitionClient Integration - State Transitions', () =>
264
273
  expect(currentState.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
265
274
 
266
275
  // Step 2: User calls stopRecording WITHOUT ever sending audio
267
- // SDK should emit synthetic finalization immediately
276
+ // Since client is in CONNECTED state (not READY), SDK should emit synthetic finalization
268
277
  await client.stopRecording();
269
278
 
270
279
  // Should have 2 callbacks: stopRecording (FINISHED) + synthetic finalization (FINALIZED)
@@ -282,6 +291,9 @@ describe('SimplifiedVGFRecognitionClient Integration - State Transitions', () =>
282
291
  });
283
292
 
284
293
  it('should emit synthetic finalization and suppress late server transcripts', async () => {
294
+ // Mock client in CONNECTED state (not yet READY) - synthetic finalization should trigger
295
+ mockClientState = ClientState.CONNECTED;
296
+
285
297
  let stateChangeCounter = 0;
286
298
  const stateHistory: RecognitionState[] = [];
287
299
  const loggerCalls: Array<{ level: string; message: string }> = [];
@@ -319,7 +331,7 @@ describe('SimplifiedVGFRecognitionClient Integration - State Transitions', () =>
319
331
  expect(stateChangeCounter).toBe(1);
320
332
 
321
333
  // Step 2: User calls stopRecording BEFORE any transcript received
322
- // SDK should emit synthetic finalization immediately (no waiting for server)
334
+ // Since client is in CONNECTED state (not READY), SDK should emit synthetic finalization
323
335
  await client.stopRecording();
324
336
 
325
337
  // Should have 3 callbacks: sendAudio, stopRecording (FINISHED), synthetic finalization (FINALIZED)