@volley/recognition-client-sdk 0.1.385 → 0.1.417
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/browser.bundled.d.ts +23 -1
- package/dist/config-builder.d.ts +5 -0
- package/dist/config-builder.d.ts.map +1 -1
- package/dist/index.bundled.d.ts +108 -79
- package/dist/index.js +122 -30
- package/dist/index.js.map +4 -4
- package/dist/recog-client-sdk.browser.js +62 -23
- package/dist/recog-client-sdk.browser.js.map +4 -4
- package/dist/recognition-client.d.ts.map +1 -1
- package/dist/recognition-client.types.d.ts +6 -0
- package/dist/recognition-client.types.d.ts.map +1 -1
- package/dist/simplified-vgf-recognition-client.d.ts +2 -0
- package/dist/simplified-vgf-recognition-client.d.ts.map +1 -1
- package/dist/utils/url-builder.d.ts +2 -0
- package/dist/utils/url-builder.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/config-builder.ts +9 -0
- package/src/recognition-client.ts +3 -2
- package/src/recognition-client.types.ts +7 -0
- package/src/simplified-vgf-recognition-client.integration.spec.ts +704 -0
- package/src/simplified-vgf-recognition-client.spec.ts +199 -13
- package/src/simplified-vgf-recognition-client.ts +70 -10
- package/src/utils/audio-ring-buffer.ts +2 -2
- package/src/utils/message-handler.ts +4 -4
- package/src/utils/url-builder.ts +10 -3
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { SimplifiedVGFRecognitionClient, createSimplifiedVGFClient } from './simplified-vgf-recognition-client.js';
|
|
6
6
|
import { RealTimeTwoWayWebSocketRecognitionClient } from './recognition-client.js';
|
|
7
7
|
import { ClientState } from './recognition-client.types.js';
|
|
8
|
-
import { AudioEncoding, RecognitionContextTypeV1 } from '@recog/shared-types';
|
|
8
|
+
import { AudioEncoding, RecognitionContextTypeV1, RecognitionResultTypeV1 } from '@recog/shared-types';
|
|
9
9
|
import {
|
|
10
10
|
RecordingStatus,
|
|
11
11
|
TranscriptionStatus,
|
|
@@ -287,21 +287,43 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
287
287
|
expect(updatedState.finalTranscriptionTimestamp).toBeDefined();
|
|
288
288
|
});
|
|
289
289
|
|
|
290
|
-
it('should
|
|
290
|
+
it('should pass metadata to callback without updating VGF state', () => {
|
|
291
291
|
// Get the actual UUID from the client
|
|
292
292
|
const actualUuid = simplifiedClient.getVGFState().audioUtteranceId;
|
|
293
|
+
const originalOnMetadata = jest.fn();
|
|
293
294
|
|
|
295
|
+
// Create new client with onMetadata callback
|
|
296
|
+
const clientWithMetadata = new SimplifiedVGFRecognitionClient({
|
|
297
|
+
asrRequestConfig: {
|
|
298
|
+
provider: 'deepgram',
|
|
299
|
+
language: 'en',
|
|
300
|
+
sampleRate: 16000,
|
|
301
|
+
encoding: AudioEncoding.LINEAR16
|
|
302
|
+
},
|
|
303
|
+
onStateChange: stateChangeCallback,
|
|
304
|
+
onMetadata: originalOnMetadata
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const constructorCalls = (RealTimeTwoWayWebSocketRecognitionClient as jest.MockedClass<typeof RealTimeTwoWayWebSocketRecognitionClient>).mock.calls;
|
|
308
|
+
const latestConfig = constructorCalls[constructorCalls.length - 1]?.[0];
|
|
309
|
+
const metadataCallback = latestConfig?.onMetadata;
|
|
310
|
+
|
|
311
|
+
const clientUuid = clientWithMetadata.getVGFState().audioUtteranceId;
|
|
294
312
|
const metadata = {
|
|
295
|
-
|
|
296
|
-
|
|
313
|
+
type: RecognitionResultTypeV1.METADATA as const,
|
|
314
|
+
audioUtteranceId: clientUuid
|
|
297
315
|
};
|
|
298
316
|
|
|
299
|
-
|
|
317
|
+
// Clear previous state changes from client creation
|
|
318
|
+
stateChangeCallback.mockClear();
|
|
300
319
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
expect(
|
|
320
|
+
metadataCallback?.(metadata);
|
|
321
|
+
|
|
322
|
+
// Metadata should NOT trigger state change (state management simplified)
|
|
323
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
324
|
+
|
|
325
|
+
// But original callback should still be called
|
|
326
|
+
expect(originalOnMetadata).toHaveBeenCalledWith(metadata);
|
|
305
327
|
});
|
|
306
328
|
|
|
307
329
|
it('should handle errors and update state', () => {
|
|
@@ -325,13 +347,18 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
325
347
|
// Then error occurs
|
|
326
348
|
onErrorCallback({ message: 'Error' });
|
|
327
349
|
|
|
328
|
-
//
|
|
350
|
+
// After terminal status (ERROR), no more state changes should be emitted
|
|
351
|
+
// The session is considered over, so sendAudio should not trigger callbacks
|
|
329
352
|
stateChangeCallback.mockClear();
|
|
330
353
|
simplifiedClient.sendAudio(Buffer.from([4, 5, 6]));
|
|
331
354
|
|
|
332
|
-
|
|
333
|
-
expect(
|
|
334
|
-
|
|
355
|
+
// No callback should be triggered since we're in terminal state
|
|
356
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
357
|
+
|
|
358
|
+
// However, the internal isRecordingAudio flag should still be reset
|
|
359
|
+
// (verified by the fact that the flag was set during the first sendAudio)
|
|
360
|
+
const state = simplifiedClient.getVGFState();
|
|
361
|
+
expect(state.transcriptionStatus).toBe(TranscriptionStatus.ERROR);
|
|
335
362
|
});
|
|
336
363
|
});
|
|
337
364
|
|
|
@@ -1331,4 +1358,163 @@ describe('SimplifiedVGFRecognitionClient', () => {
|
|
|
1331
1358
|
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
1332
1359
|
});
|
|
1333
1360
|
});
|
|
1361
|
+
|
|
1362
|
+
describe('Terminal Status Protection', () => {
|
|
1363
|
+
let stateChangeCallback: jest.Mock;
|
|
1364
|
+
let onTranscriptCallback: (result: any) => void;
|
|
1365
|
+
let onErrorCallback: (error: any) => void;
|
|
1366
|
+
let simplifiedClient: SimplifiedVGFRecognitionClient;
|
|
1367
|
+
let clientUuid: string;
|
|
1368
|
+
|
|
1369
|
+
beforeEach(() => {
|
|
1370
|
+
stateChangeCallback = jest.fn();
|
|
1371
|
+
simplifiedClient = new SimplifiedVGFRecognitionClient({
|
|
1372
|
+
asrRequestConfig: {
|
|
1373
|
+
provider: 'deepgram',
|
|
1374
|
+
language: 'en',
|
|
1375
|
+
sampleRate: 16000,
|
|
1376
|
+
encoding: AudioEncoding.LINEAR16
|
|
1377
|
+
},
|
|
1378
|
+
onStateChange: stateChangeCallback
|
|
1379
|
+
});
|
|
1380
|
+
|
|
1381
|
+
const constructorCalls = (RealTimeTwoWayWebSocketRecognitionClient as jest.MockedClass<typeof RealTimeTwoWayWebSocketRecognitionClient>).mock.calls;
|
|
1382
|
+
const latestConfig = constructorCalls[constructorCalls.length - 1]?.[0];
|
|
1383
|
+
onTranscriptCallback = latestConfig?.onTranscript ?? jest.fn();
|
|
1384
|
+
onErrorCallback = latestConfig?.onError ?? jest.fn();
|
|
1385
|
+
clientUuid = simplifiedClient.getVGFState().audioUtteranceId;
|
|
1386
|
+
});
|
|
1387
|
+
|
|
1388
|
+
it('should allow first terminal transcript callback', () => {
|
|
1389
|
+
onTranscriptCallback({
|
|
1390
|
+
type: 'Transcription',
|
|
1391
|
+
audioUtteranceId: clientUuid,
|
|
1392
|
+
finalTranscript: 'hello',
|
|
1393
|
+
finalTranscriptConfidence: 0.9,
|
|
1394
|
+
is_finished: true
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
expect(stateChangeCallback).toHaveBeenCalledTimes(1);
|
|
1398
|
+
expect(stateChangeCallback.mock.calls[0][0].transcriptionStatus).toBe(TranscriptionStatus.FINALIZED);
|
|
1399
|
+
});
|
|
1400
|
+
|
|
1401
|
+
it('should block second terminal transcript callback with same UUID', () => {
|
|
1402
|
+
// First terminal
|
|
1403
|
+
onTranscriptCallback({
|
|
1404
|
+
type: 'Transcription',
|
|
1405
|
+
audioUtteranceId: clientUuid,
|
|
1406
|
+
finalTranscript: 'first',
|
|
1407
|
+
finalTranscriptConfidence: 0.9,
|
|
1408
|
+
is_finished: true
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
stateChangeCallback.mockClear();
|
|
1412
|
+
|
|
1413
|
+
// Second terminal - should be blocked
|
|
1414
|
+
onTranscriptCallback({
|
|
1415
|
+
type: 'Transcription',
|
|
1416
|
+
audioUtteranceId: clientUuid,
|
|
1417
|
+
finalTranscript: 'second',
|
|
1418
|
+
finalTranscriptConfidence: 0.95,
|
|
1419
|
+
is_finished: true
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
it('should allow first error callback', () => {
|
|
1426
|
+
onErrorCallback({
|
|
1427
|
+
audioUtteranceId: clientUuid,
|
|
1428
|
+
message: 'Error occurred'
|
|
1429
|
+
});
|
|
1430
|
+
|
|
1431
|
+
expect(stateChangeCallback).toHaveBeenCalledTimes(1);
|
|
1432
|
+
expect(stateChangeCallback.mock.calls[0][0].transcriptionStatus).toBe(TranscriptionStatus.ERROR);
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
it('should block second error callback with same UUID', () => {
|
|
1436
|
+
// First error
|
|
1437
|
+
onErrorCallback({
|
|
1438
|
+
audioUtteranceId: clientUuid,
|
|
1439
|
+
message: 'First error'
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
stateChangeCallback.mockClear();
|
|
1443
|
+
|
|
1444
|
+
// Second error - should be blocked
|
|
1445
|
+
onErrorCallback({
|
|
1446
|
+
audioUtteranceId: clientUuid,
|
|
1447
|
+
message: 'Second error'
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1450
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
it('should block transcript after error', () => {
|
|
1454
|
+
// Error first
|
|
1455
|
+
onErrorCallback({
|
|
1456
|
+
audioUtteranceId: clientUuid,
|
|
1457
|
+
message: 'Error'
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
stateChangeCallback.mockClear();
|
|
1461
|
+
|
|
1462
|
+
// Transcript after error - should be blocked
|
|
1463
|
+
onTranscriptCallback({
|
|
1464
|
+
type: 'Transcription',
|
|
1465
|
+
audioUtteranceId: clientUuid,
|
|
1466
|
+
finalTranscript: 'late',
|
|
1467
|
+
finalTranscriptConfidence: 0.9,
|
|
1468
|
+
is_finished: true
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
1472
|
+
});
|
|
1473
|
+
|
|
1474
|
+
it('should block error after terminal transcript', () => {
|
|
1475
|
+
// Terminal transcript first
|
|
1476
|
+
onTranscriptCallback({
|
|
1477
|
+
type: 'Transcription',
|
|
1478
|
+
audioUtteranceId: clientUuid,
|
|
1479
|
+
finalTranscript: 'done',
|
|
1480
|
+
finalTranscriptConfidence: 0.9,
|
|
1481
|
+
is_finished: true
|
|
1482
|
+
});
|
|
1483
|
+
|
|
1484
|
+
stateChangeCallback.mockClear();
|
|
1485
|
+
|
|
1486
|
+
// Error after terminal - should be blocked
|
|
1487
|
+
onErrorCallback({
|
|
1488
|
+
audioUtteranceId: clientUuid,
|
|
1489
|
+
message: 'Late error'
|
|
1490
|
+
});
|
|
1491
|
+
|
|
1492
|
+
expect(stateChangeCallback).not.toHaveBeenCalled();
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1495
|
+
it('should preserve original state after blocking duplicate', () => {
|
|
1496
|
+
// First terminal with specific transcript
|
|
1497
|
+
onTranscriptCallback({
|
|
1498
|
+
type: 'Transcription',
|
|
1499
|
+
audioUtteranceId: clientUuid,
|
|
1500
|
+
finalTranscript: 'original',
|
|
1501
|
+
finalTranscriptConfidence: 0.85,
|
|
1502
|
+
is_finished: true
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1505
|
+
// Attempt second terminal with different transcript
|
|
1506
|
+
onTranscriptCallback({
|
|
1507
|
+
type: 'Transcription',
|
|
1508
|
+
audioUtteranceId: clientUuid,
|
|
1509
|
+
finalTranscript: 'different',
|
|
1510
|
+
finalTranscriptConfidence: 0.99,
|
|
1511
|
+
is_finished: true
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
// State should still have original values
|
|
1515
|
+
const state = simplifiedClient.getVGFState();
|
|
1516
|
+
expect(state.finalTranscript).toBe('original');
|
|
1517
|
+
expect(state.finalConfidence).toBe(0.85);
|
|
1518
|
+
});
|
|
1519
|
+
});
|
|
1334
1520
|
});
|
|
@@ -153,6 +153,7 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
153
153
|
private stateChangeCallback: ((state: RecognitionState) => void) | undefined;
|
|
154
154
|
private expectedUuid: string;
|
|
155
155
|
private logger: IRecognitionClientConfig['logger'];
|
|
156
|
+
private lastSentTerminalUuid: string | null = null;
|
|
156
157
|
|
|
157
158
|
constructor(config: SimplifiedVGFClientConfig) {
|
|
158
159
|
const { onStateChange, initialState, ...clientConfig } = config;
|
|
@@ -192,6 +193,9 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
192
193
|
// Use new UUID in client config
|
|
193
194
|
clientConfig.audioUtteranceId = newUUID;
|
|
194
195
|
|
|
196
|
+
// Reset terminal status tracking for new session
|
|
197
|
+
this.lastSentTerminalUuid = null;
|
|
198
|
+
|
|
195
199
|
// Notify state change immediately so app can update
|
|
196
200
|
if (onStateChange) {
|
|
197
201
|
onStateChange(this.state);
|
|
@@ -245,12 +249,19 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
245
249
|
if (result.audioUtteranceId && result.audioUtteranceId !== this.expectedUuid) {
|
|
246
250
|
if (this.logger) {
|
|
247
251
|
this.logger('warn',
|
|
248
|
-
`[VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
|
|
252
|
+
`[RecogSDK:VGF] Skipping transcript update: UUID mismatch (expected: ${this.expectedUuid}, got: ${result.audioUtteranceId})`
|
|
249
253
|
);
|
|
250
254
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Skip if terminal status already sent for THIS session
|
|
259
|
+
// (If lastSentTerminalUuid exists but doesn't match expectedUuid, treat as new session)
|
|
260
|
+
if (this.lastSentTerminalUuid === this.expectedUuid) {
|
|
261
|
+
if (this.logger) {
|
|
262
|
+
this.logger('info',
|
|
263
|
+
`[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
|
|
264
|
+
);
|
|
254
265
|
}
|
|
255
266
|
return;
|
|
256
267
|
}
|
|
@@ -270,7 +281,7 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
270
281
|
if (metadata.audioUtteranceId && metadata.audioUtteranceId !== this.expectedUuid) {
|
|
271
282
|
if (this.logger) {
|
|
272
283
|
this.logger('warn',
|
|
273
|
-
`[VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
|
|
284
|
+
`[RecogSDK:VGF] Skipping metadata update: UUID mismatch (expected: ${this.expectedUuid}, got: ${metadata.audioUtteranceId})`
|
|
274
285
|
);
|
|
275
286
|
}
|
|
276
287
|
return;
|
|
@@ -293,12 +304,17 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
293
304
|
if (error.audioUtteranceId && error.audioUtteranceId !== this.expectedUuid) {
|
|
294
305
|
if (this.logger) {
|
|
295
306
|
this.logger('warn',
|
|
296
|
-
`[VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
|
|
307
|
+
`[RecogSDK:VGF] Skipping error update: UUID mismatch (expected: ${this.expectedUuid}, got: ${error.audioUtteranceId})`
|
|
297
308
|
);
|
|
298
309
|
}
|
|
299
310
|
return;
|
|
300
311
|
}
|
|
301
312
|
|
|
313
|
+
// Skip if terminal status already sent for THIS session
|
|
314
|
+
if (this.lastSentTerminalUuid === this.expectedUuid) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
|
|
302
318
|
this.isRecordingAudio = false; // Reset on error
|
|
303
319
|
this.state = mapErrorToState(this.state, error);
|
|
304
320
|
this.notifyStateChange();
|
|
@@ -350,6 +366,27 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
350
366
|
this.isRecordingAudio = false;
|
|
351
367
|
this.state = updateStateOnStop(this.state);
|
|
352
368
|
this.notifyStateChange();
|
|
369
|
+
|
|
370
|
+
// Early termination: If transcription never started (NOT_STARTED), emit synthetic finalization immediately
|
|
371
|
+
// This prevents games from getting stuck waiting for a server response that may never come
|
|
372
|
+
if (this.state.transcriptionStatus === TranscriptionStatus.NOT_STARTED) {
|
|
373
|
+
if (this.logger) {
|
|
374
|
+
this.logger('info',
|
|
375
|
+
`[RecogSDK:VGF] Early termination detected (transcriptionStatus: NOT_STARTED) - emitting synthetic finalization`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
this.state = {
|
|
379
|
+
...this.state,
|
|
380
|
+
transcriptionStatus: TranscriptionStatus.FINALIZED,
|
|
381
|
+
finalTranscript: '',
|
|
382
|
+
finalConfidence: 0,
|
|
383
|
+
pendingTranscript: '',
|
|
384
|
+
pendingConfidence: undefined,
|
|
385
|
+
finalTranscriptionTimestamp: new Date().toISOString()
|
|
386
|
+
};
|
|
387
|
+
this.notifyStateChange();
|
|
388
|
+
}
|
|
389
|
+
|
|
353
390
|
await this.client.stopRecording();
|
|
354
391
|
}
|
|
355
392
|
|
|
@@ -424,11 +461,34 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
424
461
|
return { ...this.state };
|
|
425
462
|
}
|
|
426
463
|
|
|
464
|
+
private isTerminalStatus(status: string | undefined): boolean {
|
|
465
|
+
return status === TranscriptionStatus.FINALIZED ||
|
|
466
|
+
status === TranscriptionStatus.ABORTED ||
|
|
467
|
+
status === TranscriptionStatus.ERROR;
|
|
468
|
+
}
|
|
469
|
+
|
|
427
470
|
private notifyStateChange(): void {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
471
|
+
|
|
472
|
+
// Block duplicate terminal status emissions for THIS session
|
|
473
|
+
if (this.isTerminalStatus(this.state.transcriptionStatus)) {
|
|
474
|
+
if (this.lastSentTerminalUuid === this.expectedUuid) {
|
|
475
|
+
// Already sent a terminal status for this session - suppress duplicate
|
|
476
|
+
if (this.logger) {
|
|
477
|
+
this.logger('info',
|
|
478
|
+
`[RecogSDK:VGF] Duplicate terminal status suppressed (lastSentTerminalUuid: ${this.lastSentTerminalUuid})`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
// First terminal status for this session - record it
|
|
484
|
+
this.lastSentTerminalUuid = this.expectedUuid;
|
|
431
485
|
}
|
|
486
|
+
|
|
487
|
+
if (!this.stateChangeCallback) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
this.stateChangeCallback({ ...this.state });
|
|
432
492
|
}
|
|
433
493
|
}
|
|
434
494
|
|
|
@@ -477,4 +537,4 @@ export class SimplifiedVGFRecognitionClient implements ISimplifiedVGFRecognition
|
|
|
477
537
|
*/
|
|
478
538
|
export function createSimplifiedVGFClient(config: SimplifiedVGFClientConfig): ISimplifiedVGFRecognitionClient {
|
|
479
539
|
return new SimplifiedVGFRecognitionClient(config);
|
|
480
|
-
}
|
|
540
|
+
}
|
|
@@ -55,7 +55,7 @@ export class AudioRingBuffer {
|
|
|
55
55
|
|
|
56
56
|
// Log buffer overflow event
|
|
57
57
|
if (this.logger) {
|
|
58
|
-
this.logger('debug', 'Buffer overflow detected', {
|
|
58
|
+
this.logger('debug', '[RecogSDK] Buffer overflow detected', {
|
|
59
59
|
bufferSize: this.bufferSize,
|
|
60
60
|
totalOverflows: this.overflowCount,
|
|
61
61
|
droppedChunk: this.buffer[this.readIndex]?.timestamp
|
|
@@ -151,7 +151,7 @@ export class AudioRingBuffer {
|
|
|
151
151
|
this.totalBufferedBytes = 0;
|
|
152
152
|
|
|
153
153
|
if (this.logger) {
|
|
154
|
-
this.logger('debug', 'Audio buffer cleared');
|
|
154
|
+
this.logger('debug', '[RecogSDK] Audio buffer cleared');
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -44,7 +44,7 @@ export class MessageHandler {
|
|
|
44
44
|
handleMessage(msg: { v: number; type: string; data: any }): void {
|
|
45
45
|
// Log ALL incoming messages for debugging
|
|
46
46
|
if (this.callbacks.logger) {
|
|
47
|
-
this.callbacks.logger('debug', 'Received WebSocket message', {
|
|
47
|
+
this.callbacks.logger('debug', '[RecogSDK] Received WebSocket message', {
|
|
48
48
|
msgType: msg.type,
|
|
49
49
|
msgDataType: msg.data && typeof msg.data === 'object' && 'type' in msg.data ? msg.data.type : 'N/A',
|
|
50
50
|
fullMessage: msg
|
|
@@ -55,7 +55,7 @@ export class MessageHandler {
|
|
|
55
55
|
// Log error if we receive primitive data (indicates server issue)
|
|
56
56
|
if (msg.data && typeof msg.data !== 'object') {
|
|
57
57
|
if (this.callbacks.logger) {
|
|
58
|
-
this.callbacks.logger('error', 'Received primitive msg.data from server', {
|
|
58
|
+
this.callbacks.logger('error', '[RecogSDK] Received primitive msg.data from server', {
|
|
59
59
|
dataType: typeof msg.data,
|
|
60
60
|
data: msg.data,
|
|
61
61
|
fullMessage: msg
|
|
@@ -90,7 +90,7 @@ export class MessageHandler {
|
|
|
90
90
|
default:
|
|
91
91
|
// Unknown message type - log if logger available
|
|
92
92
|
if (this.callbacks.logger) {
|
|
93
|
-
this.callbacks.logger('debug', 'Unknown message type', { type: msgType });
|
|
93
|
+
this.callbacks.logger('debug', '[RecogSDK] Unknown message type', { type: msgType });
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -106,7 +106,7 @@ export class MessageHandler {
|
|
|
106
106
|
const timeToFirstTranscript = this.firstTranscriptTime - this.sessionStartTime;
|
|
107
107
|
|
|
108
108
|
if (this.callbacks.logger) {
|
|
109
|
-
this.callbacks.logger('debug', 'First transcript received', {
|
|
109
|
+
this.callbacks.logger('debug', '[RecogSDK] First transcript received', {
|
|
110
110
|
timeToFirstTranscriptMs: timeToFirstTranscript
|
|
111
111
|
});
|
|
112
112
|
}
|
package/src/utils/url-builder.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface UrlBuilderConfig {
|
|
|
19
19
|
questionAnswerId?: string;
|
|
20
20
|
platform?: string;
|
|
21
21
|
gameContext?: GameContextV1;
|
|
22
|
+
/** Standalone gameId - takes precedence over gameContext.gameId if both provided */
|
|
23
|
+
gameId?: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
@@ -75,9 +77,14 @@ export function buildWebSocketUrl(config: UrlBuilderConfig): string {
|
|
|
75
77
|
url.searchParams.set('platform', config.platform);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
// Add gameId
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// Add gameId - standalone gameId takes precedence over gameContext.gameId
|
|
81
|
+
const gameId = config.gameId ?? config.gameContext?.gameId;
|
|
82
|
+
if (gameId) {
|
|
83
|
+
url.searchParams.set('gameId', gameId);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Add gamePhase from gameContext if provided
|
|
87
|
+
if (config.gameContext?.gamePhase) {
|
|
81
88
|
url.searchParams.set('gamePhase', config.gameContext.gamePhase);
|
|
82
89
|
}
|
|
83
90
|
|