@@ -29,75 +29,89 @@ const useLayercodeAgent = (
2929) => {
3030 // Extract public options
3131 const { agentId, conversationId, authorizeSessionEndpoint, metadata = { } , onConnect, onDisconnect, onError, onDataMessage, onMessage, onMuteStateChange } = options ;
32+ const websocketUrlOverride = options [ '_websocketUrl' ] ;
3233
3334 const [ status , setStatus ] = useState ( 'initializing' ) ;
3435 const [ userAudioAmplitude , setUserAudioAmplitude ] = useState ( 0 ) ;
3536 const [ agentAudioAmplitude , setAgentAudioAmplitude ] = useState ( 0 ) ;
3637 const [ isMuted , setIsMuted ] = useState ( false ) ;
38+ const [ internalConversationId , setInternalConversationId ] = useState < string | null | undefined > ( conversationId ) ;
39+ const conversationIdRef = useRef < string | undefined > ( conversationId ) ;
3740 // Reference to the LayercodeClient instance
3841 const clientRef = useRef < LayercodeClient | null > ( null ) ;
3942
40- // Initialize the client on component mount
4143 useEffect ( ( ) => {
42- // Create a new LayercodeClient instance
43- console . log ( 'Creating LayercodeClient instance' ) ;
44- clientRef . current = new LayercodeClient ( {
45- agentId,
46- conversationId,
47- authorizeSessionEndpoint,
48- metadata,
49- onConnect : ( { conversationId } : { conversationId : string | null } ) => {
50- onConnect ?.( { conversationId } ) ;
51- } ,
52- onDisconnect : ( ) => {
53- onDisconnect ?.( ) ;
54- } ,
55- onError : ( error : Error ) => {
56- onError ?.( error ) ;
57- } ,
58- onDataMessage : ( data : any ) => {
59- onDataMessage ?.( data ) ;
60- } ,
61- onMessage : ( data : any ) => {
62- onMessage ?.( data ) ;
63- } ,
64- onStatusChange : ( newStatus : string ) => {
65- setStatus ( newStatus ) ;
66- } ,
67- onUserAmplitudeChange : ( amplitude : number ) => {
68- setUserAudioAmplitude ( amplitude ) ;
69- } ,
70- onAgentAmplitudeChange : ( amplitude : number ) => {
71- setAgentAudioAmplitude ( amplitude ) ;
72- } ,
73- onMuteStateChange : ( muted : boolean ) => {
74- setIsMuted ( muted ) ;
75- onMuteStateChange ?.( muted ) ;
76- } ,
77- } ) ;
78-
79- // Pass the override websocket URL if provided. Use for local development.
80- if ( options [ '_websocketUrl' ] ) {
81- clientRef . current . _websocketUrl = options [ '_websocketUrl' ] ;
44+ conversationIdRef . current = conversationId ;
45+ if ( conversationId !== undefined ) {
46+ setInternalConversationId ( conversationId ) ;
47+ } else {
48+ setInternalConversationId ( undefined ) ;
8249 }
50+ } , [ conversationId ] ) ;
8351
84- // Set initial mute state from JS SDK
85- setIsMuted ( clientRef . current . isMuted ) ;
86-
87- // Connect to the agent
88- clientRef . current . connect ( ) . catch ( ( error : Error ) => {
89- console . error ( 'Failed to connect to agent:' , error ) ;
90- onError ?.( error ) ;
91- } ) ;
52+ const createClient = useCallback (
53+ ( initialConversationId : string | null ) => {
54+ console . log ( 'Creating LayercodeClient instance' ) ;
55+ const client = new LayercodeClient ( {
56+ agentId,
57+ conversationId : initialConversationId ,
58+ authorizeSessionEndpoint,
59+ metadata,
60+ onConnect : ( { conversationId } : { conversationId : string | null } ) => {
61+ setInternalConversationId ( ( current ) => {
62+ if ( conversationIdRef . current === undefined ) {
63+ return conversationId ;
64+ }
65+ return conversationId ?? current ?? null ;
66+ } ) ;
67+ onConnect ?.( { conversationId } ) ;
68+ } ,
69+ onDisconnect : ( ) => {
70+ onDisconnect ?.( ) ;
71+ } ,
72+ onError : ( error : Error ) => {
73+ onError ?.( error ) ;
74+ } ,
75+ onDataMessage : ( data : any ) => {
76+ onDataMessage ?.( data ) ;
77+ } ,
78+ onMessage : ( data : any ) => {
79+ onMessage ?.( data ) ;
80+ } ,
81+ onStatusChange : ( newStatus : string ) => {
82+ setStatus ( newStatus ) ;
83+ } ,
84+ onUserAmplitudeChange : ( amplitude : number ) => {
85+ setUserAudioAmplitude ( amplitude ) ;
86+ } ,
87+ onAgentAmplitudeChange : ( amplitude : number ) => {
88+ setAgentAudioAmplitude ( amplitude ) ;
89+ } ,
90+ onMuteStateChange : ( muted : boolean ) => {
91+ setIsMuted ( muted ) ;
92+ onMuteStateChange ?.( muted ) ;
93+ } ,
94+ } ) ;
95+
96+ if ( websocketUrlOverride ) {
97+ client . _websocketUrl = websocketUrlOverride ;
98+ }
9299
93- // Cleanup function to disconnect when component unmounts
100+ setIsMuted ( client . isMuted ) ;
101+ clientRef . current = client ;
102+ return client ;
103+ } ,
104+ [ agentId , authorizeSessionEndpoint , metadata , onConnect , onDataMessage , onDisconnect , onError , onMessage , onMuteStateChange , websocketUrlOverride ]
105+ ) ;
106+
107+ useEffect ( ( ) => {
94108 return ( ) => {
95109 if ( clientRef . current ) {
96110 clientRef . current . disconnect ( ) ;
111+ clientRef . current = null ;
97112 }
98113 } ;
99- // Add the internal override URL to the dependency array
100- } , [ agentId , conversationId , authorizeSessionEndpoint ] ) ; // Make sure metadata isn't causing unnecessary re-renders if it changes often
114+ } , [ ] ) ;
101115
102116 // Class methods
103117 const mute = useCallback ( ( ) => {
@@ -114,12 +128,47 @@ const useLayercodeAgent = (
114128 const triggerUserTurnFinished = useCallback ( ( ) => {
115129 clientRef . current ?. triggerUserTurnFinished ( ) ;
116130 } , [ ] ) ;
117- const connect = useCallback ( ( ) => {
118- clientRef . current ?. connect ( ) ;
119- } , [ ] ) ;
120- const disconnect = useCallback ( ( ) => {
121- clientRef . current ?. disconnect ( ) ;
122- } , [ ] ) ;
131+ const connect = useCallback ( async ( ) => {
132+ if ( clientRef . current ) {
133+ try {
134+ await clientRef . current . disconnect ( ) ;
135+ } catch ( error ) {
136+ console . error ( 'Failed to disconnect existing client before reconnect:' , error ) ;
137+ }
138+ clientRef . current = null ;
139+ }
140+
141+ const nextConversationId =
142+ conversationIdRef . current !== undefined
143+ ? conversationIdRef . current
144+ : internalConversationId ?? null ;
145+
146+ const client = createClient ( nextConversationId ?? null ) ;
147+
148+ try {
149+ await client . connect ( ) ;
150+ } catch ( error ) {
151+ console . error ( 'Failed to connect to agent:' , error ) ;
152+ onError ?.( error as Error ) ;
153+ throw error ;
154+ }
155+ } , [ createClient , internalConversationId , onError ] ) ;
156+ const disconnect = useCallback ( async ( ) => {
157+ if ( ! clientRef . current ) {
158+ return ;
159+ }
160+
161+ const client = clientRef . current ;
162+ clientRef . current = null ;
163+
164+ try {
165+ await client . disconnect ( ) ;
166+ } catch ( error ) {
167+ console . error ( 'Failed to disconnect from agent:' , error ) ;
168+ onError ?.( error as Error ) ;
169+ throw error ;
170+ }
171+ } , [ onError ] ) ;
123172
124173 // Return methods and state
125174 return {
@@ -136,6 +185,7 @@ const useLayercodeAgent = (
136185 userAudioAmplitude,
137186 agentAudioAmplitude,
138187 isMuted,
188+ conversationId : internalConversationId ,
139189 } ;
140190} ;
141191
0 commit comments