AgentState The agent could be in one of the follow...
# ask-ai
e
AgentState The agent could be in one of the following states: •
initializing
- agent is starting up. this should be brief. •
listening
- agent is waiting for user input •
thinking
- agent is processing user input •
speaking
- agent is speaking How would i listen this events on client side
t
Thanks for reaching out, Aditya. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
You're asking how to listen for agent state changes (initializing, listening, thinking, speaking) on the client side. Two straightforward approaches: 1) Listen to the participant attribute
lk.agent.state
• The agent's current state is synchronized to the participant attribute
lk.agent.state
. • Subscribe to participant attribute updates and read that attribute when it changes. • Example (React with LiveKit SDK):
Copy code
import { useRoom } from '@livekit/components-react';
import { useEffect, useState } from 'react';

function useAgentState() {
  const room = useRoom();
  const [agentState, setAgentState] = useState<string>('');

  useEffect(() => {
    const onUpdated = (participant: any) => {
      const state = participant?.attributes?.['lk.agent.state'];
      if (state) setAgentState(state);
    };

    room.on('participant_attributes_updated', onUpdated);
    return () => { room.off('participant_attributes_updated', onUpdated); };
  }, [room]);

  return agentState;
}
2) Use built-in voice/agent UI hooks/components • LiveKit provides frontend components/hooks (React, SwiftUI, Android, Flutter) that already consume
lk.agent.state
and audio tracks to show visual state (e.g., bars, waveforms). • Use the appropriate component/hook for your platform to get state updates and audio visualization with minimal wiring. If you want, tell me which frontend platform/library you're using (React, plain JS, Flutter, iOS, Android) and I’ll give a tailored code example. Sources: Web and mobile frontends | LiveKit docs | Agent session | LiveKit docs | Events and error handling | LiveKit docs
e
I am using python for building the agent and next js for the client
t
You're using a Python agent and Next.js frontend — below are concise, working patterns: Python shows emitting state changes via AgentSession event; Next.js shows subscribing to participant attribute updates for
lk.agent.state
and a small React hook using LiveKit's JS SDK/components. 1) Python agent — emit agent state changes (example)
Copy code
# assume you're using livekit.agents and have an AgentSession `session`
from livekit.agents import AgentStateChangedEvent

@session.on("agent_state_changed")
def on_agent_state_changed(ev: AgentStateChangedEvent):
    # ev.old_state / ev.new_state contain: "initializing", "listening", "thinking", "speaking"
    print(f"Agent state changed: {ev.old_state} -> {ev.new_state}")

# When you set the agent state in your agent logic, the AgentSession will emit this event
# and LiveKit will keep participant attribute `lk.agent.state` in sync for clients.
2) Next.js (React) — listen for
lk.agent.state
updates • Use LiveKit's JS SDK or
@livekit/components-react
. Listen to participant attribute updates and read
lk.agent.state
. Example hook using LiveKit JS (works in Next.js pages/components):
Copy code
import { useEffect, useState } from "react";
import { Room, RemoteParticipant } from "livekit-client"; // or use @livekit/components-react useRoom()

export function useAgentState(room: Room | null) {
  const [agentState, setAgentState] = useState<string>("");

  useEffect(() => {
    if (!room) return;

    const updateFromParticipant = (participant: RemoteParticipant) => {
      const state = participant.attributes?.["lk.agent.state"];
      if (state) setAgentState(state);
    };

    // handle all current remote participants (in case agent is already present)
    room.participants.forEach((p) => updateFromParticipant(p));

    // listen for attribute updates on any participant
    const onAttributesUpdated = (participant: RemoteParticipant) => updateFromParticipant(participant);
    room.on("participant_attributes_updated", onAttributesUpdated);

    // also update when a participant joins
    const onParticipantConnected = (participant: RemoteParticipant) => updateFromParticipant(participant);
    room.on("participant_connected", onParticipantConnected);

    return () => {
      room.off("participant_attributes_updated", onAttributesUpdated);
      room.off("participant_connected", onParticipantConnected);
    };
  }, [room]);

  return agentState;
}
3) Using LiveKit React Components (simpler) • If you're using
@livekit/components-react
, use
useRoom()
to get the
room
and apply the same hook, or use prebuilt voice assistant components that read
lk.agent.state
and audio tracks to show visualization. If you want, I can: • Provide a Next.js page example showing connecting to the room and rendering state. • Show how to set the agent state programmatically in your Python agent logic (specific code for transitions). Which would you like?
e
Yeah useAgent hook as the state parameter, but how would i display the states in the meeting app. I am using
Copy code
<RoomContext.Provider value={room}>
				<VideoConference />
			</RoomContext.Provider>
t
Responding to showing agent state inside your meeting app using the existing RoomContext + VideoConference setup. Below is a minimal pattern: import or implement the
useAgentState
hook (from earlier), consume it inside
VideoConference
, and render the state UI. Place the UI where it fits in your layout. 1) Hook (if you haven't already)
Copy code
// hooks/useAgentState.ts
import { useEffect, useState } from "react";
import type { Room, RemoteParticipant } from "livekit-client";

export function useAgentState(room: Room | null) {
  const [agentState, setAgentState] = useState<string>("");

  useEffect(() => {
    if (!room) return;

    const updateFromParticipant = (p: RemoteParticipant) => {
      const s = p.attributes?.["lk.agent.state"];
      if (s) setAgentState(s);
    };

    // initial scan
    room.participants.forEach(updateFromParticipant);

    const onAttributesUpdated = (p: RemoteParticipant) => updateFromParticipant(p);
    const onParticipantConnected = (p: RemoteParticipant) => updateFromParticipant(p);

    room.on("participant_attributes_updated", onAttributesUpdated);
    room.on("participant_connected", onParticipantConnected);

    return () => {
      room.off("participant_attributes_updated", onAttributesUpdated);
      room.off("participant_connected", onParticipantConnected);
    };
  }, [room]);

  return agentState;
}
2) Consume in VideoConference
Copy code
// components/VideoConference.tsx
import { useContext } from "react";
import { RoomContext } from "../path/to/RoomContext"; // your provider
import { useAgentState } from "../hooks/useAgentState";

export default function VideoConference() {
  const room = useContext(RoomContext);
  const agentState = useAgentState(room);

  return (
    <div className="video-conference">
      {/* your existing video grid, controls, etc. */}

      <div className="agent-state">
        <strong>Agent:</strong>{" "}
        <span className={`agent-state-pill agent-state-${agentState || "unknown"}`}>
          {agentState || "offline"}
        </span>
      </div>
    </div>
  );
}
3) Simple CSS for clarity
Copy code
.agent-state-pill {
  padding: 6px 10px;
  border-radius: 12px;
  color: white;
  font-weight: 600;
}
.agent-state-initializing { background: gray; }
.agent-state-listening    { background: green; }
.agent-state-thinking     { background: orange; }
.agent-state-speaking     { background: blue; }
.agent-state-unknown      { background: darkslategray; }
Notes: • The hook reads
lk.agent.state
from participant attributes; update will reflect in real time. • If multiple agents may appear, filter participants by role/identity before reading the attribute. • Tell me if you want the example adapted to
@livekit/components-react
hooks or to include an audio-visualizer component.
e
import { RoomContext, VideoConference, useAgent } from "@alert-easter-19258/components-react"; video conference is not a custom component but imported from livekit components
t
You're using the built-in LiveKit components — good. Here's a minimal pattern that uses the provided
useAgent
(or the
useRoom
+ participant attributes) to display agent state alongside the imported
VideoConference
component. 1) Simple component using
useAgent
(preferred if available)
Copy code
// components/AgentStatusOverlay.tsx
import React from "react";
import { useAgent } from "@livekit/components-react";

export default function AgentStatusOverlay() {
  const agent = useAgent(); // returns agent participant or null
  const state = agent?.attributes?.["lk.agent.state"] ?? "offline";

  return (
    <div style={{ position: "absolute", top: 12, right: 12 }}>
      <strong>Agent:</strong>{" "}
      <span className={`agent-state-pill agent-state-${state}`}>
        {state}
      </span>
    </div>
  );
}
2) If
useAgent
isn't available, use
useRoom
to find the agent participant
Copy code
import React from "react";
import { useRoom } from "@livekit/components-react";

export default function AgentStatusOverlay() {
  const room = useRoom();
  // replace the filter below if you identify agent by role, name, or metadata
  const agent = Array.from(room.participants.values()).find(p => p.attributes?.["lk.agent.state"]);
  const state = agent?.attributes?.["lk.agent.state"] ?? "offline";

  return (
    <div style={{ position: "absolute", top: 12, right: 12 }}>
      <strong>Agent:</strong>{" "}
      <span className={`agent-state-pill agent-state-${state}`}>
        {state}
      </span>
    </div>
  );
}
3) Use it together with your provider and imported VideoConference
Copy code
import { RoomContext, VideoConference } from "@livekit/components-react";
import AgentStatusOverlay from "./AgentStatusOverlay";

function Meeting({ room }) {
  return (
    <RoomContext.Provider value={room}>
      <div style={{ position: "relative" }}>
        <VideoConference />
        <AgentStatusOverlay />
      </div>
    </RoomContext.Provider>
  );
}
4) Optional CSS
Copy code
.agent-state-pill { padding: 6px 10px; border-radius: 12px; color: white; font-weight: 600; }
.agent-state-initializing { background: gray; }
.agent-state-listening    { background: green; }
.agent-state-thinking     { background: orange; }
.agent-state-speaking     { background: blue; }
.agent-state-offline      { background: darkslategray; }
Notes: • The code reads
lk.agent.state
from participant attributes; updates are real-time. • If you have multiple agents, filter participants by a specific attribute (e.g., role or identity) instead of the simple presence check. • Tell me if you want the overlay to show an icon, animated visualizer, or to be embedded inside VideoConference controls and I’ll provide that snippet.