diff --git a/.changeset/vast-queens-fold.md b/.changeset/vast-queens-fold.md new file mode 100644 index 000000000..26d1a39b5 --- /dev/null +++ b/.changeset/vast-queens-fold.md @@ -0,0 +1,5 @@ +--- +'@livekit/components-react': patch +--- + +Add participant identity, name, and metadata to root useAgent() return value diff --git a/packages/react/src/hooks/useAgent.ts b/packages/react/src/hooks/useAgent.ts index a0be0a567..0812c09bc 100644 --- a/packages/react/src/hooks/useAgent.ts +++ b/packages/react/src/hooks/useAgent.ts @@ -6,6 +6,7 @@ import { RemoteParticipant, RoomEvent, Track, + Participant, } from 'livekit-client'; import type TypedEventEmitter from 'typed-emitter'; import { EventEmitter } from 'events'; @@ -16,6 +17,7 @@ import { useParticipantTracks } from './useParticipantTracks'; import { useRemoteParticipants } from './useRemoteParticipants'; import { UseSessionReturn } from './useSession'; import { useMaybeSessionContext } from '../context'; +import { useParticipantInfo } from './useParticipantInfo'; // FIXME: make this 10 seconds once room dispatch booting info is discoverable const DEFAULT_AGENT_CONNECT_TIMEOUT_MILLISECONDS = 20_000; @@ -63,7 +65,7 @@ export type AgentCallbacks = { type AgentStateCommon = { // FIXME: maybe add some sort of schema to this? - attributes: Record; + attributes: Participant['attributes']; internal: { emitter: TypedEventEmitter; @@ -77,6 +79,11 @@ type AgentStateAvailable = AgentStateCommon & { state: 'listening' | 'thinking' | 'speaking'; failureReasons: null; + /** The client's assigned identity, coming from the JWT token. */ + identity: Participant['identity']; + name: Participant['name']; + metadata: Participant['metadata']; + /** Is the agent connected to the client? */ isConnected: true; @@ -102,6 +109,11 @@ type AgentStatePreConnectBuffering = AgentStateCommon & { state: 'pre-connect-buffering'; failureReasons: null; + /** The client's assigned identity, coming from the JWT token. */ + identity: Participant['identity']; + name: Participant['name']; + metadata: Participant['metadata']; + /** Is the agent connected to the client? */ isConnected: false; @@ -127,6 +139,11 @@ type AgentStateUnAvailable = AgentStateCommon & { state: 'initializing' | 'idle'; failureReasons: null; + /** The client's assigned identity, coming from the JWT token. */ + identity: Participant['identity']; + name: Participant['name']; + metadata: Participant['metadata']; + /** Is the agent connected to the client? */ isConnected: false; @@ -152,6 +169,11 @@ type AgentStateConnecting = AgentStateCommon & { state: 'connecting'; failureReasons: null; + /** The client's assigned identity, coming from the JWT token. */ + identity: undefined; + name: undefined; + metadata: undefined; + /** Is the agent connected to the client? */ isConnected: false; @@ -177,6 +199,11 @@ type AgentStateDisconnected = AgentStateCommon & { state: 'disconnected'; failureReasons: null; + /** The client's assigned identity, coming from the JWT token. */ + identity: undefined; + name: undefined; + metadata: undefined; + /** Is the agent connected to the client? */ isConnected: false; @@ -202,6 +229,11 @@ type AgentStateFailed = AgentStateCommon & { state: 'failed'; failureReasons: Array; + /** The client's assigned identity, coming from the JWT token. */ + identity: undefined; + name: undefined; + metadata: undefined; + /** Is the agent connected to the client? */ isConnected: false; @@ -517,8 +549,8 @@ export function useAgent(session?: SessionStub): UseAgentReturn { // 1. Listen for agent participant attribute changes const [agentParticipantAttributes, setAgentParticipantAttributes] = React.useState< - Record - >({}); + Participant['attributes'] + >(agentParticipant?.attributes ?? {}); React.useEffect(() => { if (!agentParticipant) { return; @@ -710,6 +742,12 @@ export function useAgent(session?: SessionStub): UseAgentReturn { }; }, [isSessionDisconnected, agentConnectTimeoutMilliseconds]); + const { + identity: agentParticipantIdentity, + name: agentParticipantName, + metadata: agentParticipantMetadata, + } = useParticipantInfo({ participant: agentParticipant ?? undefined }); + const agentState: AgentStateCases = React.useMemo(() => { const common: AgentStateCommon = { attributes: agentParticipantAttributes, @@ -725,6 +763,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'disconnected': return { ...common, + identity: undefined, + name: undefined, + metadata: undefined, state, ...generateDerivedStateValues(state), @@ -738,6 +779,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'connecting': return { ...common, + identity: undefined, + name: undefined, + metadata: undefined, state, ...generateDerivedStateValues(state), @@ -752,6 +796,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'idle': return { ...common, + identity: agentParticipantIdentity!, + name: agentParticipantName, + metadata: agentParticipantMetadata, state, ...generateDerivedStateValues(state), @@ -764,6 +811,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'pre-connect-buffering': return { ...common, + identity: agentParticipantIdentity!, + name: agentParticipantName, + metadata: agentParticipantMetadata, state, ...generateDerivedStateValues(state), @@ -778,6 +828,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'speaking': return { ...common, + identity: agentParticipantIdentity!, + name: agentParticipantName, + metadata: agentParticipantMetadata, state, ...generateDerivedStateValues(state), @@ -790,6 +843,9 @@ export function useAgent(session?: SessionStub): UseAgentReturn { case 'failed': return { ...common, + identity: undefined, + name: undefined, + metadata: undefined, state: 'failed', ...generateDerivedStateValues('failed'), @@ -800,7 +856,17 @@ export function useAgent(session?: SessionStub): UseAgentReturn { microphoneTrack: undefined, }; } - }, [agentParticipantAttributes, emitter, agentParticipant, state, videoTrack, audioTrack]); + }, [ + agentParticipantIdentity, + agentParticipantName, + agentParticipantMetadata, + agentParticipantAttributes, + emitter, + agentParticipant, + state, + videoTrack, + audioTrack, + ]); const { waitUntilConnected, waitUntilCouldBeListening, waitUntilFinished } = useAgentWaitUntilDerivedStates(emitter, state);