white-telephone-81843
02/18/2026, 9:42 AMtall-airline-16756
02/18/2026, 9:42 AMtall-airline-16756
02/18/2026, 9:42 AMkind field.
◦ PARTICIPANT_KIND_SIP → participant is connected via telephony (SIP).
◦ PARTICIPANT_KIND_STANDARD → participant is a regular WebRTC participant (console/local testing will appear as standard).
Example (Python)
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Participant is connected via telephony (SIP)")
else:
print("Participant is not using telephony (e.g., console or standard WebRTC client)")
Other useful indicators
• SIP participants often include SIP-specific attributes when available, such as sip.callStatus, sip.phoneNumber, or sip.trunkID. Checking for those fields can provide additional confirmation.
• Console/local test participants are still standard WebRTC participants unless explicitly bridged to SIP, so they will normally show as PARTICIPANT_KIND_STANDARD.
If you’d like, tell me:
• which SDK/language you’re using (JS, Python, Go, etc.) and I’ll give a code snippet for that environment, or
• an example participant object you’re seeing and I’ll point out the fields to inspect. Sources: SIP Lifecycle Management Agent | LiveKit Documentation | Agents telephony integration | LiveKit Documentation | Voice AI quickstart | LiveKit Documentationtall-airline-16756
02/18/2026, 9:44 AM"rtc" is not defined. I can help with both.
First, quick recap of how to detect telephony vs console:
• Check the participant’s kind field:
◦ PARTICIPANT_KIND_SIP → telephony (SIP).
◦ PARTICIPANT_KIND_STANDARD → regular WebRTC (console/local tests appear as standard).
• You can also look for SIP-specific fields such as sip.callStatus, sip.phoneNumber, or sip.trunkID for extra confirmation.
Now about your Pylance error `"rtc" is not defined`:
• That error means your code references rtc but you haven’t imported or defined it in your Python file.
• To fix this I need to know which LiveKit Python package or client you are using (official LiveKit Python SDK, a generated protobuf module, or a local module named rtc).
Can you tell me:
1. Which SDK/library and version you’re using for Python (package name from pip or repository)?
2. The minimal code around the line producing the error (lines ~70–90) so I can see how participant and rtc are referenced?
3. Whether you expected rtc to be an import (e.g., import rtc or from livekit import rtc) or a variable created earlier?
If you’d like, here’s a likely fix patterns you can try while you share the details:
• If the SDK exposes rtc under `livekit`:
from livekit import rtc
# then use rtc.ParticipantKind...
• If the SDK exposes ParticipantKind directly:
from livekit.rtc import ParticipantKind
if participant.kind == ParticipantKind.PARTICIPANT_KIND_SIP:
...
• If you’re using generated protobufs, import the generated module that defines ParticipantKind (replace generated_module with the actual module name):
from generated_module import rtc as rtc_pb
if participant.kind == rtc_pb.ParticipantKind.PARTICIPANT_KIND_SIP:
...
Share the SDK/package name and the snippet around the error and I’ll give the exact import and corrected snippet to resolve the Pylance warning.tall-airline-16756
02/18/2026, 9:45 AM"participant" is not defined, which means the variable you’re checking against (participant.kind) isn’t in scope where you’re using it.
A few quick questions so I can give an exact fix:
• Which SDK/language are you using (JavaScript/TypeScript, Python, Go, etc.)?
• Where in your code are you trying to check the participant’s kind? (for example: inside an event handler like participantJoined / on("participantConnected"), inside a loop over room.participants, or elsewhere)
• If possible, paste the surrounding 10–20 lines of code where the error occurs (redact any secrets).
General guidance while you gather that:
1. Ensure you have a valid participant object in scope before checking participant.kind.
◦ Common patterns:
▪︎ In JS/TS event handlers: room.on('participantConnected', participant => { /* use participant here */ })
▪︎ When iterating participants: for (const participant of room.participants.values()) { /* use participant */ }
▪︎ When accessing the local participant: use the SDK’s room.localParticipant (name may vary by SDK)
1. Add a defensive check to avoid runtime errors while you debug:
if participant is None:
# handle missing participant (log, return, fetch participant)
elif participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
# SIP handling
else:
# standard/WebRTC handling
(Adjust syntax for your language — I’ll provide a language-specific snippet once you tell me which SDK you’re using.)
1. If your linter still flags the variable:
◦ Confirm the variable name is spelled consistently.
◦ Ensure the variable is declared/received as a function parameter or defined in the same scope.
◦ In TypeScript, ensure types are imported and participant is typed (e.g., participant: Participant) or use a narrow any while debugging.
If you share the SDK/language and the code block where the error appears, I’ll give a tailored code example that shows how to obtain the participant object and check participant.kind (including handling SIP-specific fields like sip.phoneNumber if present).white-telephone-81843
02/18/2026, 9:47 AMtall-airline-16756
02/18/2026, 9:47 AMparticipant variable in scope at the line where you’re using it. I can give an exact fix, but first I need a couple quick details:
1. Which SDK / language are you using? (JavaScript/TypeScript, Python, Go, etc.)
2. Where in your code are you running this check? For example:
◦ Inside an event handler like participantConnected / on("participantConnected")
◦ While iterating room.participants
◦ In a separate function where you expect to receive a participant object
While you paste that code, here are the typical ways to get a participant object so the check works. Pick the pattern that matches your setup:
• Event handler (JS/TS example)
room.on('participantConnected', (participant) => {
if (participant.kind === rtc.ParticipantKind.PARTICIPANT_KIND_SIP) {
// SIP participant
} else {
// standard/WebRTC
}
});
• Iterating current participants (JS/TS)
for (const participant of room.participants.values()) {
if (participant.kind === rtc.ParticipantKind.PARTICIPANT_KIND_SIP) {
// handle SIP
}
}
• Accessing the local participant (name may vary by SDK)
const participant = room.localParticipant;
if (participant && participant.kind === rtc.ParticipantKind.PARTICIPANT_KIND_SIP) {
// SIP
}
• Defensive check (Python-style pseudocode)
if participant is None:
# handle missing participant
elif participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
# SIP
else:
# standard
If you share the SDK and the 10–20 lines of code around where the error appears (redact secrets), I’ll point out exactly where you need to obtain or pass the participant variable and give a ready-to-drop code snippet.white-telephone-81843
02/18/2026, 9:47 AMtall-airline-16756
02/18/2026, 9:47 AM# Example assumes you have an SDK Room object named `room`
# and an rtc module with ParticipantKind enum available as rtc.ParticipantKind
def on_participant_connected(participant):
# participant is provided by the event callback -> in scope here
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Participant connected via telephony (SIP)")
else:
print("Participant is a standard/WebRTC participant (console/local)")
# Register the handler with your room object (API name may vary by SDK)
room.on("participantConnected", on_participant_connected)
2) Iterating current participants in the room
# room.participants is commonly a dict or map of participantId -> Participant
for participant_id, participant in room.participants.items():
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print(f"{participant_id} is connected via SIP")
else:
print(f"{participant_id} is a standard/WebRTC participant")
3) Checking the local participant
# If you need to check the local participant
participant = room.local_participant # name may vary: localParticipant/local_participant
if participant is None:
print("No local participant available yet")
elif participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Local participant is SIP")
else:
print("Local participant is standard/WebRTC")
Defensive pattern to avoid the "participant is not defined" error
• Ensure the variable participant is either:
◦ passed into your function (event callback), or
◦ obtained from room.participants or room.local_participant before checking participant.kind.
• Add a None-check before accessing `.kind`:
if participant is None:
# handle missing participant
elif participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
# handle SIP
else:
# handle standard
Optional extra: check SIP-specific fields
• SIP participants often include SIP fields like sip.callStatus, sip.phoneNumber, or sip.trunkID when available. You can check those attributes for additional confirmation if your participant objects expose them.
If you share which LiveKit Python SDK module names you have imported (or paste the 10–20 lines around where you tried the check), I’ll tailor the snippet to your exact API names and show how to register the handler or access room correctly.white-telephone-81843
02/18/2026, 9:48 AMtall-airline-16756
02/18/2026, 9:49 AMparticipant is in scope. Below are two Python patterns you can use depending on how your SDK/event system names the event: one where the handler receives the participant directly, and one where you receive an event object that contains the participant.
1) Handler that receives the participant directly
# Example: room.on("participantConnected", handler)
def on_enter(participant):
# participant is provided by the event -> safe to use here
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Participant entered via telephony (SIP)")
else:
print("Participant entered as standard/WebRTC (console/local)")
# Register the handler (event name may vary by SDK)
room.on("participantConnected", on_enter)
2) Handler that receives an event object containing the participant
def on_enter_event(event):
# event may contain participant as event.participant or event.data['participant']
participant = getattr(event, "participant", None) or event.data.get("participant")
if participant is None:
print("No participant in event")
return
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Participant entered via telephony (SIP)")
else:
print("Participant entered as standard/WebRTC (console/local)")
Defensive checks (recommended)
• Always confirm participant is not None before accessing .kind.
• If your linter/type checker still flags the variable, ensure the callback signature matches the SDK’s event signature (parameter name and order).
Extra confirmation (optional)
• For added certainty, check SIP-specific fields when present (for example participant.sip.callStatus, participant.sip.phoneNumber, or participant.sip.trunkID) — these fields often exist for SIP participants.
If you share the exact event name your SDK uses for "on enter" and a short snippet of how you registered the handler, I’ll tailor the example to match your API (and fix any scoping issues that cause the "participant is not defined" error).white-telephone-81843
02/18/2026, 9:50 AMtall-airline-16756
02/18/2026, 9:51 AM# Example async on_enter handler
# Adjust register syntax to match your SDK if different
async def on_enter(self, participant) -> None:
# Ensure participant was passed into the handler
if participant is None:
print("No participant provided to on_enter")
return
# Check participant kind for SIP vs standard/WebRTC
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
print("Participant entered via telephony (SIP)")
# Optional: check SIP-specific fields if available
# e.g., print(participant.sip.phoneNumber)
else:
print("Participant entered as standard/WebRTC (console/local)")
How to register it (example patterns — use the one that matches your SDK)
• If the SDK expects a bound method:
# assuming this is a method on a class instance 'handler_instance'
room.on("participantConnected", handler_instance.on_enter)
• If the SDK expects a simple callback function:
room.on("participantConnected", on_enter)
Notes and tips
• The key reason you saw "participant is not defined" is using participant outside the function where it’s not in scope. With the handler signature above, participant is a parameter and is available inside the function.
• Keep the None-check to avoid attribute errors while participants are still initializing.
• If your linter still flags things, confirm the event actually calls the handler with the participant as the first argument (some SDKs pass an event object instead). If the SDK passes an event object, use:
async def on_enter(self, event) -> None:
participant = getattr(event, "participant", None) or event.data.get("participant")
...
If you share how you register the handler with your room (the exact code line), I’ll confirm the correct registration form for your SDK and adapt the example if needed.tall-airline-16756
02/18/2026, 9:52 AMon_enter(self, participant) causes the TypeError.
What to change
• Define on_enter with only self (no participant parameter).
• Inside on_enter, get the participant from self.session.room_io.linked_participant.
• Then check participant.kind to detect SIP vs standard.
Ready-to-use example
from livekit import rtc
from livekit.agents import Agent
class RegNumAgent(Agent):
def __init__(self) -> None:
super().__init__(instructions="You are a helpful agent.")
async def on_enter(self) -> None:
# Obtain the participant the agent is handling
participant = self.session.room_io.linked_participant
if participant is None:
# defensive: participant may not be set yet
await self.session.generate_reply(instructions="No participant linked yet.")
return
# Check SIP vs standard/WebRTC
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
await self.session.generate_reply(
instructions="Hello SIP caller, welcome to the telephony system."
)
else:
await self.session.generate_reply(
instructions="Hello WebRTC user, welcome to the application."
)
Why this fixes the error
• The agent framework calls on_enter() with no participant argument. Making on_enter(self) matches the framework’s call.
• self.session.room_io.linked_participant is where the framework exposes the participant associated with the session, so you can access the participant inside the handler.
If you want, I can:
• Show how to handle cases where linked_participant might be populated slightly later (retry loop or wait/timeout).
• Adapt the example to include logging or inspect SIP-specific fields like participant.sip.phoneNumber if available.
Would you like the retry/wait pattern example or logging added to this handler?
Sources: Agents and handoffs | LiveKit Documentation | Agent session | LiveKit Documentation | SIP Lifecycle Management Agent | LiveKit Documentation