@wix/legends-platform-sdk 1.25.0 → 1.27.0
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/README.md +2 -2
- package/dist/cjs/conversation/types.js.map +1 -1
- package/dist/cjs/hooks/useConversation/livekit/useConversation.js +34 -16
- package/dist/cjs/hooks/useConversation/livekit/useConversation.js.map +1 -1
- package/dist/cjs/hooks/useConversation/livekit/utils/dataChannel.js +4 -0
- package/dist/cjs/hooks/useConversation/livekit/utils/dataChannel.js.map +1 -1
- package/dist/cjs/hooks/useConversationEvents/types.js.map +1 -1
- package/dist/cjs/hooks/useTextChat/streamChatMessage.js +18 -1
- package/dist/cjs/hooks/useTextChat/streamChatMessage.js.map +1 -1
- package/dist/cjs/hooks/useTextChat/useTextChatStream.js +5 -2
- package/dist/cjs/hooks/useTextChat/useTextChatStream.js.map +1 -1
- package/dist/esm/conversation/types.js.map +1 -1
- package/dist/esm/hooks/useConversation/livekit/useConversation.js +35 -17
- package/dist/esm/hooks/useConversation/livekit/useConversation.js.map +1 -1
- package/dist/esm/hooks/useConversation/livekit/utils/dataChannel.js +3 -0
- package/dist/esm/hooks/useConversation/livekit/utils/dataChannel.js.map +1 -1
- package/dist/esm/hooks/useConversationEvents/types.js.map +1 -1
- package/dist/esm/hooks/useTextChat/streamChatMessage.js +17 -1
- package/dist/esm/hooks/useTextChat/streamChatMessage.js.map +1 -1
- package/dist/esm/hooks/useTextChat/useTextChatStream.js +5 -2
- package/dist/esm/hooks/useTextChat/useTextChatStream.js.map +1 -1
- package/dist/types/conversation/types.d.ts +1 -1
- package/dist/types/conversation/types.d.ts.map +1 -1
- package/dist/types/hooks/useConversation/livekit/useConversation.d.ts.map +1 -1
- package/dist/types/hooks/useConversation/livekit/utils/dataChannel.d.ts +1 -0
- package/dist/types/hooks/useConversation/livekit/utils/dataChannel.d.ts.map +1 -1
- package/dist/types/hooks/useConversationEvents/types.d.ts +4 -0
- package/dist/types/hooks/useConversationEvents/types.d.ts.map +1 -1
- package/dist/types/hooks/useTextChat/streamChatMessage.d.ts +2 -0
- package/dist/types/hooks/useTextChat/streamChatMessage.d.ts.map +1 -1
- package/dist/types/hooks/useTextChat/useTextChatStream.d.ts +1 -0
- package/dist/types/hooks/useTextChat/useTextChatStream.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ const { status, join, leave } = useConversation({
|
|
|
105
105
|
|
|
106
106
|
| Return | Type | Description |
|
|
107
107
|
|--------|------|-------------|
|
|
108
|
-
| `status` | `'pending' \| 'created' \| 'destroying' \| 'destroyed' \| 'exceeded' \| 'inactivity-timeout' \| 'voice-not-found' \| 'initialization-error' \| 'error'` | Current conversation state |
|
|
108
|
+
| `status` | `'pending' \| 'created' \| 'destroying' \| 'destroyed' \| 'exceeded' \| 'inactivity-timeout' \| 'credit-exhausted' \| 'voice-not-found' \| 'initialization-error' \| 'error'` | Current conversation state |
|
|
109
109
|
| `join()` | `() => void` | Start the conversation |
|
|
110
110
|
| `leave()` | `(destroy?: boolean) => Promise<void>` | End the conversation |
|
|
111
111
|
|
|
@@ -157,7 +157,7 @@ const result = await send({ message: 'Hello' });
|
|
|
157
157
|
```tsx
|
|
158
158
|
const status = useConversationStatus();
|
|
159
159
|
// 'pending' | 'created' | 'destroying' | 'destroyed' | 'exceeded'
|
|
160
|
-
// | 'inactivity-timeout' | 'voice-not-found' | 'initialization-error' | 'error'
|
|
160
|
+
// | 'inactivity-timeout' | 'credit-exhausted' | 'voice-not-found' | 'initialization-error' | 'error'
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
#### `useConversationTimer()`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["../../../src/conversation/types.ts"],"sourcesContent":["export type ConversationType = 'video' | 'audio';\n\nexport type ConversationParticipantRole = 'user' | 'agent';\n\nexport type ConversationVendor =\n | 'LIVEKIT'\n | 'DAILY'\n | 'HUME'\n | 'ELEVEN_LABS'\n | 'UNKNOWN_VENDOR';\n\nexport type AgentConnectionState =\n | 'joined' // agent is connected to the conversation\n | 'joining' // agent is connecting to the conversation\n | 'left' // agent left the conversation\n | 'idle'; // agent is not connected to the conversation\n\nexport type UserConnectionState =\n | 'joined' // user is connected to the conversation\n | 'joining' // user is connecting to the conversation\n | 'idle' // user is not connected to the conversation\n | 'leaving' // user is leaving the conversation\n | 'join-error'; // failed to join the conversation\n\nexport type ActivityState = 'idle' | 'speaking' | 'listening';\n\nexport type ConversationStatus =\n // Initial state\n | 'pending' // conversation is not created yet\n // States\n | 'created' // conversation was created\n | 'destroying' // destroying the conversation\n | 'destroyed' // conversation was destroyed\n | 'exceeded' // conversation limit is exceeded\n | 'inactivity-timeout' // conversation ended due to inactivity\n // Errors\n | 'voice-not-found' // failed to find a voice\n | 'initialization-error' // failed to create conversation\n | 'error'; // unknown error\n\nexport type Conversation = {\n id: string;\n url: string;\n limit?: number;\n type: ConversationType;\n};\n\nexport type ConversationTranscription = {\n message: string;\n source: ConversationParticipantRole;\n id: string;\n};\n\nexport type ConversationDevice = {\n enabled: boolean;\n deviceId: string;\n};\n\nexport type ConversationAudio = {\n // Range between `0.0` and `1.0`.\n volume: number;\n muted: boolean;\n};\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["../../../src/conversation/types.ts"],"sourcesContent":["export type ConversationType = 'video' | 'audio';\n\nexport type ConversationParticipantRole = 'user' | 'agent';\n\nexport type ConversationVendor =\n | 'LIVEKIT'\n | 'DAILY'\n | 'HUME'\n | 'ELEVEN_LABS'\n | 'UNKNOWN_VENDOR';\n\nexport type AgentConnectionState =\n | 'joined' // agent is connected to the conversation\n | 'joining' // agent is connecting to the conversation\n | 'left' // agent left the conversation\n | 'idle'; // agent is not connected to the conversation\n\nexport type UserConnectionState =\n | 'joined' // user is connected to the conversation\n | 'joining' // user is connecting to the conversation\n | 'idle' // user is not connected to the conversation\n | 'leaving' // user is leaving the conversation\n | 'join-error'; // failed to join the conversation\n\nexport type ActivityState = 'idle' | 'speaking' | 'listening';\n\nexport type ConversationStatus =\n // Initial state\n | 'pending' // conversation is not created yet\n // States\n | 'created' // conversation was created\n | 'destroying' // destroying the conversation\n | 'destroyed' // conversation was destroyed\n | 'exceeded' // conversation limit is exceeded\n | 'inactivity-timeout' // conversation ended due to inactivity\n | 'credit-exhausted' // the server ended the conversation because the Legend owner ran out of credit\n // Errors\n | 'voice-not-found' // failed to find a voice\n | 'initialization-error' // failed to create conversation\n | 'error'; // unknown error\n\nexport type Conversation = {\n id: string;\n url: string;\n limit?: number;\n type: ConversationType;\n};\n\nexport type ConversationTranscription = {\n message: string;\n source: ConversationParticipantRole;\n id: string;\n};\n\nexport type ConversationDevice = {\n enabled: boolean;\n deviceId: string;\n};\n\nexport type ConversationAudio = {\n // Range between `0.0` and `1.0`.\n volume: number;\n muted: boolean;\n};\n"],"mappings":"","ignoreList":[]}
|
|
@@ -75,6 +75,7 @@ function useConversation({
|
|
|
75
75
|
const setUserActivityState = (0, _jotai.useSetAtom)(_conversation.state.userActivityState);
|
|
76
76
|
const emitEvent = (0, _useEmitConversationEvent.useEmitConversationEvent)();
|
|
77
77
|
const inactivityTimeoutRef = (0, _react.useRef)(false);
|
|
78
|
+
const creditExhaustedRef = (0, _react.useRef)(false);
|
|
78
79
|
const acousticPhaseRef = (0, _react.useRef)('idle');
|
|
79
80
|
const acousticT0Ref = (0, _react.useRef)(null);
|
|
80
81
|
const latestTurnMetadataRef = (0, _react.useRef)({});
|
|
@@ -339,11 +340,19 @@ function useConversation({
|
|
|
339
340
|
guard: _utils.checkIsInactivityTimeoutData,
|
|
340
341
|
handle: handleInactivityTimeoutEvent
|
|
341
342
|
}];
|
|
342
|
-
function handleDataReceivedEvent(payload) {
|
|
343
|
+
function handleDataReceivedEvent(payload, _participant, _kind, topic) {
|
|
343
344
|
const decoded = (0, _utils.decodeDataPayload)(payload);
|
|
344
345
|
if (decoded === null) {
|
|
345
346
|
return;
|
|
346
347
|
}
|
|
348
|
+
if ((0, _utils.checkIsCreditExhaustedMessage)(decoded, topic)) {
|
|
349
|
+
var _conversationRef$curr6;
|
|
350
|
+
creditExhaustedRef.current = true;
|
|
351
|
+
emitEvent('creditExhausted', {
|
|
352
|
+
conversationId: (_conversationRef$curr6 = conversationRef.current) == null ? void 0 : _conversationRef$curr6.id
|
|
353
|
+
});
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
347
356
|
for (const {
|
|
348
357
|
guard,
|
|
349
358
|
handle
|
|
@@ -357,12 +366,12 @@ function useConversation({
|
|
|
357
366
|
}
|
|
358
367
|
}
|
|
359
368
|
function handleConnectedEvent() {
|
|
360
|
-
var _conversationRef$
|
|
369
|
+
var _conversationRef$curr7;
|
|
361
370
|
isConnectedRef.current = true;
|
|
362
371
|
setUserConnectionState('joined');
|
|
363
372
|
setAgentConnectionState('joining');
|
|
364
373
|
emitEvent('callStarted', {
|
|
365
|
-
conversationId: (_conversationRef$
|
|
374
|
+
conversationId: (_conversationRef$curr7 = conversationRef.current) == null ? void 0 : _conversationRef$curr7.id
|
|
366
375
|
});
|
|
367
376
|
}
|
|
368
377
|
async function handleEncryptionErrorEvent(error) {
|
|
@@ -385,6 +394,11 @@ function useConversation({
|
|
|
385
394
|
setConversationStatus('inactivity-timeout');
|
|
386
395
|
return;
|
|
387
396
|
}
|
|
397
|
+
if (creditExhaustedRef.current) {
|
|
398
|
+
creditExhaustedRef.current = false;
|
|
399
|
+
setConversationStatus('credit-exhausted');
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
388
402
|
switch (reason) {
|
|
389
403
|
case _livekitClient.DisconnectReason.CLIENT_INITIATED:
|
|
390
404
|
break;
|
|
@@ -403,18 +417,18 @@ function useConversation({
|
|
|
403
417
|
}
|
|
404
418
|
}
|
|
405
419
|
function handleAgentJoin(participant) {
|
|
406
|
-
var _conversationRef$
|
|
420
|
+
var _conversationRef$curr8;
|
|
407
421
|
setAgentConnectionState('joined');
|
|
408
422
|
emitEvent('agentJoined', {
|
|
409
|
-
conversationId: (_conversationRef$
|
|
423
|
+
conversationId: (_conversationRef$curr8 = conversationRef.current) == null ? void 0 : _conversationRef$curr8.id,
|
|
410
424
|
participant
|
|
411
425
|
});
|
|
412
426
|
}
|
|
413
427
|
function handleParticipantDisconnectedEvent(participant) {
|
|
414
|
-
var _conversationRef$
|
|
428
|
+
var _conversationRef$curr9;
|
|
415
429
|
setAgentConnectionState('left');
|
|
416
430
|
emitEvent('agentLeft', {
|
|
417
|
-
conversationId: (_conversationRef$
|
|
431
|
+
conversationId: (_conversationRef$curr9 = conversationRef.current) == null ? void 0 : _conversationRef$curr9.id,
|
|
418
432
|
participant
|
|
419
433
|
});
|
|
420
434
|
}
|
|
@@ -423,13 +437,13 @@ function useConversation({
|
|
|
423
437
|
return;
|
|
424
438
|
}
|
|
425
439
|
try {
|
|
426
|
-
var _conversationRef$
|
|
440
|
+
var _conversationRef$curr0;
|
|
427
441
|
setUserConnectionState('leaving');
|
|
428
442
|
await (room == null ? void 0 : room.disconnect(true));
|
|
429
443
|
setConversationStatus('destroyed');
|
|
430
444
|
setJoinedAt(undefined);
|
|
431
445
|
emitEvent('callEnded', {
|
|
432
|
-
conversationId: (_conversationRef$
|
|
446
|
+
conversationId: (_conversationRef$curr0 = conversationRef.current) == null ? void 0 : _conversationRef$curr0.id
|
|
433
447
|
});
|
|
434
448
|
} catch (error) {
|
|
435
449
|
console.error('Failed to leave', error);
|
|
@@ -437,18 +451,22 @@ function useConversation({
|
|
|
437
451
|
}
|
|
438
452
|
}
|
|
439
453
|
async function handleExpire() {
|
|
440
|
-
var _conversationRef$
|
|
454
|
+
var _conversationRef$curr1, _conversationRef$curr10;
|
|
455
|
+
// The duration timer keeps running after the call ends.
|
|
456
|
+
if (conversationStatus === 'credit-exhausted') {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
441
459
|
emitEvent('timeExceeded', {
|
|
442
|
-
conversationId: (_conversationRef$
|
|
443
|
-
limit: (_conversationRef$
|
|
460
|
+
conversationId: (_conversationRef$curr1 = conversationRef.current) == null ? void 0 : _conversationRef$curr1.id,
|
|
461
|
+
limit: (_conversationRef$curr10 = conversationRef.current) == null ? void 0 : _conversationRef$curr10.limit
|
|
444
462
|
});
|
|
445
463
|
await leave();
|
|
446
464
|
setConversationStatus('exceeded');
|
|
447
465
|
}
|
|
448
466
|
async function interrupt() {
|
|
449
|
-
var _conversationRef$
|
|
467
|
+
var _conversationRef$curr11;
|
|
450
468
|
emitEvent('interrupt', {
|
|
451
|
-
conversationId: (_conversationRef$
|
|
469
|
+
conversationId: (_conversationRef$curr11 = conversationRef.current) == null ? void 0 : _conversationRef$curr11.id
|
|
452
470
|
});
|
|
453
471
|
await (0, _utils.publishConversationDataMessage)(room, {}, 'interrupt');
|
|
454
472
|
}
|
|
@@ -458,7 +476,7 @@ function useConversation({
|
|
|
458
476
|
}, 'inactivity_dismiss');
|
|
459
477
|
}
|
|
460
478
|
async function send(message, attachments = []) {
|
|
461
|
-
var _conversationRef$
|
|
479
|
+
var _conversationRef$curr12;
|
|
462
480
|
await (room == null ? void 0 : room.localParticipant.sendText(message, {
|
|
463
481
|
topic: 'lk.chat',
|
|
464
482
|
attributes: {
|
|
@@ -466,7 +484,7 @@ function useConversation({
|
|
|
466
484
|
}
|
|
467
485
|
}));
|
|
468
486
|
emitEvent('userSendMessage', {
|
|
469
|
-
conversationId: (_conversationRef$
|
|
487
|
+
conversationId: (_conversationRef$curr12 = conversationRef.current) == null ? void 0 : _conversationRef$curr12.id,
|
|
470
488
|
message
|
|
471
489
|
});
|
|
472
490
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","require","_livekitClient","_invariant","_interopRequireDefault","_reactTimerHook","_reactUse","_componentsReact","_jotai","_conversation","_sdkConsumer","_useCreateConversation","_useSpeechActivityDetector","_useParticipantTrack","_useEmitConversationEvent","_useToolCallingRuntime","_serialize","_utils","_constants","useConversation","autoJoin","type","config","startWithMicrophone","startWithCamera","firstConversation","lastConversationTopic","_conversation$data2","setLogLevel","LogLevel","silent","conversation","useCreateConversation","room","useEnsureRoom","speaker","useAtomValue","state","microphone","setMicrophone","useAtom","camera","setCamera","tools","toolsRegistry","useSdkConsumer","toolRuntime","useToolCallingRuntime","toolsRegistryRef","useLatest","conversationRef","data","toolRuntimeRef","conversationStatus","setConversationStatus","userConnectionState","setUserConnectionState","joinedAt","setJoinedAt","setActiveMediaDevice","setMicrophoneDeviceId","useMediaDeviceSelect","kind","setSpeakerDeviceId","setCameraDeviceId","requestPermissions","enabled","setTranscriptions","useSetAtom","transcriptions","agentConnectionState","setAgentConnectionState","setAgentActivityState","agentActivityState","setUserActivityState","userActivityState","emitEvent","useEmitConversationEvent","inactivityTimeoutRef","useRef","acousticPhaseRef","acousticT0Ref","latestTurnMetadataRef","isConnectedRef","userCumulativeTrackStatsRef","undefined","agentCumulativeTrackStatsRef","userMicPublication","useParticipantTrack","source","Source","Microphone","agentMicPublication","timer","useTimer","autoStart","onExpire","handleExpire","expiryTimestamp","Date","useEffect","registerRoomEvents","unregisterRoomEvents","useUpdateEffect","deviceId","localParticipant","setMicrophoneEnabled","setCameraEnabled","resolution","width","height","join","_conversation$data","limit","restart","getTime","_conversation$data3","invariant","url","URL","accessToken","searchParams","get","connect","remoteParticipant","findJoinedAgentParticipant","handleAgentJoin","enableMediaDevices","error","console","handleTranscriptionReceivedEvent","segments","participant","map","s","id","message","text","ParticipantKind","AGENT","old","mergeTranscriptions","handleTurnDetectionEvent","_conversationRef$curr","conversationId","current","participantKind","eventState","turnDetectionStrategy","sequence","speechId","handleAcousticUserOnset","handleAcousticUserOffset","timestampMs","ACOUSTIC_USER_HANGOVER_MS","handleAcousticAgentOnset","_conversationRef$curr2","latencyMs","emitConversationTurnLatency","clientAcousticLatencyMs","_conversationRef$curr3","userReport","agentReport","Promise","all","getTrackStats","userStats","parseTrackStats","agentStats","cumulativeTrackStats","rttMs","roundTripTimeMs","jitterBufferDelayMs","userPacketsLost","packetsLost","agentPacketsLost","handleAcousticAgentOffset","useSpeechActivityDetector","onSpeechStart","onSpeechEnd","thresholdRms","ACOUSTIC_USER_THRESHOLD_RMS","hangoverMs","ACOUSTIC_AGENT_HANGOVER_MS","handleInactivityWarningEvent","_conversationRef$curr4","gracePeriodSec","grace_period_sec","handleInactivityTimeoutEvent","_data","_conversationRef$curr5","handleGetToolsRpc","JSON","stringify","buildToolDefinitions","handleExecuteToolRpc","call","parseFunctionCallPayload","payload","functionCallId","result","executeToolCalls","extractToolErrorMessage","dataChannelHandlers","guard","checkIsTurnDetectionData","handle","checkIsInactivityWarningData","checkIsInactivityTimeoutData","handleDataReceivedEvent","decoded","decodeDataPayload","resolve","catch","handleConnectedEvent","_conversationRef$curr6","handleEncryptionErrorEvent","handleDisconnectedEvent","reason","DisconnectReason","CLIENT_INITIATED","ROOM_CLOSED","handleParticipantConnectedEvent","shouldHandleParticipantConnected","_conversationRef$curr7","handleParticipantDisconnectedEvent","_conversationRef$curr8","leave","_conversationRef$curr9","disconnect","_conversationRef$curr0","_conversationRef$curr1","interrupt","_conversationRef$curr10","publishConversationDataMessage","dismissInactivity","send","attachments","_conversationRef$curr11","sendText","topic","attributes","safeStringify","on","unregisterRpcMethod","GET_TOOLS_RPC_METHOD","EXECUTE_TOOL_RPC_METHOD","registerRpcMethod","off","status"],"sources":["../../../../../src/hooks/useConversation/livekit/useConversation.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport {\n DisconnectReason,\n Participant,\n setLogLevel,\n ParticipantKind,\n RemoteParticipant,\n TranscriptionSegment,\n LogLevel,\n type RpcInvocationData,\n} from 'livekit-client';\nimport invariant from 'invariant';\nimport { useTimer } from 'react-timer-hook';\nimport { useLatest, useUpdateEffect } from 'react-use';\nimport { useEnsureRoom, useMediaDeviceSelect } from '@livekit/components-react';\nimport { useAtom, useAtomValue, useSetAtom } from 'jotai';\nimport {\n Conversation,\n state,\n type ConversationTranscription,\n} from '../../../conversation';\nimport type {\n UseConversationResult,\n UseConversationOptions,\n Attachment,\n} from '../types';\nimport type { FunctionCallResult } from '../../../types/service';\nimport { useSdkConsumer } from '../../../sdk-consumer';\nimport type {\n InactivityWarningData,\n InactivityTimeoutData,\n TurnDetectionData,\n} from './types';\nimport { useCreateConversation } from '../../useCreateConversation';\nimport { useSpeechActivityDetector } from '../../useSpeechActivityDetector';\nimport {\n useParticipantTrack,\n Source,\n getTrackStats,\n parseTrackStats,\n type CumulativeTrackStats,\n} from '../../useParticipantTrack';\n\nimport { useEmitConversationEvent } from '../../useConversationEvents/useEmitConversationEvent';\nimport { useToolCallingRuntime } from '../../useTools/runtime/useToolCallingRuntime';\nimport { extractToolErrorMessage } from '../../useTools/utils/serialize';\nimport {\n checkIsTurnDetectionData,\n checkIsInactivityWarningData,\n checkIsInactivityTimeoutData,\n buildToolDefinitions,\n decodeDataPayload,\n findJoinedAgentParticipant,\n mergeTranscriptions,\n parseFunctionCallPayload,\n publishConversationDataMessage,\n safeStringify,\n shouldHandleParticipantConnected,\n} from './utils';\nimport {\n ACOUSTIC_AGENT_HANGOVER_MS,\n ACOUSTIC_USER_HANGOVER_MS,\n ACOUSTIC_USER_THRESHOLD_RMS,\n EXECUTE_TOOL_RPC_METHOD,\n GET_TOOLS_RPC_METHOD,\n} from './constants';\n\nexport function useConversation({\n autoJoin = true,\n type,\n config,\n startWithMicrophone = false,\n startWithCamera = false,\n firstConversation,\n lastConversationTopic,\n}: UseConversationOptions): UseConversationResult {\n setLogLevel(LogLevel.silent);\n\n const conversation = useCreateConversation({\n type,\n config,\n firstConversation,\n lastConversationTopic,\n });\n const room = useEnsureRoom();\n const speaker = useAtomValue(state.speaker);\n const [microphone, setMicrophone] = useAtom(state.microphone);\n const [camera, setCamera] = useAtom(state.camera);\n const { tools: toolsRegistry = {} } = useSdkConsumer();\n const toolRuntime = useToolCallingRuntime();\n const toolsRegistryRef = useLatest(toolsRegistry);\n\n // for use in register/unregister room events\n const conversationRef = useLatest<Conversation | undefined>(\n conversation.data,\n );\n const toolRuntimeRef = useLatest(toolRuntime);\n\n const [conversationStatus, setConversationStatus] = useAtom(\n state.conversationStatus,\n );\n\n const [userConnectionState, setUserConnectionState] = useAtom(\n state.userConnectionState,\n );\n\n const [joinedAt, setJoinedAt] = useAtom(state.joinedAt);\n\n const { setActiveMediaDevice: setMicrophoneDeviceId } = useMediaDeviceSelect({\n kind: 'audioinput',\n });\n const { setActiveMediaDevice: setSpeakerDeviceId } = useMediaDeviceSelect({\n kind: 'audiooutput',\n });\n const { setActiveMediaDevice: setCameraDeviceId } = useMediaDeviceSelect({\n kind: 'videoinput',\n requestPermissions: camera.enabled,\n });\n\n const setTranscriptions = useSetAtom(state.transcriptions);\n const [agentConnectionState, setAgentConnectionState] = useAtom(\n state.agentConnectionState,\n );\n const setAgentActivityState = useSetAtom(state.agentActivityState);\n const setUserActivityState = useSetAtom(state.userActivityState);\n const emitEvent = useEmitConversationEvent();\n\n const inactivityTimeoutRef = useRef(false);\n const acousticPhaseRef = useRef<'idle' | 'waitingForAgent' | 'busy'>('idle');\n const acousticT0Ref = useRef<number | null>(null);\n const latestTurnMetadataRef = useRef<{\n turnDetectionStrategy?: string;\n sequence?: number;\n speechId?: string;\n }>({});\n const isConnectedRef = useRef(false);\n const userCumulativeTrackStatsRef = useRef<CumulativeTrackStats | undefined>(\n undefined,\n );\n const agentCumulativeTrackStatsRef = useRef<CumulativeTrackStats | undefined>(\n undefined,\n );\n\n const userMicPublication = useParticipantTrack({\n type: 'user',\n source: Source.Microphone,\n });\n const agentMicPublication = useParticipantTrack({\n type: 'agent',\n source: Source.Microphone,\n });\n\n const timer = useTimer({\n autoStart: false,\n onExpire: handleExpire,\n expiryTimestamp: new Date(),\n });\n\n useEffect(() => {\n if (!room) {\n return;\n }\n registerRoomEvents();\n\n return () => {\n unregisterRoomEvents();\n };\n }, [room]);\n\n useUpdateEffect(() => {\n setMicrophoneDeviceId(microphone.deviceId);\n }, [microphone.deviceId]);\n\n useUpdateEffect(() => {\n setSpeakerDeviceId(speaker.deviceId);\n }, [speaker.deviceId]);\n\n useUpdateEffect(() => {\n setCameraDeviceId(camera.deviceId);\n }, [camera.deviceId]);\n\n useUpdateEffect(() => {\n if (agentConnectionState !== 'joined') {\n return;\n }\n room.localParticipant.setMicrophoneEnabled(microphone.enabled);\n }, [microphone.enabled, agentConnectionState]);\n\n useUpdateEffect(() => {\n if (agentConnectionState !== 'joined') {\n return;\n }\n room.localParticipant.setCameraEnabled(camera.enabled, {\n resolution: { width: 1920, height: 1080 },\n });\n }, [camera.enabled, agentConnectionState]);\n\n useEffect(() => {\n if (!autoJoin) {\n return;\n }\n\n if (conversationStatus === 'created') {\n void join();\n }\n }, [conversationStatus, autoJoin]);\n\n useEffect(() => {\n if (!joinedAt || conversation.data?.limit === undefined) {\n return;\n }\n\n timer.restart(new Date(joinedAt.getTime() + conversation.data!.limit!));\n }, [joinedAt, conversation.data?.limit]);\n\n async function join() {\n invariant(userConnectionState === 'idle', 'Already joined');\n invariant(conversation.data, 'Conversation is not ready');\n const url = new URL(conversation?.data?.url || '');\n const accessToken = url.searchParams.get('token');\n try {\n setUserConnectionState('joining');\n await room?.connect(conversation.data.url, accessToken!, {});\n\n // sometimes the agent is already joined before the user joins the conversation\n const remoteParticipant = findJoinedAgentParticipant(room, type);\n if (remoteParticipant && agentConnectionState !== 'joined') {\n handleAgentJoin(remoteParticipant);\n }\n\n enableMediaDevices();\n } catch (error) {\n console.error('Failed to join', error);\n setUserConnectionState('join-error');\n }\n }\n\n function enableMediaDevices() {\n if (startWithMicrophone) {\n setMicrophone({ ...microphone, enabled: true });\n }\n if (startWithCamera && type === 'video') {\n setCamera({ ...camera, enabled: true });\n }\n }\n\n function handleTranscriptionReceivedEvent(\n segments: TranscriptionSegment[],\n participant?: Participant,\n ) {\n const transcriptions: ConversationTranscription[] = segments.map((s) => ({\n id: s.id,\n message: s.text,\n source: participant?.kind === ParticipantKind.AGENT ? 'agent' : 'user',\n }));\n\n setTranscriptions((old) => mergeTranscriptions(transcriptions, old));\n }\n\n function handleTurnDetectionEvent(data: TurnDetectionData) {\n const conversationId = conversationRef.current?.id;\n const { participantKind, state: eventState } = data;\n switch (participantKind) {\n case 'STANDARD':\n if (eventState === 'listening') {\n latestTurnMetadataRef.current = {\n turnDetectionStrategy: data.turnDetectionStrategy,\n sequence: data.sequence,\n speechId: data.speechId,\n };\n }\n emitEvent(\n eventState === 'speaking' ? 'userSpeakStart' : 'userSpeakStop',\n { conversationId: conversationId! },\n );\n setUserActivityState(eventState);\n break;\n case 'AGENT':\n if (data.speechId) {\n latestTurnMetadataRef.current = {\n ...latestTurnMetadataRef.current,\n speechId: data.speechId,\n };\n }\n emitEvent(\n eventState === 'speaking' ? 'agentSpeakStart' : 'agentSpeakStop',\n { conversationId: conversationId! },\n );\n setAgentActivityState(eventState);\n break;\n }\n }\n\n function handleAcousticUserOnset() {\n if (!isConnectedRef.current) {\n return;\n }\n if (acousticPhaseRef.current === 'waitingForAgent') {\n acousticPhaseRef.current = 'idle';\n acousticT0Ref.current = null;\n }\n }\n\n function handleAcousticUserOffset(timestampMs: number) {\n if (!isConnectedRef.current || acousticPhaseRef.current !== 'idle') {\n return;\n }\n acousticT0Ref.current = timestampMs - ACOUSTIC_USER_HANGOVER_MS;\n acousticPhaseRef.current = 'waitingForAgent';\n }\n\n function handleAcousticAgentOnset(timestampMs: number) {\n if (\n !isConnectedRef.current ||\n acousticPhaseRef.current !== 'waitingForAgent' ||\n acousticT0Ref.current == null\n ) {\n return;\n }\n\n const latencyMs = timestampMs - acousticT0Ref.current;\n acousticT0Ref.current = null;\n acousticPhaseRef.current = 'busy';\n\n if (latencyMs < 0 || latencyMs > 15000) {\n return;\n }\n\n emitEvent('responseLatency', {\n conversationId: conversationRef.current?.id!,\n latencyMs,\n turnDetectionStrategy:\n latestTurnMetadataRef.current.turnDetectionStrategy!,\n sequence: latestTurnMetadataRef.current.sequence,\n speechId: latestTurnMetadataRef.current.speechId,\n });\n\n void emitConversationTurnLatency(latencyMs);\n }\n\n async function emitConversationTurnLatency(clientAcousticLatencyMs: number) {\n const [userReport, agentReport] = await Promise.all([\n getTrackStats(userMicPublication),\n getTrackStats(agentMicPublication),\n ]);\n const userStats = parseTrackStats(\n userReport,\n userCumulativeTrackStatsRef.current,\n );\n const agentStats = parseTrackStats(\n agentReport,\n agentCumulativeTrackStatsRef.current,\n );\n userCumulativeTrackStatsRef.current = userStats.cumulativeTrackStats;\n agentCumulativeTrackStatsRef.current = agentStats.cumulativeTrackStats;\n\n emitEvent('conversationTurnLatency', {\n conversationId: conversationRef.current?.id!,\n speechId: latestTurnMetadataRef.current.speechId,\n sequence: latestTurnMetadataRef.current.sequence,\n clientAcousticLatencyMs,\n rttMs: userStats.roundTripTimeMs,\n jitterBufferDelayMs: agentStats.jitterBufferDelayMs,\n userPacketsLost: userStats.packetsLost,\n agentPacketsLost: agentStats.packetsLost,\n });\n }\n\n function handleAcousticAgentOffset() {\n acousticPhaseRef.current = 'idle';\n }\n\n useSpeechActivityDetector({\n source: 'user',\n onSpeechStart: handleAcousticUserOnset,\n onSpeechEnd: handleAcousticUserOffset,\n thresholdRms: ACOUSTIC_USER_THRESHOLD_RMS,\n hangoverMs: ACOUSTIC_USER_HANGOVER_MS,\n });\n useSpeechActivityDetector({\n source: 'agent',\n onSpeechStart: handleAcousticAgentOnset,\n onSpeechEnd: handleAcousticAgentOffset,\n hangoverMs: ACOUSTIC_AGENT_HANGOVER_MS,\n });\n\n function handleInactivityWarningEvent(data: InactivityWarningData) {\n emitEvent('inactivityWarning', {\n conversationId: conversationRef.current?.id!,\n gracePeriodSec: data.grace_period_sec,\n });\n }\n\n function handleInactivityTimeoutEvent(_data: InactivityTimeoutData) {\n inactivityTimeoutRef.current = true;\n emitEvent('inactivityTimeout', {\n conversationId: conversationRef.current?.id!,\n });\n }\n\n async function handleGetToolsRpc() {\n return JSON.stringify(buildToolDefinitions(toolsRegistryRef.current));\n }\n\n async function handleExecuteToolRpc(data: RpcInvocationData) {\n const call = parseFunctionCallPayload(data.payload);\n if (!call) {\n return JSON.stringify({\n functionCallId: '',\n result: '',\n error: 'Malformed function call payload.',\n } satisfies FunctionCallResult);\n }\n try {\n const [result] = await toolRuntimeRef.current.executeToolCalls([call]);\n return JSON.stringify(result);\n } catch (error) {\n return JSON.stringify({\n functionCallId: call.functionCallId,\n result: '',\n error: extractToolErrorMessage(error),\n } satisfies FunctionCallResult);\n }\n }\n\n const dataChannelHandlers: {\n guard: (data: unknown) => boolean;\n handle: (data: unknown) => void | Promise<void>;\n }[] = [\n {\n guard: checkIsTurnDetectionData,\n handle: handleTurnDetectionEvent as (data: unknown) => void,\n },\n {\n guard: checkIsInactivityWarningData,\n handle: handleInactivityWarningEvent as (data: unknown) => void,\n },\n {\n guard: checkIsInactivityTimeoutData,\n handle: handleInactivityTimeoutEvent as (data: unknown) => void,\n },\n ];\n\n function handleDataReceivedEvent(payload: Uint8Array) {\n const decoded = decodeDataPayload(payload);\n if (decoded === null) {\n return;\n }\n for (const { guard, handle } of dataChannelHandlers) {\n if (guard(decoded)) {\n void Promise.resolve(handle(decoded)).catch((error) => {\n console.error('Failed to handle data channel payload', error);\n });\n return;\n }\n }\n }\n\n function handleConnectedEvent() {\n isConnectedRef.current = true;\n setUserConnectionState('joined');\n setAgentConnectionState('joining');\n emitEvent('callStarted', {\n conversationId: conversationRef.current?.id!,\n });\n }\n\n async function handleEncryptionErrorEvent(error: Error) {\n console.error('Encryption error', error);\n setConversationStatus('error');\n }\n\n function handleDisconnectedEvent(reason?: DisconnectReason) {\n isConnectedRef.current = false;\n acousticPhaseRef.current = 'idle';\n acousticT0Ref.current = null;\n latestTurnMetadataRef.current = {};\n userCumulativeTrackStatsRef.current = undefined;\n agentCumulativeTrackStatsRef.current = undefined;\n setAgentActivityState('idle');\n setAgentConnectionState('idle');\n setUserActivityState('idle');\n setUserConnectionState('idle');\n\n if (inactivityTimeoutRef.current) {\n inactivityTimeoutRef.current = false;\n setConversationStatus('inactivity-timeout');\n return;\n }\n\n switch (reason) {\n case DisconnectReason.CLIENT_INITIATED:\n break;\n case DisconnectReason.ROOM_CLOSED:\n setConversationStatus('destroyed');\n break;\n default:\n console.error('Conversation disconnected with reason', reason);\n setConversationStatus('error');\n break;\n }\n }\n\n function handleParticipantConnectedEvent(participant: RemoteParticipant) {\n if (shouldHandleParticipantConnected(participant, type)) {\n handleAgentJoin(participant);\n }\n }\n\n function handleAgentJoin(participant: RemoteParticipant) {\n setAgentConnectionState('joined');\n emitEvent('agentJoined', {\n conversationId: conversationRef.current?.id!,\n participant,\n });\n }\n\n function handleParticipantDisconnectedEvent(participant: RemoteParticipant) {\n setAgentConnectionState('left');\n emitEvent('agentLeft', {\n conversationId: conversationRef.current?.id!,\n participant,\n });\n }\n\n async function leave() {\n if (userConnectionState !== 'joined' && userConnectionState !== 'joining') {\n return;\n }\n\n try {\n setUserConnectionState('leaving');\n await room?.disconnect(true);\n setConversationStatus('destroyed');\n setJoinedAt(undefined);\n emitEvent('callEnded', {\n conversationId: conversationRef.current?.id!,\n });\n } catch (error) {\n console.error('Failed to leave', error);\n setConversationStatus('error');\n }\n }\n\n async function handleExpire() {\n emitEvent('timeExceeded', {\n conversationId: conversationRef.current?.id!,\n limit: conversationRef.current?.limit!,\n });\n await leave();\n setConversationStatus('exceeded');\n }\n\n async function interrupt() {\n emitEvent('interrupt', {\n conversationId: conversationRef.current?.id!,\n });\n\n await publishConversationDataMessage(room, {}, 'interrupt');\n }\n\n async function dismissInactivity() {\n await publishConversationDataMessage(\n room,\n { type: 'inactivity_dismiss' },\n 'inactivity_dismiss',\n );\n }\n\n async function send(message: string, attachments: Attachment[] = []) {\n await room?.localParticipant.sendText(message, {\n topic: 'lk.chat',\n attributes: {\n attachments: safeStringify(attachments),\n },\n });\n emitEvent('userSendMessage', {\n conversationId: conversationRef.current?.id!,\n message,\n });\n }\n\n function registerRoomEvents() {\n room\n .on('connected', handleConnectedEvent)\n .on('encryptionError', handleEncryptionErrorEvent)\n .on('disconnected', handleDisconnectedEvent)\n .on('transcriptionReceived', handleTranscriptionReceivedEvent)\n .on('participantConnected', handleParticipantConnectedEvent)\n .on('participantDisconnected', handleParticipantDisconnectedEvent)\n .on('dataReceived', handleDataReceivedEvent);\n room.unregisterRpcMethod(GET_TOOLS_RPC_METHOD);\n room.unregisterRpcMethod(EXECUTE_TOOL_RPC_METHOD);\n room.registerRpcMethod(GET_TOOLS_RPC_METHOD, handleGetToolsRpc);\n room.registerRpcMethod(EXECUTE_TOOL_RPC_METHOD, handleExecuteToolRpc);\n }\n\n function unregisterRoomEvents() {\n room.unregisterRpcMethod(GET_TOOLS_RPC_METHOD);\n room.unregisterRpcMethod(EXECUTE_TOOL_RPC_METHOD);\n room.off('connected', handleConnectedEvent);\n room.off('encryptionError', handleEncryptionErrorEvent);\n room.off('disconnected', handleDisconnectedEvent);\n room.off('transcriptionReceived', handleTranscriptionReceivedEvent);\n room.off('participantConnected', handleParticipantConnectedEvent);\n room.off('participantDisconnected', handleParticipantDisconnectedEvent);\n room.off('dataReceived', handleDataReceivedEvent);\n }\n\n return {\n status: conversationStatus,\n conversation: conversation.data,\n join,\n send,\n interrupt,\n dismissInactivity,\n leave,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","require","_livekitClient","_invariant","_interopRequireDefault","_reactTimerHook","_reactUse","_componentsReact","_jotai","_conversation","_sdkConsumer","_useCreateConversation","_useSpeechActivityDetector","_useParticipantTrack","_useEmitConversationEvent","_useToolCallingRuntime","_serialize","_utils","_constants","useConversation","autoJoin","type","config","startWithMicrophone","startWithCamera","firstConversation","lastConversationTopic","_conversation$data2","setLogLevel","LogLevel","silent","conversation","useCreateConversation","room","useEnsureRoom","speaker","useAtomValue","state","microphone","setMicrophone","useAtom","camera","setCamera","tools","toolsRegistry","useSdkConsumer","toolRuntime","useToolCallingRuntime","toolsRegistryRef","useLatest","conversationRef","data","toolRuntimeRef","conversationStatus","setConversationStatus","userConnectionState","setUserConnectionState","joinedAt","setJoinedAt","setActiveMediaDevice","setMicrophoneDeviceId","useMediaDeviceSelect","kind","setSpeakerDeviceId","setCameraDeviceId","requestPermissions","enabled","setTranscriptions","useSetAtom","transcriptions","agentConnectionState","setAgentConnectionState","setAgentActivityState","agentActivityState","setUserActivityState","userActivityState","emitEvent","useEmitConversationEvent","inactivityTimeoutRef","useRef","creditExhaustedRef","acousticPhaseRef","acousticT0Ref","latestTurnMetadataRef","isConnectedRef","userCumulativeTrackStatsRef","undefined","agentCumulativeTrackStatsRef","userMicPublication","useParticipantTrack","source","Source","Microphone","agentMicPublication","timer","useTimer","autoStart","onExpire","handleExpire","expiryTimestamp","Date","useEffect","registerRoomEvents","unregisterRoomEvents","useUpdateEffect","deviceId","localParticipant","setMicrophoneEnabled","setCameraEnabled","resolution","width","height","join","_conversation$data","limit","restart","getTime","_conversation$data3","invariant","url","URL","accessToken","searchParams","get","connect","remoteParticipant","findJoinedAgentParticipant","handleAgentJoin","enableMediaDevices","error","console","handleTranscriptionReceivedEvent","segments","participant","map","s","id","message","text","ParticipantKind","AGENT","old","mergeTranscriptions","handleTurnDetectionEvent","_conversationRef$curr","conversationId","current","participantKind","eventState","turnDetectionStrategy","sequence","speechId","handleAcousticUserOnset","handleAcousticUserOffset","timestampMs","ACOUSTIC_USER_HANGOVER_MS","handleAcousticAgentOnset","_conversationRef$curr2","latencyMs","emitConversationTurnLatency","clientAcousticLatencyMs","_conversationRef$curr3","userReport","agentReport","Promise","all","getTrackStats","userStats","parseTrackStats","agentStats","cumulativeTrackStats","rttMs","roundTripTimeMs","jitterBufferDelayMs","userPacketsLost","packetsLost","agentPacketsLost","handleAcousticAgentOffset","useSpeechActivityDetector","onSpeechStart","onSpeechEnd","thresholdRms","ACOUSTIC_USER_THRESHOLD_RMS","hangoverMs","ACOUSTIC_AGENT_HANGOVER_MS","handleInactivityWarningEvent","_conversationRef$curr4","gracePeriodSec","grace_period_sec","handleInactivityTimeoutEvent","_data","_conversationRef$curr5","handleGetToolsRpc","JSON","stringify","buildToolDefinitions","handleExecuteToolRpc","call","parseFunctionCallPayload","payload","functionCallId","result","executeToolCalls","extractToolErrorMessage","dataChannelHandlers","guard","checkIsTurnDetectionData","handle","checkIsInactivityWarningData","checkIsInactivityTimeoutData","handleDataReceivedEvent","_participant","_kind","topic","decoded","decodeDataPayload","checkIsCreditExhaustedMessage","_conversationRef$curr6","resolve","catch","handleConnectedEvent","_conversationRef$curr7","handleEncryptionErrorEvent","handleDisconnectedEvent","reason","DisconnectReason","CLIENT_INITIATED","ROOM_CLOSED","handleParticipantConnectedEvent","shouldHandleParticipantConnected","_conversationRef$curr8","handleParticipantDisconnectedEvent","_conversationRef$curr9","leave","_conversationRef$curr0","disconnect","_conversationRef$curr1","_conversationRef$curr10","interrupt","_conversationRef$curr11","publishConversationDataMessage","dismissInactivity","send","attachments","_conversationRef$curr12","sendText","attributes","safeStringify","on","unregisterRpcMethod","GET_TOOLS_RPC_METHOD","EXECUTE_TOOL_RPC_METHOD","registerRpcMethod","off","status"],"sources":["../../../../../src/hooks/useConversation/livekit/useConversation.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport {\n DisconnectReason,\n Participant,\n setLogLevel,\n ParticipantKind,\n RemoteParticipant,\n TranscriptionSegment,\n LogLevel,\n type RpcInvocationData,\n} from 'livekit-client';\nimport invariant from 'invariant';\nimport { useTimer } from 'react-timer-hook';\nimport { useLatest, useUpdateEffect } from 'react-use';\nimport { useEnsureRoom, useMediaDeviceSelect } from '@livekit/components-react';\nimport { useAtom, useAtomValue, useSetAtom } from 'jotai';\nimport {\n Conversation,\n state,\n type ConversationTranscription,\n} from '../../../conversation';\nimport type {\n UseConversationResult,\n UseConversationOptions,\n Attachment,\n} from '../types';\nimport type { FunctionCallResult } from '../../../types/service';\nimport { useSdkConsumer } from '../../../sdk-consumer';\nimport type {\n InactivityWarningData,\n InactivityTimeoutData,\n TurnDetectionData,\n} from './types';\nimport { useCreateConversation } from '../../useCreateConversation';\nimport { useSpeechActivityDetector } from '../../useSpeechActivityDetector';\nimport {\n useParticipantTrack,\n Source,\n getTrackStats,\n parseTrackStats,\n type CumulativeTrackStats,\n} from '../../useParticipantTrack';\n\nimport { useEmitConversationEvent } from '../../useConversationEvents/useEmitConversationEvent';\nimport { useToolCallingRuntime } from '../../useTools/runtime/useToolCallingRuntime';\nimport { extractToolErrorMessage } from '../../useTools/utils/serialize';\nimport {\n checkIsTurnDetectionData,\n checkIsInactivityWarningData,\n checkIsInactivityTimeoutData,\n checkIsCreditExhaustedMessage,\n buildToolDefinitions,\n decodeDataPayload,\n findJoinedAgentParticipant,\n mergeTranscriptions,\n parseFunctionCallPayload,\n publishConversationDataMessage,\n safeStringify,\n shouldHandleParticipantConnected,\n} from './utils';\nimport {\n ACOUSTIC_AGENT_HANGOVER_MS,\n ACOUSTIC_USER_HANGOVER_MS,\n ACOUSTIC_USER_THRESHOLD_RMS,\n EXECUTE_TOOL_RPC_METHOD,\n GET_TOOLS_RPC_METHOD,\n} from './constants';\n\nexport function useConversation({\n autoJoin = true,\n type,\n config,\n startWithMicrophone = false,\n startWithCamera = false,\n firstConversation,\n lastConversationTopic,\n}: UseConversationOptions): UseConversationResult {\n setLogLevel(LogLevel.silent);\n\n const conversation = useCreateConversation({\n type,\n config,\n firstConversation,\n lastConversationTopic,\n });\n const room = useEnsureRoom();\n const speaker = useAtomValue(state.speaker);\n const [microphone, setMicrophone] = useAtom(state.microphone);\n const [camera, setCamera] = useAtom(state.camera);\n const { tools: toolsRegistry = {} } = useSdkConsumer();\n const toolRuntime = useToolCallingRuntime();\n const toolsRegistryRef = useLatest(toolsRegistry);\n\n // for use in register/unregister room events\n const conversationRef = useLatest<Conversation | undefined>(\n conversation.data,\n );\n const toolRuntimeRef = useLatest(toolRuntime);\n\n const [conversationStatus, setConversationStatus] = useAtom(\n state.conversationStatus,\n );\n\n const [userConnectionState, setUserConnectionState] = useAtom(\n state.userConnectionState,\n );\n\n const [joinedAt, setJoinedAt] = useAtom(state.joinedAt);\n\n const { setActiveMediaDevice: setMicrophoneDeviceId } = useMediaDeviceSelect({\n kind: 'audioinput',\n });\n const { setActiveMediaDevice: setSpeakerDeviceId } = useMediaDeviceSelect({\n kind: 'audiooutput',\n });\n const { setActiveMediaDevice: setCameraDeviceId } = useMediaDeviceSelect({\n kind: 'videoinput',\n requestPermissions: camera.enabled,\n });\n\n const setTranscriptions = useSetAtom(state.transcriptions);\n const [agentConnectionState, setAgentConnectionState] = useAtom(\n state.agentConnectionState,\n );\n const setAgentActivityState = useSetAtom(state.agentActivityState);\n const setUserActivityState = useSetAtom(state.userActivityState);\n const emitEvent = useEmitConversationEvent();\n\n const inactivityTimeoutRef = useRef(false);\n const creditExhaustedRef = useRef(false);\n const acousticPhaseRef = useRef<'idle' | 'waitingForAgent' | 'busy'>('idle');\n const acousticT0Ref = useRef<number | null>(null);\n const latestTurnMetadataRef = useRef<{\n turnDetectionStrategy?: string;\n sequence?: number;\n speechId?: string;\n }>({});\n const isConnectedRef = useRef(false);\n const userCumulativeTrackStatsRef = useRef<CumulativeTrackStats | undefined>(\n undefined,\n );\n const agentCumulativeTrackStatsRef = useRef<CumulativeTrackStats | undefined>(\n undefined,\n );\n\n const userMicPublication = useParticipantTrack({\n type: 'user',\n source: Source.Microphone,\n });\n const agentMicPublication = useParticipantTrack({\n type: 'agent',\n source: Source.Microphone,\n });\n\n const timer = useTimer({\n autoStart: false,\n onExpire: handleExpire,\n expiryTimestamp: new Date(),\n });\n\n useEffect(() => {\n if (!room) {\n return;\n }\n registerRoomEvents();\n\n return () => {\n unregisterRoomEvents();\n };\n }, [room]);\n\n useUpdateEffect(() => {\n setMicrophoneDeviceId(microphone.deviceId);\n }, [microphone.deviceId]);\n\n useUpdateEffect(() => {\n setSpeakerDeviceId(speaker.deviceId);\n }, [speaker.deviceId]);\n\n useUpdateEffect(() => {\n setCameraDeviceId(camera.deviceId);\n }, [camera.deviceId]);\n\n useUpdateEffect(() => {\n if (agentConnectionState !== 'joined') {\n return;\n }\n room.localParticipant.setMicrophoneEnabled(microphone.enabled);\n }, [microphone.enabled, agentConnectionState]);\n\n useUpdateEffect(() => {\n if (agentConnectionState !== 'joined') {\n return;\n }\n room.localParticipant.setCameraEnabled(camera.enabled, {\n resolution: { width: 1920, height: 1080 },\n });\n }, [camera.enabled, agentConnectionState]);\n\n useEffect(() => {\n if (!autoJoin) {\n return;\n }\n\n if (conversationStatus === 'created') {\n void join();\n }\n }, [conversationStatus, autoJoin]);\n\n useEffect(() => {\n if (!joinedAt || conversation.data?.limit === undefined) {\n return;\n }\n\n timer.restart(new Date(joinedAt.getTime() + conversation.data!.limit!));\n }, [joinedAt, conversation.data?.limit]);\n\n async function join() {\n invariant(userConnectionState === 'idle', 'Already joined');\n invariant(conversation.data, 'Conversation is not ready');\n const url = new URL(conversation?.data?.url || '');\n const accessToken = url.searchParams.get('token');\n try {\n setUserConnectionState('joining');\n await room?.connect(conversation.data.url, accessToken!, {});\n\n // sometimes the agent is already joined before the user joins the conversation\n const remoteParticipant = findJoinedAgentParticipant(room, type);\n if (remoteParticipant && agentConnectionState !== 'joined') {\n handleAgentJoin(remoteParticipant);\n }\n\n enableMediaDevices();\n } catch (error) {\n console.error('Failed to join', error);\n setUserConnectionState('join-error');\n }\n }\n\n function enableMediaDevices() {\n if (startWithMicrophone) {\n setMicrophone({ ...microphone, enabled: true });\n }\n if (startWithCamera && type === 'video') {\n setCamera({ ...camera, enabled: true });\n }\n }\n\n function handleTranscriptionReceivedEvent(\n segments: TranscriptionSegment[],\n participant?: Participant,\n ) {\n const transcriptions: ConversationTranscription[] = segments.map((s) => ({\n id: s.id,\n message: s.text,\n source: participant?.kind === ParticipantKind.AGENT ? 'agent' : 'user',\n }));\n\n setTranscriptions((old) => mergeTranscriptions(transcriptions, old));\n }\n\n function handleTurnDetectionEvent(data: TurnDetectionData) {\n const conversationId = conversationRef.current?.id;\n const { participantKind, state: eventState } = data;\n switch (participantKind) {\n case 'STANDARD':\n if (eventState === 'listening') {\n latestTurnMetadataRef.current = {\n turnDetectionStrategy: data.turnDetectionStrategy,\n sequence: data.sequence,\n speechId: data.speechId,\n };\n }\n emitEvent(\n eventState === 'speaking' ? 'userSpeakStart' : 'userSpeakStop',\n { conversationId: conversationId! },\n );\n setUserActivityState(eventState);\n break;\n case 'AGENT':\n if (data.speechId) {\n latestTurnMetadataRef.current = {\n ...latestTurnMetadataRef.current,\n speechId: data.speechId,\n };\n }\n emitEvent(\n eventState === 'speaking' ? 'agentSpeakStart' : 'agentSpeakStop',\n { conversationId: conversationId! },\n );\n setAgentActivityState(eventState);\n break;\n }\n }\n\n function handleAcousticUserOnset() {\n if (!isConnectedRef.current) {\n return;\n }\n if (acousticPhaseRef.current === 'waitingForAgent') {\n acousticPhaseRef.current = 'idle';\n acousticT0Ref.current = null;\n }\n }\n\n function handleAcousticUserOffset(timestampMs: number) {\n if (!isConnectedRef.current || acousticPhaseRef.current !== 'idle') {\n return;\n }\n acousticT0Ref.current = timestampMs - ACOUSTIC_USER_HANGOVER_MS;\n acousticPhaseRef.current = 'waitingForAgent';\n }\n\n function handleAcousticAgentOnset(timestampMs: number) {\n if (\n !isConnectedRef.current ||\n acousticPhaseRef.current !== 'waitingForAgent' ||\n acousticT0Ref.current == null\n ) {\n return;\n }\n\n const latencyMs = timestampMs - acousticT0Ref.current;\n acousticT0Ref.current = null;\n acousticPhaseRef.current = 'busy';\n\n if (latencyMs < 0 || latencyMs > 15000) {\n return;\n }\n\n emitEvent('responseLatency', {\n conversationId: conversationRef.current?.id!,\n latencyMs,\n turnDetectionStrategy:\n latestTurnMetadataRef.current.turnDetectionStrategy!,\n sequence: latestTurnMetadataRef.current.sequence,\n speechId: latestTurnMetadataRef.current.speechId,\n });\n\n void emitConversationTurnLatency(latencyMs);\n }\n\n async function emitConversationTurnLatency(clientAcousticLatencyMs: number) {\n const [userReport, agentReport] = await Promise.all([\n getTrackStats(userMicPublication),\n getTrackStats(agentMicPublication),\n ]);\n const userStats = parseTrackStats(\n userReport,\n userCumulativeTrackStatsRef.current,\n );\n const agentStats = parseTrackStats(\n agentReport,\n agentCumulativeTrackStatsRef.current,\n );\n userCumulativeTrackStatsRef.current = userStats.cumulativeTrackStats;\n agentCumulativeTrackStatsRef.current = agentStats.cumulativeTrackStats;\n\n emitEvent('conversationTurnLatency', {\n conversationId: conversationRef.current?.id!,\n speechId: latestTurnMetadataRef.current.speechId,\n sequence: latestTurnMetadataRef.current.sequence,\n clientAcousticLatencyMs,\n rttMs: userStats.roundTripTimeMs,\n jitterBufferDelayMs: agentStats.jitterBufferDelayMs,\n userPacketsLost: userStats.packetsLost,\n agentPacketsLost: agentStats.packetsLost,\n });\n }\n\n function handleAcousticAgentOffset() {\n acousticPhaseRef.current = 'idle';\n }\n\n useSpeechActivityDetector({\n source: 'user',\n onSpeechStart: handleAcousticUserOnset,\n onSpeechEnd: handleAcousticUserOffset,\n thresholdRms: ACOUSTIC_USER_THRESHOLD_RMS,\n hangoverMs: ACOUSTIC_USER_HANGOVER_MS,\n });\n useSpeechActivityDetector({\n source: 'agent',\n onSpeechStart: handleAcousticAgentOnset,\n onSpeechEnd: handleAcousticAgentOffset,\n hangoverMs: ACOUSTIC_AGENT_HANGOVER_MS,\n });\n\n function handleInactivityWarningEvent(data: InactivityWarningData) {\n emitEvent('inactivityWarning', {\n conversationId: conversationRef.current?.id!,\n gracePeriodSec: data.grace_period_sec,\n });\n }\n\n function handleInactivityTimeoutEvent(_data: InactivityTimeoutData) {\n inactivityTimeoutRef.current = true;\n emitEvent('inactivityTimeout', {\n conversationId: conversationRef.current?.id!,\n });\n }\n\n async function handleGetToolsRpc() {\n return JSON.stringify(buildToolDefinitions(toolsRegistryRef.current));\n }\n\n async function handleExecuteToolRpc(data: RpcInvocationData) {\n const call = parseFunctionCallPayload(data.payload);\n if (!call) {\n return JSON.stringify({\n functionCallId: '',\n result: '',\n error: 'Malformed function call payload.',\n } satisfies FunctionCallResult);\n }\n try {\n const [result] = await toolRuntimeRef.current.executeToolCalls([call]);\n return JSON.stringify(result);\n } catch (error) {\n return JSON.stringify({\n functionCallId: call.functionCallId,\n result: '',\n error: extractToolErrorMessage(error),\n } satisfies FunctionCallResult);\n }\n }\n\n const dataChannelHandlers: {\n guard: (data: unknown) => boolean;\n handle: (data: unknown) => void | Promise<void>;\n }[] = [\n {\n guard: checkIsTurnDetectionData,\n handle: handleTurnDetectionEvent as (data: unknown) => void,\n },\n {\n guard: checkIsInactivityWarningData,\n handle: handleInactivityWarningEvent as (data: unknown) => void,\n },\n {\n guard: checkIsInactivityTimeoutData,\n handle: handleInactivityTimeoutEvent as (data: unknown) => void,\n },\n ];\n\n function handleDataReceivedEvent(\n payload: Uint8Array,\n _participant?: RemoteParticipant,\n _kind?: unknown,\n topic?: string,\n ) {\n const decoded = decodeDataPayload(payload);\n if (decoded === null) {\n return;\n }\n if (checkIsCreditExhaustedMessage(decoded, topic)) {\n creditExhaustedRef.current = true;\n emitEvent('creditExhausted', {\n conversationId: conversationRef.current?.id!,\n });\n return;\n }\n for (const { guard, handle } of dataChannelHandlers) {\n if (guard(decoded)) {\n void Promise.resolve(handle(decoded)).catch((error) => {\n console.error('Failed to handle data channel payload', error);\n });\n return;\n }\n }\n }\n\n function handleConnectedEvent() {\n isConnectedRef.current = true;\n setUserConnectionState('joined');\n setAgentConnectionState('joining');\n emitEvent('callStarted', {\n conversationId: conversationRef.current?.id!,\n });\n }\n\n async function handleEncryptionErrorEvent(error: Error) {\n console.error('Encryption error', error);\n setConversationStatus('error');\n }\n\n function handleDisconnectedEvent(reason?: DisconnectReason) {\n isConnectedRef.current = false;\n acousticPhaseRef.current = 'idle';\n acousticT0Ref.current = null;\n latestTurnMetadataRef.current = {};\n userCumulativeTrackStatsRef.current = undefined;\n agentCumulativeTrackStatsRef.current = undefined;\n setAgentActivityState('idle');\n setAgentConnectionState('idle');\n setUserActivityState('idle');\n setUserConnectionState('idle');\n\n if (inactivityTimeoutRef.current) {\n inactivityTimeoutRef.current = false;\n setConversationStatus('inactivity-timeout');\n return;\n }\n\n if (creditExhaustedRef.current) {\n creditExhaustedRef.current = false;\n setConversationStatus('credit-exhausted');\n return;\n }\n\n switch (reason) {\n case DisconnectReason.CLIENT_INITIATED:\n break;\n case DisconnectReason.ROOM_CLOSED:\n setConversationStatus('destroyed');\n break;\n default:\n console.error('Conversation disconnected with reason', reason);\n setConversationStatus('error');\n break;\n }\n }\n\n function handleParticipantConnectedEvent(participant: RemoteParticipant) {\n if (shouldHandleParticipantConnected(participant, type)) {\n handleAgentJoin(participant);\n }\n }\n\n function handleAgentJoin(participant: RemoteParticipant) {\n setAgentConnectionState('joined');\n emitEvent('agentJoined', {\n conversationId: conversationRef.current?.id!,\n participant,\n });\n }\n\n function handleParticipantDisconnectedEvent(participant: RemoteParticipant) {\n setAgentConnectionState('left');\n emitEvent('agentLeft', {\n conversationId: conversationRef.current?.id!,\n participant,\n });\n }\n\n async function leave() {\n if (userConnectionState !== 'joined' && userConnectionState !== 'joining') {\n return;\n }\n\n try {\n setUserConnectionState('leaving');\n await room?.disconnect(true);\n setConversationStatus('destroyed');\n setJoinedAt(undefined);\n emitEvent('callEnded', {\n conversationId: conversationRef.current?.id!,\n });\n } catch (error) {\n console.error('Failed to leave', error);\n setConversationStatus('error');\n }\n }\n\n async function handleExpire() {\n // The duration timer keeps running after the call ends.\n if (conversationStatus === 'credit-exhausted') {\n return;\n }\n emitEvent('timeExceeded', {\n conversationId: conversationRef.current?.id!,\n limit: conversationRef.current?.limit!,\n });\n await leave();\n setConversationStatus('exceeded');\n }\n\n async function interrupt() {\n emitEvent('interrupt', {\n conversationId: conversationRef.current?.id!,\n });\n\n await publishConversationDataMessage(room, {}, 'interrupt');\n }\n\n async function dismissInactivity() {\n await publishConversationDataMessage(\n room,\n { type: 'inactivity_dismiss' },\n 'inactivity_dismiss',\n );\n }\n\n async function send(message: string, attachments: Attachment[] = []) {\n await room?.localParticipant.sendText(message, {\n topic: 'lk.chat',\n attributes: {\n attachments: safeStringify(attachments),\n },\n });\n emitEvent('userSendMessage', {\n conversationId: conversationRef.current?.id!,\n message,\n });\n }\n\n function registerRoomEvents() {\n room\n .on('connected', handleConnectedEvent)\n .on('encryptionError', handleEncryptionErrorEvent)\n .on('disconnected', handleDisconnectedEvent)\n .on('transcriptionReceived', handleTranscriptionReceivedEvent)\n .on('participantConnected', handleParticipantConnectedEvent)\n .on('participantDisconnected', handleParticipantDisconnectedEvent)\n .on('dataReceived', handleDataReceivedEvent);\n room.unregisterRpcMethod(GET_TOOLS_RPC_METHOD);\n room.unregisterRpcMethod(EXECUTE_TOOL_RPC_METHOD);\n room.registerRpcMethod(GET_TOOLS_RPC_METHOD, handleGetToolsRpc);\n room.registerRpcMethod(EXECUTE_TOOL_RPC_METHOD, handleExecuteToolRpc);\n }\n\n function unregisterRoomEvents() {\n room.unregisterRpcMethod(GET_TOOLS_RPC_METHOD);\n room.unregisterRpcMethod(EXECUTE_TOOL_RPC_METHOD);\n room.off('connected', handleConnectedEvent);\n room.off('encryptionError', handleEncryptionErrorEvent);\n room.off('disconnected', handleDisconnectedEvent);\n room.off('transcriptionReceived', handleTranscriptionReceivedEvent);\n room.off('participantConnected', handleParticipantConnectedEvent);\n room.off('participantDisconnected', handleParticipantDisconnectedEvent);\n room.off('dataReceived', handleDataReceivedEvent);\n }\n\n return {\n status: conversationStatus,\n conversation: conversation.data,\n join,\n send,\n interrupt,\n dismissInactivity,\n leave,\n };\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
|
+
exports.checkIsCreditExhaustedMessage = checkIsCreditExhaustedMessage;
|
|
4
5
|
exports.checkIsInactivityTimeoutData = checkIsInactivityTimeoutData;
|
|
5
6
|
exports.checkIsInactivityWarningData = checkIsInactivityWarningData;
|
|
6
7
|
exports.checkIsTurnDetectionData = checkIsTurnDetectionData;
|
|
@@ -22,4 +23,7 @@ function checkIsInactivityWarningData(data) {
|
|
|
22
23
|
function checkIsInactivityTimeoutData(data) {
|
|
23
24
|
return typeof data === 'object' && data !== null && 'type' in data && data.type === 'inactivity_timeout';
|
|
24
25
|
}
|
|
26
|
+
function checkIsCreditExhaustedMessage(data, topic) {
|
|
27
|
+
return topic === 'billing' && typeof data === 'object' && data !== null && data.type === 'ended' && data.reason === 'insufficient_credit';
|
|
28
|
+
}
|
|
25
29
|
//# sourceMappingURL=dataChannel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["decodeDataPayload","data","JSON","parse","TextDecoder","decode","error","console","checkIsTurnDetectionData","checkIsInactivityWarningData","type","grace_period_sec","checkIsInactivityTimeoutData"],"sources":["../../../../../../src/hooks/useConversation/livekit/utils/dataChannel.ts"],"sourcesContent":["import type {\n InactivityWarningData,\n InactivityTimeoutData,\n TurnDetectionData,\n} from '../types';\n\nexport function decodeDataPayload(data: Uint8Array): unknown {\n try {\n return JSON.parse(new TextDecoder().decode(data));\n } catch (error) {\n console.error('Failed to decode data received payload', error);\n return null;\n }\n}\n\nexport function checkIsTurnDetectionData(\n data: unknown,\n): data is TurnDetectionData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'participantKind' in data &&\n 'state' in data\n );\n}\n\nexport function checkIsInactivityWarningData(\n data: unknown,\n): data is InactivityWarningData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n (data as Record<string, unknown>).type === 'inactivity_warning' &&\n 'grace_period_sec' in data &&\n typeof (data as Record<string, unknown>).grace_period_sec === 'number'\n );\n}\n\nexport function checkIsInactivityTimeoutData(\n data: unknown,\n): data is InactivityTimeoutData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n (data as Record<string, unknown>).type === 'inactivity_timeout'\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"names":["decodeDataPayload","data","JSON","parse","TextDecoder","decode","error","console","checkIsTurnDetectionData","checkIsInactivityWarningData","type","grace_period_sec","checkIsInactivityTimeoutData","checkIsCreditExhaustedMessage","topic","reason"],"sources":["../../../../../../src/hooks/useConversation/livekit/utils/dataChannel.ts"],"sourcesContent":["import type {\n InactivityWarningData,\n InactivityTimeoutData,\n TurnDetectionData,\n} from '../types';\n\nexport function decodeDataPayload(data: Uint8Array): unknown {\n try {\n return JSON.parse(new TextDecoder().decode(data));\n } catch (error) {\n console.error('Failed to decode data received payload', error);\n return null;\n }\n}\n\nexport function checkIsTurnDetectionData(\n data: unknown,\n): data is TurnDetectionData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'participantKind' in data &&\n 'state' in data\n );\n}\n\nexport function checkIsInactivityWarningData(\n data: unknown,\n): data is InactivityWarningData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n (data as Record<string, unknown>).type === 'inactivity_warning' &&\n 'grace_period_sec' in data &&\n typeof (data as Record<string, unknown>).grace_period_sec === 'number'\n );\n}\n\nexport function checkIsInactivityTimeoutData(\n data: unknown,\n): data is InactivityTimeoutData {\n return (\n typeof data === 'object' &&\n data !== null &&\n 'type' in data &&\n (data as Record<string, unknown>).type === 'inactivity_timeout'\n );\n}\n\nexport function checkIsCreditExhaustedMessage(\n data: unknown,\n topic: string | undefined,\n): boolean {\n return (\n topic === 'billing' &&\n typeof data === 'object' &&\n data !== null &&\n (data as Record<string, unknown>).type === 'ended' &&\n (data as Record<string, unknown>).reason === 'insufficient_credit'\n );\n}\n"],"mappings":";;;;;;;;AAMO,SAASA,iBAAiBA,CAACC,IAAgB,EAAW;EAC3D,IAAI;IACF,OAAOC,IAAI,CAACC,KAAK,CAAC,IAAIC,WAAW,CAAC,CAAC,CAACC,MAAM,CAACJ,IAAI,CAAC,CAAC;EACnD,CAAC,CAAC,OAAOK,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,wCAAwC,EAAEA,KAAK,CAAC;IAC9D,OAAO,IAAI;EACb;AACF;AAEO,SAASE,wBAAwBA,CACtCP,IAAa,EACc;EAC3B,OACE,OAAOA,IAAI,KAAK,QAAQ,IACxBA,IAAI,KAAK,IAAI,IACb,iBAAiB,IAAIA,IAAI,IACzB,OAAO,IAAIA,IAAI;AAEnB;AAEO,SAASQ,4BAA4BA,CAC1CR,IAAa,EACkB;EAC/B,OACE,OAAOA,IAAI,KAAK,QAAQ,IACxBA,IAAI,KAAK,IAAI,IACb,MAAM,IAAIA,IAAI,IACbA,IAAI,CAA6BS,IAAI,KAAK,oBAAoB,IAC/D,kBAAkB,IAAIT,IAAI,IAC1B,OAAQA,IAAI,CAA6BU,gBAAgB,KAAK,QAAQ;AAE1E;AAEO,SAASC,4BAA4BA,CAC1CX,IAAa,EACkB;EAC/B,OACE,OAAOA,IAAI,KAAK,QAAQ,IACxBA,IAAI,KAAK,IAAI,IACb,MAAM,IAAIA,IAAI,IACbA,IAAI,CAA6BS,IAAI,KAAK,oBAAoB;AAEnE;AAEO,SAASG,6BAA6BA,CAC3CZ,IAAa,EACba,KAAyB,EAChB;EACT,OACEA,KAAK,KAAK,SAAS,IACnB,OAAOb,IAAI,KAAK,QAAQ,IACxBA,IAAI,KAAK,IAAI,IACZA,IAAI,CAA6BS,IAAI,KAAK,OAAO,IACjDT,IAAI,CAA6Bc,MAAM,KAAK,qBAAqB;AAEtE","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["../../../../src/hooks/useConversationEvents/types.tsx"],"sourcesContent":["import React from 'react';\nimport type { RemoteParticipant } from 'livekit-client';\n\nexport type UserSpeakStartPayload = {\n conversationId: string;\n};\n\nexport type TimeExceededPayload = {\n conversationId: string;\n limit: number;\n};\n\nexport type UserSpeakStopPayload = {\n conversationId: string;\n};\n\nexport type AgentSpeakStartPayload = {\n conversationId: string;\n};\n\nexport type AgentSpeakStopPayload = {\n conversationId: string;\n};\n\nexport type ResponseLatencyPayload = {\n conversationId: string;\n latencyMs: number;\n turnDetectionStrategy: string;\n sequence?: number;\n speechId?: string;\n};\n\nexport type ConversationTurnLatencyPayload = {\n conversationId: string;\n speechId?: string;\n sequence?: number;\n clientAcousticLatencyMs: number;\n rttMs?: number;\n jitterBufferDelayMs?: number;\n userPacketsLost?: number;\n agentPacketsLost?: number;\n};\n\nexport type InterruptPayload = {\n conversationId: string;\n};\n\nexport type CallStartedPayload = {\n conversationId: string;\n};\n\nexport type CallEndedPayload = {\n conversationId: string;\n};\n\nexport type UserSendMessagePayload = {\n conversationId: string;\n message: string;\n};\n\nexport type AgentJoinedPayload = {\n conversationId: string;\n participant: RemoteParticipant;\n};\n\nexport type AgentLeftPayload = {\n conversationId: string;\n participant?: RemoteParticipant;\n};\n\nexport type AgentVideoLoadedPayload = {\n videoRef: React.RefObject<HTMLVideoElement>;\n};\n\nexport type InactivityWarningPayload = {\n conversationId: string;\n gracePeriodSec: number;\n};\n\nexport type InactivityTimeoutPayload = {\n conversationId: string;\n};\n\nexport type ConversationEventMap = {\n userSpeakStart: UserSpeakStartPayload;\n userSpeakStop: UserSpeakStopPayload;\n agentSpeakStart: AgentSpeakStartPayload;\n agentSpeakStop: AgentSpeakStopPayload;\n responseLatency: ResponseLatencyPayload;\n conversationTurnLatency: ConversationTurnLatencyPayload;\n interrupt: InterruptPayload;\n callStarted: CallStartedPayload;\n callEnded: CallEndedPayload;\n userSendMessage: UserSendMessagePayload;\n agentJoined: AgentJoinedPayload;\n agentLeft: AgentLeftPayload;\n timeExceeded: TimeExceededPayload;\n agentVideoLoaded: AgentVideoLoadedPayload;\n inactivityWarning: InactivityWarningPayload;\n inactivityTimeout: InactivityTimeoutPayload;\n};\n\nexport type ConversationEvent = keyof ConversationEventMap;\n\nexport type EventPayload<T extends ConversationEvent> = ConversationEventMap[T];\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["../../../../src/hooks/useConversationEvents/types.tsx"],"sourcesContent":["import React from 'react';\nimport type { RemoteParticipant } from 'livekit-client';\n\nexport type UserSpeakStartPayload = {\n conversationId: string;\n};\n\nexport type TimeExceededPayload = {\n conversationId: string;\n limit: number;\n};\n\nexport type UserSpeakStopPayload = {\n conversationId: string;\n};\n\nexport type AgentSpeakStartPayload = {\n conversationId: string;\n};\n\nexport type AgentSpeakStopPayload = {\n conversationId: string;\n};\n\nexport type ResponseLatencyPayload = {\n conversationId: string;\n latencyMs: number;\n turnDetectionStrategy: string;\n sequence?: number;\n speechId?: string;\n};\n\nexport type ConversationTurnLatencyPayload = {\n conversationId: string;\n speechId?: string;\n sequence?: number;\n clientAcousticLatencyMs: number;\n rttMs?: number;\n jitterBufferDelayMs?: number;\n userPacketsLost?: number;\n agentPacketsLost?: number;\n};\n\nexport type InterruptPayload = {\n conversationId: string;\n};\n\nexport type CallStartedPayload = {\n conversationId: string;\n};\n\nexport type CallEndedPayload = {\n conversationId: string;\n};\n\nexport type UserSendMessagePayload = {\n conversationId: string;\n message: string;\n};\n\nexport type AgentJoinedPayload = {\n conversationId: string;\n participant: RemoteParticipant;\n};\n\nexport type AgentLeftPayload = {\n conversationId: string;\n participant?: RemoteParticipant;\n};\n\nexport type AgentVideoLoadedPayload = {\n videoRef: React.RefObject<HTMLVideoElement>;\n};\n\nexport type InactivityWarningPayload = {\n conversationId: string;\n gracePeriodSec: number;\n};\n\nexport type InactivityTimeoutPayload = {\n conversationId: string;\n};\n\nexport type CreditExhaustedPayload = {\n conversationId: string;\n};\n\nexport type ConversationEventMap = {\n userSpeakStart: UserSpeakStartPayload;\n userSpeakStop: UserSpeakStopPayload;\n agentSpeakStart: AgentSpeakStartPayload;\n agentSpeakStop: AgentSpeakStopPayload;\n responseLatency: ResponseLatencyPayload;\n conversationTurnLatency: ConversationTurnLatencyPayload;\n interrupt: InterruptPayload;\n callStarted: CallStartedPayload;\n callEnded: CallEndedPayload;\n userSendMessage: UserSendMessagePayload;\n agentJoined: AgentJoinedPayload;\n agentLeft: AgentLeftPayload;\n timeExceeded: TimeExceededPayload;\n agentVideoLoaded: AgentVideoLoadedPayload;\n inactivityWarning: InactivityWarningPayload;\n inactivityTimeout: InactivityTimeoutPayload;\n creditExhausted: CreditExhaustedPayload;\n};\n\nexport type ConversationEvent = keyof ConversationEventMap;\n\nexport type EventPayload<T extends ConversationEvent> = ConversationEventMap[T];\n"],"mappings":"","ignoreList":[]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
exports.__esModule = true;
|
|
4
4
|
exports.createObjectScanner = createObjectScanner;
|
|
5
|
+
exports.extractCanSendChatMessage = extractCanSendChatMessage;
|
|
5
6
|
exports.extractContent = extractContent;
|
|
6
7
|
exports.streamChatMessage = streamChatMessage;
|
|
7
8
|
// Same-origin Wix persona-chat gateway path. The transport always posts here
|
|
@@ -38,6 +39,17 @@ function extractContent(frame) {
|
|
|
38
39
|
return null;
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
// Same lookup order as extractContent: top level first, then the gateway body.
|
|
43
|
+
function extractCanSendChatMessage(frame) {
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(frame);
|
|
46
|
+
const payload = typeof parsed.canSendChatMessage === 'boolean' || typeof parsed.body !== 'string' ? parsed : JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(parsed.body), char => char.charCodeAt(0))));
|
|
47
|
+
return typeof payload.canSendChatMessage === 'boolean' ? payload.canSendChatMessage : null;
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
// Feeds decoded text through a running scanner that emits each complete
|
|
42
54
|
// top-level `{…}` object as its closing brace arrives.
|
|
43
55
|
function createObjectScanner(onObject) {
|
|
@@ -91,7 +103,8 @@ async function streamChatMessage(params, callbacks, signal) {
|
|
|
91
103
|
const {
|
|
92
104
|
onChunk,
|
|
93
105
|
onDone,
|
|
94
|
-
onError
|
|
106
|
+
onError,
|
|
107
|
+
onCanSendChatMessage
|
|
95
108
|
} = callbacks;
|
|
96
109
|
const xsrfToken = readCookie('XSRF-TOKEN');
|
|
97
110
|
const autoXsrf = !(headers != null && headers['x-xsrf-token']) && xsrfToken ? {
|
|
@@ -126,6 +139,10 @@ async function streamChatMessage(params, callbacks, signal) {
|
|
|
126
139
|
if (content !== null) {
|
|
127
140
|
onChunk(content);
|
|
128
141
|
}
|
|
142
|
+
const canSend = extractCanSendChatMessage(frame);
|
|
143
|
+
if (canSend !== null) {
|
|
144
|
+
onCanSendChatMessage == null || onCanSendChatMessage(canSend);
|
|
145
|
+
}
|
|
129
146
|
});
|
|
130
147
|
const reader = response.body.getReader();
|
|
131
148
|
const decoder = new TextDecoder();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["DEFAULT_STREAM_PATH","readCookie","name","_document$cookie$spli","document","undefined","cookie","split","map","part","trim","find","startsWith","slice","length","extractContent","frame","parsed","JSON","parse","content","body","decoded","TextDecoder","decode","Uint8Array","from","atob","char","charCodeAt","inner","createObjectScanner","onObject","buffer","cursor","braceDepth","objectStart","inString","escaped","feed","text","streamChatMessage","params","callbacks","signal","chatId","message","namespace","chatConfig","attachments","metadata","headers","onChunk","onDone","onError","xsrfToken","autoXsrf","response","fetch","method","credentials","stringify","ok","Error","status","scanForObjects","reader","getReader","decoder","done","value","read","stream","err"],"sources":["../../../../src/hooks/useTextChat/streamChatMessage.ts"],"sourcesContent":["// Same-origin Wix persona-chat gateway path. The transport always posts here\n// with `credentials: 'include'`, so the session cookie rides along and a\n// consumer needs no proxy route of its own.\nconst DEFAULT_STREAM_PATH =\n '/_api/persona-chat-service/v1/chat/messages/stream';\n\nexport type StreamCallbacks = {\n onChunk: (token: string) => void;\n onDone: () => void;\n onError: (err: Error) => void;\n};\n\nexport type StreamChatMessageParams = {\n chatId: string;\n message: string;\n namespace: string;\n chatConfig?: object;\n attachments?: object[];\n // Request metadata forwarded to the RPC (e.g. `additionalMetadata` carrying\n // opening-message context). Mirrors the top-level `metadata` object the unary\n // `sendChatMessage` request accepts, so a streamed send carries it identically.\n metadata?: object;\n // Extra request headers merged onto the POST. Lets the caller satisfy the\n // host's transport requirements the SDK can't know about — e.g. an\n // `x-xsrf-token` when the endpoint sits behind a CSRF-protected gateway.\n headers?: Record<string, string>;\n};\n\n// Read a cookie value by name in the browser. Returns undefined outside a\n// browser or when the cookie is absent.\nfunction readCookie(name: string): string | undefined {\n if (typeof document === 'undefined') {\n return undefined;\n }\n return document.cookie\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith(`${name}=`))\n ?.slice(name.length + 1);\n}\n\n// Pull the assistant text out of one streamed frame. Two framings reach us: the\n// proxy route yields `{ content }` objects, while the gateway wraps each frame\n// as `{ body: base64(json) }`. Returns null for frames without content.\nexport function extractContent(frame: string): string | null {\n try {\n const parsed = JSON.parse(frame);\n if (typeof parsed.content === 'string') {\n return parsed.content;\n }\n if (typeof parsed.body === 'string') {\n const decoded = new TextDecoder().decode(\n Uint8Array.from(atob(parsed.body), (char) => char.charCodeAt(0)),\n );\n const inner = JSON.parse(decoded);\n return typeof inner.content === 'string' ? inner.content : null;\n }\n } catch {\n // Incomplete or non-object frame — skip it.\n }\n return null;\n}\n\n// Feeds decoded text through a running scanner that emits each complete\n// top-level `{…}` object as its closing brace arrives.\nexport function createObjectScanner(onObject: (frame: string) => void) {\n let buffer = '';\n let cursor = 0;\n let braceDepth = 0;\n let objectStart = -1;\n let inString = false;\n let escaped = false;\n\n return function feed(text: string) {\n buffer += text;\n for (; cursor < buffer.length; cursor++) {\n const char = buffer[cursor];\n if (inString) {\n if (escaped) {\n escaped = false;\n } else if (char === '\\\\') {\n escaped = true;\n } else if (char === '\"') {\n inString = false;\n }\n continue;\n }\n if (char === '\"') {\n inString = true;\n } else if (char === '{') {\n if (braceDepth === 0) {\n objectStart = cursor;\n }\n braceDepth++;\n } else if (char === '}' && braceDepth > 0) {\n braceDepth--;\n if (braceDepth === 0 && objectStart >= 0) {\n onObject(buffer.slice(objectStart, cursor + 1));\n objectStart = -1;\n }\n }\n }\n };\n}\n\nexport async function streamChatMessage(\n params: StreamChatMessageParams,\n callbacks: StreamCallbacks,\n signal?: AbortSignal,\n): Promise<void> {\n const {\n chatId,\n message,\n namespace,\n chatConfig,\n attachments,\n metadata,\n headers,\n } = params;\n const { onChunk, onDone, onError } = callbacks;\n\n const xsrfToken = readCookie('XSRF-TOKEN');\n const autoXsrf =\n !headers?.['x-xsrf-token'] && xsrfToken\n ? { 'x-xsrf-token': xsrfToken }\n : undefined;\n\n try {\n // eslint-disable-next-line no-undef\n const response = await fetch(DEFAULT_STREAM_PATH, {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', ...autoXsrf, ...headers },\n body: JSON.stringify({\n chatId,\n message,\n namespace,\n chatConfig,\n attachments,\n metadata,\n }),\n signal,\n });\n\n if (!response.ok || !response.body) {\n onError(new Error(`Stream request failed: ${response.status}`));\n return;\n }\n\n const scanForObjects = createObjectScanner((frame) => {\n const content = extractContent(frame);\n if (content !== null) {\n onChunk(content);\n }\n });\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n scanForObjects(decoder.decode(value, { stream: true }));\n }\n scanForObjects(decoder.decode());\n onDone();\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n onError(err as Error);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["DEFAULT_STREAM_PATH","readCookie","name","_document$cookie$spli","document","undefined","cookie","split","map","part","trim","find","startsWith","slice","length","extractContent","frame","parsed","JSON","parse","content","body","decoded","TextDecoder","decode","Uint8Array","from","atob","char","charCodeAt","inner","extractCanSendChatMessage","payload","canSendChatMessage","createObjectScanner","onObject","buffer","cursor","braceDepth","objectStart","inString","escaped","feed","text","streamChatMessage","params","callbacks","signal","chatId","message","namespace","chatConfig","attachments","metadata","headers","onChunk","onDone","onError","onCanSendChatMessage","xsrfToken","autoXsrf","response","fetch","method","credentials","stringify","ok","Error","status","scanForObjects","canSend","reader","getReader","decoder","done","value","read","stream","err"],"sources":["../../../../src/hooks/useTextChat/streamChatMessage.ts"],"sourcesContent":["// Same-origin Wix persona-chat gateway path. The transport always posts here\n// with `credentials: 'include'`, so the session cookie rides along and a\n// consumer needs no proxy route of its own.\nconst DEFAULT_STREAM_PATH =\n '/_api/persona-chat-service/v1/chat/messages/stream';\n\nexport type StreamCallbacks = {\n onChunk: (token: string) => void;\n onDone: () => void;\n onError: (err: Error) => void;\n onCanSendChatMessage?: (canSend: boolean) => void;\n};\n\nexport type StreamChatMessageParams = {\n chatId: string;\n message: string;\n namespace: string;\n chatConfig?: object;\n attachments?: object[];\n // Request metadata forwarded to the RPC (e.g. `additionalMetadata` carrying\n // opening-message context). Mirrors the top-level `metadata` object the unary\n // `sendChatMessage` request accepts, so a streamed send carries it identically.\n metadata?: object;\n // Extra request headers merged onto the POST. Lets the caller satisfy the\n // host's transport requirements the SDK can't know about — e.g. an\n // `x-xsrf-token` when the endpoint sits behind a CSRF-protected gateway.\n headers?: Record<string, string>;\n};\n\n// Read a cookie value by name in the browser. Returns undefined outside a\n// browser or when the cookie is absent.\nfunction readCookie(name: string): string | undefined {\n if (typeof document === 'undefined') {\n return undefined;\n }\n return document.cookie\n .split(';')\n .map((part) => part.trim())\n .find((part) => part.startsWith(`${name}=`))\n ?.slice(name.length + 1);\n}\n\n// Pull the assistant text out of one streamed frame. Two framings reach us: the\n// proxy route yields `{ content }` objects, while the gateway wraps each frame\n// as `{ body: base64(json) }`. Returns null for frames without content.\nexport function extractContent(frame: string): string | null {\n try {\n const parsed = JSON.parse(frame);\n if (typeof parsed.content === 'string') {\n return parsed.content;\n }\n if (typeof parsed.body === 'string') {\n const decoded = new TextDecoder().decode(\n Uint8Array.from(atob(parsed.body), (char) => char.charCodeAt(0)),\n );\n const inner = JSON.parse(decoded);\n return typeof inner.content === 'string' ? inner.content : null;\n }\n } catch {\n // Incomplete or non-object frame — skip it.\n }\n return null;\n}\n\n// Same lookup order as extractContent: top level first, then the gateway body.\nexport function extractCanSendChatMessage(frame: string): boolean | null {\n try {\n const parsed = JSON.parse(frame);\n const payload =\n typeof parsed.canSendChatMessage === 'boolean' ||\n typeof parsed.body !== 'string'\n ? parsed\n : JSON.parse(\n new TextDecoder().decode(\n Uint8Array.from(atob(parsed.body), (char) => char.charCodeAt(0)),\n ),\n );\n return typeof payload.canSendChatMessage === 'boolean'\n ? payload.canSendChatMessage\n : null;\n } catch {\n return null;\n }\n}\n\n// Feeds decoded text through a running scanner that emits each complete\n// top-level `{…}` object as its closing brace arrives.\nexport function createObjectScanner(onObject: (frame: string) => void) {\n let buffer = '';\n let cursor = 0;\n let braceDepth = 0;\n let objectStart = -1;\n let inString = false;\n let escaped = false;\n\n return function feed(text: string) {\n buffer += text;\n for (; cursor < buffer.length; cursor++) {\n const char = buffer[cursor];\n if (inString) {\n if (escaped) {\n escaped = false;\n } else if (char === '\\\\') {\n escaped = true;\n } else if (char === '\"') {\n inString = false;\n }\n continue;\n }\n if (char === '\"') {\n inString = true;\n } else if (char === '{') {\n if (braceDepth === 0) {\n objectStart = cursor;\n }\n braceDepth++;\n } else if (char === '}' && braceDepth > 0) {\n braceDepth--;\n if (braceDepth === 0 && objectStart >= 0) {\n onObject(buffer.slice(objectStart, cursor + 1));\n objectStart = -1;\n }\n }\n }\n };\n}\n\nexport async function streamChatMessage(\n params: StreamChatMessageParams,\n callbacks: StreamCallbacks,\n signal?: AbortSignal,\n): Promise<void> {\n const {\n chatId,\n message,\n namespace,\n chatConfig,\n attachments,\n metadata,\n headers,\n } = params;\n const { onChunk, onDone, onError, onCanSendChatMessage } = callbacks;\n\n const xsrfToken = readCookie('XSRF-TOKEN');\n const autoXsrf =\n !headers?.['x-xsrf-token'] && xsrfToken\n ? { 'x-xsrf-token': xsrfToken }\n : undefined;\n\n try {\n // eslint-disable-next-line no-undef\n const response = await fetch(DEFAULT_STREAM_PATH, {\n method: 'POST',\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', ...autoXsrf, ...headers },\n body: JSON.stringify({\n chatId,\n message,\n namespace,\n chatConfig,\n attachments,\n metadata,\n }),\n signal,\n });\n\n if (!response.ok || !response.body) {\n onError(new Error(`Stream request failed: ${response.status}`));\n return;\n }\n\n const scanForObjects = createObjectScanner((frame) => {\n const content = extractContent(frame);\n if (content !== null) {\n onChunk(content);\n }\n const canSend = extractCanSendChatMessage(frame);\n if (canSend !== null) {\n onCanSendChatMessage?.(canSend);\n }\n });\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n scanForObjects(decoder.decode(value, { stream: true }));\n }\n scanForObjects(decoder.decode());\n onDone();\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n onError(err as Error);\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -139,6 +139,7 @@ function useTextChatStream(options = {}) {
|
|
|
139
139
|
let lastFrameTime = 0;
|
|
140
140
|
let receivedContent = false;
|
|
141
141
|
let errored = false;
|
|
142
|
+
let canSendChatMessage;
|
|
142
143
|
const settle = () => {
|
|
143
144
|
stopRaf();
|
|
144
145
|
const finalAssistantMsg = {
|
|
@@ -205,12 +206,14 @@ function useTextChatStream(options = {}) {
|
|
|
205
206
|
stopRaf();
|
|
206
207
|
onError == null || onError(err);
|
|
207
208
|
setStreamingMessages([]);
|
|
208
|
-
}
|
|
209
|
+
},
|
|
210
|
+
onCanSendChatMessage: canSend => canSendChatMessage = canSend
|
|
209
211
|
}, controller.signal);
|
|
210
212
|
return {
|
|
211
213
|
ok: streamDone && !errored,
|
|
212
214
|
producedContent: receivedContent,
|
|
213
|
-
aborted: !streamDone && !errored
|
|
215
|
+
aborted: !streamDone && !errored,
|
|
216
|
+
canSendChatMessage
|
|
214
217
|
};
|
|
215
218
|
}, [chatId, namespace, headers, onError, refetch, revealMsPerChar, stopRaf]);
|
|
216
219
|
return {
|