@volley/recognition-client-sdk 0.1.295 → 0.1.296

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.
@@ -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,EAGnB,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;gBAEjE,MAAM,EAAE,yBAAyB;IAoGvC,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;IAOpC,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,iBAAiB;CAK5B;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,EAGnB,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;gBAEjE,MAAM,EAAE,yBAAyB;IAqIvC,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;IAOpC,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,iBAAiB;CAK5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,yBAAyB,GAAG,+BAA+B,CAE5G"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volley/recognition-client-sdk",
3
- "version": "0.1.295",
3
+ "version": "0.1.296",
4
4
  "description": "Recognition Service TypeScript/Node.js Client SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -52,9 +52,9 @@
52
52
  "semantic-release": "^25.0.1",
53
53
  "ts-jest": "^29.4.5",
54
54
  "typescript": "^5.1.6",
55
- "@recog/shared-config": "1.0.0",
56
- "@recog/shared-types": "1.0.0",
57
55
  "@recog/shared-utils": "1.0.0",
56
+ "@recog/shared-types": "1.0.0",
57
+ "@recog/shared-config": "1.0.0",
58
58
  "@recog/websocket": "1.0.0"
59
59
  },
60
60
  "keywords": [
@@ -80,12 +80,18 @@ describe('SimplifiedVGFRecognitionClient', () => {
80
80
  });
81
81
 
82
82
  const state = simplifiedClient.getVGFState();
83
- expect(state.audioUtteranceId).toBe('existing-session-id');
83
+ // FINALIZED session gets new UUID to prevent server session reuse
84
+ expect(state.audioUtteranceId).not.toBe('existing-session-id');
85
+ expect(state.audioUtteranceId).toBeDefined();
86
+ // Other state preserved
84
87
  expect(state.finalTranscript).toBe('Previous transcript');
88
+ // Status reset to NOT_STARTED
89
+ expect(state.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
85
90
 
86
- // Verify audioUtteranceId was passed to underlying client
91
+ // Verify NEW audioUtteranceId was passed to underlying client
87
92
  const constructorCalls = (RealTimeTwoWayWebSocketRecognitionClient as jest.MockedClass<typeof RealTimeTwoWayWebSocketRecognitionClient>).mock.calls;
88
- expect(constructorCalls[0]?.[0]?.audioUtteranceId).toBe('existing-session-id');
93
+ expect(constructorCalls[0]?.[0]?.audioUtteranceId).not.toBe('existing-session-id');
94
+ expect(constructorCalls[0]?.[0]?.audioUtteranceId).toBe(state.audioUtteranceId);
89
95
  });
90
96
 
91
97
  it('should store ASR config as JSON string', () => {
@@ -528,6 +534,101 @@ describe('SimplifiedVGFRecognitionClient', () => {
528
534
  expect(client.getVGFState).toBeDefined();
529
535
  expect(client.connect).toBeDefined();
530
536
  });
537
+
538
+ it('should auto-generate new UUID for ABORTED session and reset fields', () => {
539
+ const stateChangeCallback = jest.fn();
540
+ const abortedState: RecognitionState = {
541
+ audioUtteranceId: 'old-aborted-uuid',
542
+ transcriptionStatus: TranscriptionStatus.ABORTED,
543
+ startRecordingStatus: RecordingStatus.FINISHED,
544
+ pendingTranscript: '',
545
+ finalTranscript: 'old transcript from aborted session'
546
+ };
547
+
548
+ const client = createSimplifiedVGFClient({
549
+ initialState: abortedState,
550
+ onStateChange: stateChangeCallback,
551
+ asrRequestConfig: {
552
+ provider: 'deepgram',
553
+ language: 'en',
554
+ sampleRate: 16000,
555
+ encoding: AudioEncoding.LINEAR16
556
+ }
557
+ });
558
+
559
+ // Should have called callback with new UUID
560
+ expect(stateChangeCallback).toHaveBeenCalledTimes(1);
561
+ const newState = stateChangeCallback.mock.calls[0][0];
562
+
563
+ // New UUID should be different
564
+ expect(newState.audioUtteranceId).not.toBe('old-aborted-uuid');
565
+ expect(newState.audioUtteranceId).toBeDefined();
566
+
567
+ // Status fields should be reset for fresh session
568
+ expect(newState.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
569
+ expect(newState.startRecordingStatus).toBe(RecordingStatus.READY);
570
+
571
+ // Previous transcript should be cleared
572
+ expect(newState.finalTranscript).toBeUndefined();
573
+
574
+ // Client should use the new UUID
575
+ expect(client.getVGFState().audioUtteranceId).toBe(newState.audioUtteranceId);
576
+ });
577
+
578
+ it('should auto-generate new UUID for FINALIZED session', () => {
579
+ const stateChangeCallback = jest.fn();
580
+ const finalizedState: RecognitionState = {
581
+ audioUtteranceId: 'old-finalized-uuid',
582
+ transcriptionStatus: TranscriptionStatus.FINALIZED,
583
+ startRecordingStatus: RecordingStatus.FINISHED,
584
+ pendingTranscript: '',
585
+ finalTranscript: 'completed transcript'
586
+ };
587
+
588
+ const client = createSimplifiedVGFClient({
589
+ initialState: finalizedState,
590
+ onStateChange: stateChangeCallback,
591
+ asrRequestConfig: {
592
+ provider: 'deepgram',
593
+ language: 'en',
594
+ sampleRate: 16000,
595
+ encoding: AudioEncoding.LINEAR16
596
+ }
597
+ });
598
+
599
+ // Should have generated new UUID
600
+ expect(stateChangeCallback).toHaveBeenCalledTimes(1);
601
+ const newState = stateChangeCallback.mock.calls[0][0];
602
+
603
+ expect(newState.audioUtteranceId).not.toBe('old-finalized-uuid');
604
+ expect(newState.transcriptionStatus).toBe(TranscriptionStatus.NOT_STARTED);
605
+ });
606
+
607
+ it('should preserve UUID for IN_PROGRESS session (valid resumption)', () => {
608
+ const stateChangeCallback = jest.fn();
609
+ const inProgressState: RecognitionState = {
610
+ audioUtteranceId: 'in-progress-uuid',
611
+ transcriptionStatus: TranscriptionStatus.IN_PROGRESS,
612
+ startRecordingStatus: RecordingStatus.RECORDING,
613
+ pendingTranscript: 'partial text'
614
+ };
615
+
616
+ const client = createSimplifiedVGFClient({
617
+ initialState: inProgressState,
618
+ onStateChange: stateChangeCallback,
619
+ asrRequestConfig: {
620
+ provider: 'deepgram',
621
+ language: 'en',
622
+ sampleRate: 16000,
623
+ encoding: AudioEncoding.LINEAR16
624
+ }
625
+ });
626
+
627
+ // Should NOT generate new UUID (valid reconnection)
628
+ const currentState = client.getVGFState();
629
+ expect(currentState.audioUtteranceId).toBe('in-progress-uuid');
630
+ expect(currentState.transcriptionStatus).toBe(TranscriptionStatus.IN_PROGRESS);
631
+ });
531
632
  });
532
633
 
533
634
  describe('PromptSlotMap Integration', () => {
@@ -734,6 +835,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
734
835
  expect(stateChangeCallback).toHaveBeenCalledTimes(1);
735
836
 
736
837
  const firstCallState = stateChangeCallback.mock.calls[0][0];
838
+ const firstTranscript = firstCallState.finalTranscript;
737
839
  jest.clearAllMocks();
738
840
 
739
841
  // Call stopAbnormally second time
@@ -744,7 +846,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
744
846
 
745
847
  const currentState = simplifiedClient.getVGFState();
746
848
  expect(currentState.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
747
- expect(currentState.finalTranscript).toBe('');
849
+ expect(currentState.finalTranscript).toBe(firstTranscript); // Unchanged
748
850
  });
749
851
 
750
852
  it('should work even if called before any recording', () => {
@@ -753,7 +855,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
753
855
 
754
856
  const state = simplifiedClient.getVGFState();
755
857
  expect(state.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
756
- expect(state.finalTranscript).toBe('');
858
+ expect(state.finalTranscript).toBeUndefined(); // No transcript was ever received
757
859
  expect(state.startRecordingStatus).toBe(RecordingStatus.FINISHED);
758
860
  });
759
861
 
@@ -853,7 +955,7 @@ describe('SimplifiedVGFRecognitionClient', () => {
853
955
  // Verify ABORTED is used (not FINALIZED)
854
956
  expect(abortedState.transcriptionStatus).toBe(TranscriptionStatus.ABORTED);
855
957
  expect(abortedState.transcriptionStatus).not.toBe(TranscriptionStatus.FINALIZED);
856
- expect(abortedState.finalTranscript).toBe(''); // Empty because cancelled
958
+ // finalTranscript is preserved (whatever partial transcript was received)
857
959
 
858
960
  // ABORTED clearly indicates user cancelled, vs FINALIZED which means completed normally
859
961
  });
@@ -157,10 +157,43 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
157
157
 
158
158
  // Use provided initial state or create from config
159
159
  if (initialState) {
160
- this.state = initialState;
161
- // Override audioUtteranceId in config if state has one
162
- if (initialState.audioUtteranceId && !clientConfig.audioUtteranceId) {
163
- clientConfig.audioUtteranceId = initialState.audioUtteranceId;
160
+ // If previous session is in terminal state (ABORTED/FINALIZED), force new UUID
161
+ // This prevents server from attaching to completed session which silently drops audio
162
+ if (initialState.transcriptionStatus === TranscriptionStatus.ABORTED ||
163
+ initialState.transcriptionStatus === TranscriptionStatus.FINALIZED) {
164
+
165
+ // Generate new UUID for fresh session
166
+ const newUUID = crypto.randomUUID();
167
+
168
+ if (clientConfig.logger) {
169
+ clientConfig.logger('info', `Terminal session detected (${initialState.transcriptionStatus}), generating new UUID: ${newUUID}`);
170
+ }
171
+
172
+ // Update state with new UUID and reset session-specific fields
173
+ this.state = {
174
+ ...initialState,
175
+ audioUtteranceId: newUUID,
176
+ // Reset status fields for fresh session
177
+ transcriptionStatus: TranscriptionStatus.NOT_STARTED,
178
+ startRecordingStatus: RecordingStatus.READY,
179
+ // Clear previous session's transcript
180
+ finalTranscript: undefined
181
+ };
182
+
183
+ // Use new UUID in client config
184
+ clientConfig.audioUtteranceId = newUUID;
185
+
186
+ // Notify state change immediately so app can update
187
+ if (onStateChange) {
188
+ onStateChange(this.state);
189
+ }
190
+ } else {
191
+ // Non-terminal state - safe to reuse UUID (e.g., reconnecting to IN_PROGRESS session)
192
+ this.state = initialState;
193
+ // Override audioUtteranceId in config if state has one
194
+ if (initialState.audioUtteranceId && !clientConfig.audioUtteranceId) {
195
+ clientConfig.audioUtteranceId = initialState.audioUtteranceId;
196
+ }
164
197
  }
165
198
  } else {
166
199
  // Initialize VGF state from config