@@ -241,6 +241,50 @@ export const useAgentTimeoutIdStore = (): {
241241
242242type SessionStub = Pick < UseSessionReturn , 'connectionState' | 'room' | 'internal' > ;
243243
244+ /** Internal hook used by useAgent which generates a function that when called, will return a
245+ * promise which resolves when agent.isAvailable is enabled. */
246+ function useAgentWaitUntilAvailable ( emitter : TypedEventEmitter < AgentCallbacks > , state : AgentState ) {
247+ const stateRef = React . useRef ( state ) ;
248+ React . useEffect ( ( ) => {
249+ stateRef . current = state ;
250+ } , [ state ] ) ;
251+
252+ const waitUntilAvailable = React . useCallback (
253+ async ( signal ?: AbortSignal ) => {
254+ const { isAvailable } = generateDerivedStateValues ( stateRef . current ) ;
255+ if ( isAvailable ) {
256+ return ;
257+ }
258+
259+ return new Promise < void > ( ( resolve , reject ) => {
260+ const stateChangedHandler = ( state : AgentState ) => {
261+ const { isAvailable } = generateDerivedStateValues ( state ) ;
262+ if ( ! isAvailable ) {
263+ return ;
264+ }
265+ cleanup ( ) ;
266+ resolve ( ) ;
267+ } ;
268+ const abortHandler = ( ) => {
269+ cleanup ( ) ;
270+ reject ( new Error ( 'useAgent.waitUntilAvailable - signal aborted' ) ) ;
271+ } ;
272+
273+ const cleanup = ( ) => {
274+ emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
275+ signal ?. removeEventListener ( 'abort' , abortHandler ) ;
276+ } ;
277+
278+ emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
279+ signal ?. addEventListener ( 'abort' , abortHandler ) ;
280+ } ) ;
281+ } ,
282+ [ emitter ] ,
283+ ) ;
284+
285+ return waitUntilAvailable ;
286+ }
287+
244288/**
245289 * useAgent encapculates all agent state, normalizing some quirks around how LiveKit Agents work.
246290 * @public
@@ -536,38 +580,7 @@ export function useAgent(session?: SessionStub): UseAgentReturn {
536580 isBufferingSpeech ,
537581 ] ) ;
538582
539- const waitUntilAvailable = React . useCallback (
540- async ( signal ?: AbortSignal ) => {
541- const { isAvailable } = generateDerivedStateValues ( state ) ;
542- if ( isAvailable ) {
543- return ;
544- }
545-
546- return new Promise < void > ( ( resolve , reject ) => {
547- const stateChangedHandler = ( state : AgentState ) => {
548- const { isAvailable } = generateDerivedStateValues ( state ) ;
549- if ( ! isAvailable ) {
550- return ;
551- }
552- cleanup ( ) ;
553- resolve ( ) ;
554- } ;
555- const abortHandler = ( ) => {
556- cleanup ( ) ;
557- reject ( new Error ( 'useAgent.waitUntilAvailable - signal aborted' ) ) ;
558- } ;
559-
560- const cleanup = ( ) => {
561- emitter . off ( AgentEvent . StateChanged , stateChangedHandler ) ;
562- signal ?. removeEventListener ( 'abort' , abortHandler ) ;
563- } ;
564-
565- emitter . on ( AgentEvent . StateChanged , stateChangedHandler ) ;
566- signal ?. addEventListener ( 'abort' , abortHandler ) ;
567- } ) ;
568- } ,
569- [ state , emitter ] ,
570- ) ;
583+ const waitUntilAvailable = useAgentWaitUntilAvailable ( emitter , state ) ;
571584
572585 const waitUntilCamera = React . useCallback (
573586 ( signal ?: AbortSignal ) => {
0 commit comments