What is the best way to communicate livekit agent ...
# ask-ai
i
What is the best way to communicate livekit agent status to the frontend? For example, maybe the agent encounters error or something, and I want to tell the frontend that an error happened.
t
Thanks for reaching out, Jan. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
The recommended way to communicate LiveKit agent status, including errors, to the frontend is to use participant attributes. The agent's current state is automatically published as a participant attribute (such as
lk.agent.state
), which your frontend can observe in real time. Built-in states include
initializing
,
listening
,
thinking
,
speaking
,
connecting
, and
disconnected
. For more complex scenarios, such as custom error messages or detailed status updates, you can use LiveKit's state synchronization and RPC features to share custom state or trigger specific actions between your agent and frontend. Additionally, for user-facing feedback (such as when an operation fails or is delayed), you can have the agent provide verbal status updates or display messages in the UI to keep users informed. Start with participant attributes for standard agent states, and use custom state sync or RPC for advanced error handling and communication needs. Sources: AI voice agents | LiveKit Docs | Web and mobile frontends | LiveKit Docs | Handling RAG Delays in Voice Agents | LiveKit Docs | LiveKit Docs
i
How to use custom state sync or RPC?
t
Hey there! Let me walk you through how you can sync up your LiveKit agent and frontend in a super smooth way. Think of this like setting up a seamless conversation between different parts of your app. • State Synchronization: Imagine sharing a live notebook between your agent and frontend where you can jot down real-time updates. It's like keeping each other in the loop about what's happening! • RPC (Remote Procedure Calls): This is basically like having a direct hotline between your agent and frontend. You can: ◦ Agent-to-Frontend: Your agent can give a quick nudge to the frontend, saying "Hey, here's what's up!" ◦ Frontend-to-Agent: The frontend can also reach out and say "Can you do this for me?" Super flexible! Example: Agent-to-Frontend RPC Call
Copy code
return await ctx.room.local_participant.perform_rpc(
    destination_identity=participant.identity,
    method="getUserLocation",
    payload=json.dumps({"highAccuracy": high_accuracy}),
    response_timeout=10.0 if high_accuracy else 5.0,
)
Example: Registering an RPC Method on the Agent
Copy code
@ctx.room.local_participant.register_rpc_method("set_participant")
async def on_set_participant(data: rtc.RpcInvocationData) -> None:
    target_identity = data.payload or data.caller_identity
    # Handle the RPC call
    room_io.set_participant(target_identity)
Pro tip: Mix and match these approaches! Use RPC for quick actions and a shared state structure to keep everything in sync. It's like having a well-choreographed dance between your agent and frontend. Now you've got a super powerful way to keep your app's communication smooth and real-time. How cool is that? Sources: examples/voice_agents/toggle_io.py | rpc/rpc_agent.py | Bringing AI avatars to voice agents | Web and mobile frontends | LiveKit Docs | RPC | LiveKit Docs
i
Ok I am using react as my frontend, how to listen to the RPC event like above? LIke what the react code would look like?
t
Hey there! Want to know how to listen to RPC events in your React frontend using LiveKit? No worries, I've got a super friendly walkthrough that'll make this feel like a breeze. 😊
Copy code
import { useEffect } from 'react';
import { RpcInvocationData } from 'livekit-client';
import { useRoomContext } from '@livekit/components-react';

export default function MyComponent() {
  const room = useRoomContext();

  useEffect(() => {
    if (!room || !room.localParticipant) return;

    // RPC handler function - must be async and return a string
    const handleMyRpcMethod = async (rpcInvocation: RpcInvocationData): Promise<string> => {
      try {
        // Parse the payload (usually JSON)
        const payload = JSON.parse(rpcInvocation.payload);
        console.log("Received RPC data:", payload);

        // Process the data
        // ... your logic here ...

        return "Success: Data processed";
      } catch (error) {
        console.error("Error processing RPC:", error);
        return "Error: " + (error instanceof Error ? error.message : String(error));
      }
    };

    // Register the RPC method
    room.localParticipant.registerRpcMethod("my.rpc.method", handleMyRpcMethod);

    // Cleanup function
    return () => {
      if (room && room.localParticipant) {
        room.localParticipant.unregisterRpcMethod("my.rpc.method");
      }
    };
  }, [room]);

  return <div>My Component</div>;
}
Quick Tips: • RPC handlers are like friendly messengers - they're async functions that take
RpcInvocationData
and return a string. • Use
room.localParticipant.registerRpcMethod(methodName, handler)
to set up your communication channels. • Don't forget to unregister methods in the cleanup to keep things tidy! • The
RpcInvocationData
is your info packet, carrying the
payload
and who sent it via
callerIdentity
. This approach lets your React frontend chat seamlessly with agents and participants in real-time. Cool, right? 🚀 Sources: avatars/tavus/voice-assistant-frontend/components/QuizContainer.tsx | web/providers/GameProvider.tsx | README.md
i
How to integrate the above function, if I already have a "main function" as follows
Copy code
export function DemoRoom({
  serverUrl,
  token,
}: {
  serverUrl: string;
  token: string;
}) {
  const { room, isLoading, error } = useLoadRoom({ serverUrl, token });

  if (isLoading)
    return <RoomLoadingState>Loading your room...</RoomLoadingState>;

  if (error) return <RoomErrorState errorMessage={error.message} />;

  return <RoomConnectedState room={room} />;
}
t
Hey there! Let's walk through how you can add RPC event handling to your
DemoRoom
component. It's actually pretty straightforward – we'll use a
useEffect
hook to register RPC methods on the local participant. Think of it like setting up a friendly communication channel in your room. Sources: complex-agents/role-playing/role_playing_frontend/components/character-port... | src/room/rpc.test.ts | web/providers/GameProvider.tsx
i
Ok, walk me through
t
Hey there! Let me walk you through integrating RPC handling into your
DemoRoom
component - it's easier than you might think! 1. Set up the RPC handler: Inside the
useEffect
hook, create a friendly async function (like
handleMyRpcMethod
) that'll handle incoming RPC calls. This function gets an
RpcInvocationData
object with all the details. Just parse the payload with
JSON.parse
, do your magic with the data, and send back a response. 2. Register the RPC method: Use
room.localParticipant.registerRpcMethod
to give your handler a name (like
"my.rpc.method"
). Now it'll automatically jump into action when that specific RPC call comes in! 3. Handle cleanup: In the cleanup part of the
useEffect
hook, make sure to unregister the RPC method using
room.localParticipant.unregisterRpcMethod
. It's like tidying up after yourself - keeps things running smoothly. 4. Integrate with your component: Drop the
useEffect
hook into your
DemoRoom
. Just make sure it only runs when the
room
is ready and your component is up and running. 5. Test it out: Try triggering an RPC call to your registered method from another participant or the backend. Watch as it processes the call and logs the payload - it's like magic! Here's the code to help you get started: