-
Notifications
You must be signed in to change notification settings - Fork 2.8k
hand text message request from lk server #4553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
📝 WalkthroughWalkthroughSMS/text message handling is refactored from a boolean flag ( Changes
Sequence DiagramsequenceDiagram
participant CLI as CLI/Console
participant Server as AgentServer
participant Worker as Agent Worker
participant Job as Job Context
participant Handler as Text Handler
CLI->>Server: simulate_job(text_request)
Note over Server: Queues job with text_request
Server->>Worker: send StartJobRequest with text_request
Worker->>Worker: _handle_text_request(text_request)
Worker->>Worker: enqueue to _text_request_ch
Worker->>Job: create JobContext with text_message_context
Note over Job: Initializes from text_request
Worker->>Handler: invoke text_handler(job_context)
Handler->>Job: ctx.text_message_context.mark_done()
Note over Job: Signals completion via response channel
Job->>CLI: response collected from queue
CLI->>CLI: serialize session data to file
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@livekit-agents/livekit/agents/voice/agent.py`:
- Around line 134-138: The llm parameter may be an LLMModels literal but only
str values are converted to an LLM instance; update the logic around the llm
parameter handling in agent.py (the block that checks is_given(llm) and assigns
self._llm) so that LLMModels values are passed through
inference.LLM.from_model_string(...) just like str values before setting
self._llm, and remove the use of the type: ignore assignment; use
inference.LLM.from_model_string(llm) for any string-like model identifier (str
or LLMModels) to ensure self._llm always holds an inference.LLM instance.
- Around line 139-142: The tts handling is inconsistent between __init__ and
configure: either mirror the # type: ignore usage or improve type narrowing so
mypy accepts both; preferred fix—remove the # type: ignore in configure and
explicitly narrow/cast the type in both places: in __init__ and configure check
isinstance(tts, str) and convert via inference.TTS.from_model_string(tts), then
assign self._tts = typing.cast(inference.TTS, converted_or_original_tts) (or use
typing.cast on the final value) so mypy knows self._tts is inference.TTS; update
both __init__ and configure where the tts parameter is processed (variable name
tts and attribute self._tts) to use the same explicit cast/narrowing approach.
- Around line 120-123: The type: ignore on the configure() assignment indicates
_turn_detection has no explicit class annotation; add an explicit type
annotation for the attribute (e.g., declare _turn_detection:
NotGivenOr[TurnDetectionMode | None] or _turn_detection:
Optional[TurnDetectionMode] depending on your sentinel type) on the class so
mypy can see assignments from both the constructor and the
is_given(turn_detection) branch; alternatively, if you prefer not to change the
attribute, replace the suppressed assignment in configure() with an explicit
cast to the annotated type (using typing.cast) so mypy no longer requires #
type: ignore.
In `@livekit-agents/livekit/agents/worker.py`:
- Around line 1376-1385: _handle_text_request currently calls
self._text_request_ch.send_nowait(request) which can raise ChanClosed if
aclose() ran while _recv_task is processing; wrap the send in a try/except
catching the ChanClosed (or the specific channel-close exception type used) and
either drop/log the message (use logger.debug/info with agent_name, message_id,
session_id) or check a worker-closing flag before sending to avoid raising;
ensure symbols referenced: _handle_text_request,
self._text_request_ch.send_nowait, aclose(), and _recv_task.
In `@livekit-agents/pyproject.toml`:
- Line 34: Update the broken dependency spec "livekit-protocol>=1.1.2,<2" to a
published release: change the requirement to "livekit-protocol>=1.1.1,<2" (or
another valid published version) so installation succeeds; locate the string
"livekit-protocol>=1.1.2,<2" in the pyproject dependency list and replace it
with the corrected version specifier.
🧹 Nitpick comments (1)
livekit-agents/livekit/agents/worker.py (1)
623-623: Consider adding a buffer size to prevent unbounded queue growth.The
_msg_chanon line 622 specifies a buffer size of 128, but_text_request_chhas no buffer limit. If text requests arrive faster than they can be processed (each spawns a simulated job), the channel could grow unbounded.Suggested fix
- self._text_request_ch = utils.aio.Chan["agent.TextMessageRequest"](loop=self._loop) + self._text_request_ch = utils.aio.Chan["agent.TextMessageRequest"](128, loop=self._loop)
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
examples/voice_agents/sms_agent.pylivekit-agents/livekit/agents/cli/cli.pylivekit-agents/livekit/agents/cli/proto.pylivekit-agents/livekit/agents/ipc/proto.pylivekit-agents/livekit/agents/job.pylivekit-agents/livekit/agents/voice/agent.pylivekit-agents/livekit/agents/worker.pylivekit-agents/pyproject.tomltests/test_ipc.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Format code with ruff
Run ruff linter and auto-fix issues
Run mypy type checker in strict mode
Maintain line length of 100 characters maximum
Ensure Python 3.9+ compatibility
Use Google-style docstrings
Files:
livekit-agents/livekit/agents/job.pylivekit-agents/livekit/agents/voice/agent.pytests/test_ipc.pylivekit-agents/livekit/agents/ipc/proto.pyexamples/voice_agents/sms_agent.pylivekit-agents/livekit/agents/worker.pylivekit-agents/livekit/agents/cli/cli.pylivekit-agents/livekit/agents/cli/proto.py
🧬 Code graph analysis (5)
livekit-agents/livekit/agents/voice/agent.py (2)
livekit-agents/livekit/agents/voice/agent_session.py (4)
turn_detection(389-390)stt(1347-1348)llm(1351-1352)tts(1355-1356)livekit-agents/livekit/agents/utils/misc.py (1)
is_given(25-26)
livekit-agents/livekit/agents/ipc/proto.py (1)
livekit-agents/livekit/agents/ipc/channel.py (4)
write_bool(91-92)write_bytes(62-64)read_bool(95-96)read_bytes(67-69)
examples/voice_agents/sms_agent.py (3)
livekit-agents/livekit/agents/worker.py (3)
text_handler(522-525)text_handler(528-533)text_handler(535-562)livekit-agents/livekit/agents/job.py (2)
TextMessageContext(134-161)text(156-157)livekit-agents/livekit/agents/llm/tool_context.py (1)
info(142-143)
livekit-agents/livekit/agents/worker.py (1)
livekit-agents/livekit/agents/job.py (4)
TextMessageContext(134-161)text_message_context(374-375)mark_done(148-149)agent(363-364)
livekit-agents/livekit/agents/cli/proto.py (3)
livekit-agents/livekit/agents/ipc/channel.py (5)
write_bool(91-92)write_bytes(62-64)read_bytes(67-69)read_string(78-80)read_bool(95-96)livekit-agents/livekit/agents/ipc/proto.py (10)
read(33-38)read(51-52)read(65-66)read(81-83)read(108-128)read(142-143)read(156-157)read(174-177)read(196-201)read(213-214)livekit-agents/livekit/agents/job.py (6)
job(344-346)job(717-718)agent(363-364)RunningJobInfo(92-99)JobAcceptArguments(84-88)worker_id(349-351)
🔇 Additional comments (24)
livekit-agents/livekit/agents/voice/agent.py (1)
124-129: No conversion issue exists.STTModelsvalues are string literals that are caught and converted via theisinstance(stt, str)check at line 125. Thefrom_model_string()method converts them toSTTinstances (line 126), just as intended. The# type: ignoreon line 127 suppresses a mypy type-narrowing limitation with union types, not a missing code path. This pattern is identical to the constructor (line 81), which lacks the suppression comment only because of different type context.Likely an incorrect or invalid review comment.
examples/voice_agents/sms_agent.py (1)
101-103: Rename aligns with the server-driven text flow.
Log wording update is consistent with the new handler name.livekit-agents/livekit/agents/cli/cli.py (7)
22-43: Imports updated for text-request handling.
No issues with the new imports.
294-369: IO lifecycle tracking + release hook look solid.
Centralized state and cleanup should prevent stale console IO.
404-450: Guarded IO access is solid.
The stricter checks/asserts make IO usage safer.
611-688: Explicit IO asserts keep callbacks safe.
Nice to see clearer assumptions in the audio callbacks.
1402-1444: simulate_job_on_start flag cleanly separates console vs SMS.
The toggle keeps behavior explicit and easy to reason about.
1507-1507: Console/SMS worker wiring looks consistent.
Defaults for console and the explicit disable for SMS are clear.Also applies to: 1569-1575
1164-1256: No action needed — response channel closure is guaranteed.
The text handler invocation inworker.pyis wrapped in atry/finallyblock that automatically callsctx.text_message_context.mark_done()(which closesresponse_ch) regardless of handler success or failure. Channel closure is managed by the framework, not dependent on handler behavior.Likely an incorrect or invalid review comment.
tests/test_ipc.py (1)
110-119: Fixture aligned withtext_request.
Matches the updated RunningJobInfo schema.livekit-agents/livekit/agents/job.py (3)
91-100: RunningJobInfo now carriestext_request.
Looks correct and keeps the payload optional.
134-150:mark_done()provides a clean completion signal.
Good to have an explicit close for the response channel.
199-205: TextMessageContext wiring into JobContext looks correct.
The new property keeps the text flow discoverable.Also applies to: 373-375
livekit-agents/livekit/agents/ipc/proto.py (1)
94-128: IPC StartJobRequest serialization stays symmetric.
Optionaltext_requestgating is handled consistently.livekit-agents/livekit/agents/cli/proto.py (1)
48-87: ActiveJobsResponse now carries optionaltext_requestcleanly.
Serialization/deserialization aligns with the new schema.livekit-agents/livekit/agents/worker.py (9)
74-121: LGTM! Well-structured entrypoint wrapper with proper cleanup.The refactored
_EntrypointWrappercorrectly routes between RTC sessions and text message handling. Thefinallyblock ensuresmark_done()andshutdown()are called even if the text handler raises an exception, which is appropriate for resource cleanup.
645-645: LGTM!Correctly passes both the RTC entrypoint and text handler functions to the wrapper.
695-695: LGTM!Consistent initialization pattern with other optional tasks like
_conn_taskand_load_task.
1019-1021: LGTM! Correct shutdown sequence.Closing the channel first allows the
async forloop to exit gracefully, thencancel_and_waitensures complete cleanup.
1195-1196: LGTM!The handler correctly dispatches to
_handle_text_request. Since that method usessend_nowait, it won't block the receive loop.
1238-1238: LGTM!Correctly propagates
text_requestwhen reloading jobs.
1312-1312: LGTM!Correctly sets
text_request=Nonefor RTC jobs accepted through the standard availability flow.
372-372: LGTM!The
_text_handler_fncfield is properly initialized and follows the same pattern as other handler functions.
943-996: Backward-compatible parameter enhancement - no breaking changes.The change from
sms_job: booltotext_request: agent.TextMessageRequest | None = Noneis backward compatible. Thetext_requestparameter is optional and defaults toNone, allowing all existing call sites to work without modification. All callers have been properly updated where applicable.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| if is_given(turn_detection): | ||
| self._turn_detection = turn_detection | ||
| self._turn_detection = turn_detection # type: ignore | ||
| restart_required = True | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, find the agent.py file and check its location
find . -name "agent.py" -path "*/voice/*" | head -20Repository: livekit/agents
Length of output: 104
🏁 Script executed:
#!/bin/bash
# Check the _turn_detection attribute type annotation in the file
rg -n "_turn_detection" livekit-agents/livekit/agents/voice/agent.py -A 2 -B 2Repository: livekit/agents
Length of output: 897
🏁 Script executed:
#!/bin/bash
# Find the is_given function definition and check if it's a TypeGuard
rg -n "def is_given" --type=py | head -20Repository: livekit/agents
Length of output: 156
🏁 Script executed:
#!/bin/bash
# Check the type hints and imports in the agent.py file
head -100 livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 3862
🏁 Script executed:
#!/bin/bash
# Search for the _turn_detection attribute declaration in the Agent class
rg -n "class Agent" livekit-agents/livekit/agents/voice/agent.py -A 200 | grep -E "_turn_detection|^[0-9]+-\s*(def|@|class)" | head -30Repository: livekit/agents
Length of output: 936
🏁 Script executed:
#!/bin/bash
# Look for all occurrences of _turn_detection to understand its type
rg -n "_turn_detection" livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 257
🏁 Script executed:
#!/bin/bash
# Check the imports and type annotations more carefully
sed -n '1,120p' livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 4813
🏁 Script executed:
#!/bin/bash
# Look at the configure method signature and context around line 120-142
sed -n '95,160p' livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 2564
🏁 Script executed:
#!/bin/bash
# Check if there's an explicit type annotation for _turn_detection as a class variable
rg -n "^\s*_turn_detection\s*:" livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 40
🏁 Script executed:
#!/bin/bash
# Check the is_given implementation to understand the TypeGuard
sed -n '20,40p' livekit-agents/livekit/agents/utils/misc.pyRepository: livekit/agents
Length of output: 530
🏁 Script executed:
#!/bin/bash
# Look for any mypy config or similar patterns in the codebase
find . -name "pyproject.toml" -o -name "mypy.ini" -o -name ".mypy.ini" | head -5Repository: livekit/agents
Length of output: 302
🏁 Script executed:
#!/bin/bash
# Check mypy configuration in pyproject.toml
cat livekit-agents/pyproject.toml | grep -A 20 "\[tool.mypy\]"Repository: livekit/agents
Length of output: 40
🏁 Script executed:
#!/bin/bash
# Run mypy on the specific file to see what errors occur
cd livekit-agents && python -m pip install -q mypy typing-extensions 2>/dev/null; python -m mypy livekit/agents/voice/agent.py --strict 2>&1 | grep -A 3 "_turn_detection\|line 121\|line 127\|line 137\|line 142" | head -30Repository: livekit/agents
Length of output: 144
🏁 Script executed:
#!/bin/bash
# Check if NotGiven and NotGivenOr are properly defined
rg -n "class NotGiven|type NotGivenOr" livekit-agents/livekit/agents/types.py -A 3Repository: livekit/agents
Length of output: 149
🏁 Script executed:
#!/bin/bash
# Check the NotGivenOr type definition
rg -n "NotGivenOr\s*=" livekit-agents/livekit/agents/types.py -A 2Repository: livekit/agents
Length of output: 40
🏁 Script executed:
#!/bin/bash
# Look at the full types.py to understand the type system
head -80 livekit-agents/livekit/agents/types.pyRepository: livekit/agents
Length of output: 2030
🏁 Script executed:
#!/bin/bash
# Check what TurnDetectionMode is
rg -n "class TurnDetectionMode|TurnDetectionMode\s*=" livekit-agents/livekit/agents/voice/audio_recognition.py | head -10Repository: livekit/agents
Length of output: 150
Address the type: ignore suppression for turn_detection assignment in the configure method.
The is_given() function is a proper TypeGuard[_T] that should narrow NotGivenOr[TurnDetectionMode | None] to TurnDetectionMode | None. However, the # type: ignore comment on line 121 suggests mypy is not fully trusting this narrowing.
The discrepancy is notable: the constructor (line 70) assigns the same unguarded NotGivenOr parameter type to _turn_detection without requiring suppression, yet the configure method requires it despite the TypeGuard. Since _turn_detection lacks an explicit type annotation, its type is inferred from assignments, which may be creating ambiguity.
Given the coding guideline to "Run mypy type checker in strict mode," type errors should be resolved properly rather than suppressed. Either:
- Add an explicit type annotation to
_turn_detectionin the class to clarify its intended type - Use explicit type assertions instead of relying on the TypeGuard if mypy has limitations
- Verify that the TypeGuard is actually working as expected with mypy
🤖 Prompt for AI Agents
In `@livekit-agents/livekit/agents/voice/agent.py` around lines 120 - 123, The
type: ignore on the configure() assignment indicates _turn_detection has no
explicit class annotation; add an explicit type annotation for the attribute
(e.g., declare _turn_detection: NotGivenOr[TurnDetectionMode | None] or
_turn_detection: Optional[TurnDetectionMode] depending on your sentinel type) on
the class so mypy can see assignments from both the constructor and the
is_given(turn_detection) branch; alternatively, if you prefer not to change the
attribute, replace the suppressed assignment in configure() with an explicit
cast to the annotated type (using typing.cast) so mypy no longer requires #
type: ignore.
| if is_given(llm): | ||
| if isinstance(llm, str): | ||
| llm = inference.LLM.from_model_string(llm) | ||
| self._llm = llm | ||
| self._llm = llm # type: ignore | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Search for LLMModels definition
rg -n 'LLMModels\s*=' livekit-agents/livekit/agents/ --type py -B2 -A2
# Also search for TypeAlias definitions with LLMModels
rg -n 'LLMModels' livekit-agents/livekit/agents/ --type py | head -20Repository: livekit/agents
Length of output: 1641
🏁 Script executed:
#!/bin/bash
# Check the from_model_string method to understand what it does
rg -n 'from_model_string' livekit-agents/livekit/agents/inference/llm.py -B2 -A10
# Also check what the type signature says about accepting LLMModels
rg -n 'def from_model_string' livekit-agents/livekit/agents/inference/llm.py -A15Repository: livekit/agents
Length of output: 876
🏁 Script executed:
#!/bin/bash
# Check the LLM class constructor to see what types it accepts
rg -n 'class LLM' livekit-agents/livekit/agents/inference/llm.py -A30 | head -50
# Check the types of OpenAIModels, GoogleModels, etc. to confirm they're Literal
rg -n 'OpenAIModels|GoogleModels|QwenModels|KimiModels|DeepSeekModels' livekit-agents/livekit/agents/inference/llm.py | head -10Repository: livekit/agents
Length of output: 2203
🏁 Script executed:
#!/bin/bash
# Check what the _llm attribute is typed as in the Agent class
rg -n '_llm' livekit-agents/livekit/agents/voice/agent.py -B2 -A2 | head -30
# Also check the full context around line 134-138
sed -n '130,145p' livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 1710
🏁 Script executed:
#!/bin/bash
# Check the stt parameter handling for comparison
sed -n '125,133p' livekit-agents/livekit/agents/voice/agent.py
# Check the type annotation for _llm attribute
rg -n '_llm.*:' livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 527
Handle LLMModels type conversion consistently with str.
The parameter accepts llm: NotGivenOr[llm.LLM | llm.RealtimeModel | LLMModels | str | None], where LLMModels is a type alias for a union of specific model literal strings (OpenAI, Google, Qwen, Kimi, DeepSeek models). However, only str values are converted to llm.LLM instances (line 136); LLMModels values bypass this conversion and are assigned directly with # type: ignore (line 137).
Since LLMModels represents valid model identifiers and LLM.__init__ accepts both LLMModels | str, the LLMModels case should be converted to llm.LLM using from_model_string() for consistency—just like the str case. The current pattern allows a literal model string to be stored directly in self._llm rather than wrapped as an LLM instance, which is inconsistent with the intent of converting string-based models to proper LLM objects.
🤖 Prompt for AI Agents
In `@livekit-agents/livekit/agents/voice/agent.py` around lines 134 - 138, The llm
parameter may be an LLMModels literal but only str values are converted to an
LLM instance; update the logic around the llm parameter handling in agent.py
(the block that checks is_given(llm) and assigns self._llm) so that LLMModels
values are passed through inference.LLM.from_model_string(...) just like str
values before setting self._llm, and remove the use of the type: ignore
assignment; use inference.LLM.from_model_string(llm) for any string-like model
identifier (str or LLMModels) to ensure self._llm always holds an inference.LLM
instance.
| if is_given(tts): | ||
| if isinstance(tts, str): | ||
| tts = inference.TTS.from_model_string(tts) | ||
| self._tts = tts | ||
| self._tts = tts # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify what TTSModels is and check overall type pattern
# Check the definition of TTSModels
rg -nP --type=py -C5 'TTSModels\s*=' livekit-agents/livekit/agents/
# Check all three Models types together
rg -nP --type=py -C3 'class (STT|LLM|TTS)Models|(STT|LLM|TTS)Models.*(TypeAlias|Protocol)' livekit-agents/livekit/agents/inference/Repository: livekit/agents
Length of output: 884
🏁 Script executed:
#!/bin/bash
# Check STTModels and LLMModels definitions
rg -nP --type=py 'STTModels\s*=' livekit-agents/livekit/agents/
rg -nP --type=py 'LLMModels\s*=' livekit-agents/livekit/agents/
# Also check the agent.py constructor to see the full pattern
cat -n livekit-agents/livekit/agents/voice/agent.py | head -100Repository: livekit/agents
Length of output: 4768
🏁 Script executed:
#!/bin/bash
# Check the actual code at lines 139-142
sed -n '130,160p' livekit-agents/livekit/agents/voice/agent.pyRepository: livekit/agents
Length of output: 1107
🏁 Script executed:
#!/bin/bash
# Find the method containing this code block
sed -n '100,145p' livekit-agents/livekit/agents/voice/agent.py | head -50Repository: livekit/agents
Length of output: 1893
🏁 Script executed:
#!/bin/bash
# Verify the field type for self._tts to understand full assignment context
rg -nP --type=py 'self\._tts\s*[:=]' livekit-agents/livekit/agents/voice/agent.py | head -5Repository: livekit/agents
Length of output: 132
🏁 Script executed:
#!/bin/bash
# Check mypy configuration to understand strict mode requirement
fd -name 'pyproject.toml|mypy.ini|setup.cfg' livekit-agents/ | head -5
rg -l '\[tool\.mypy\]|^\[mypy\]' livekit-agents/ | head -3Repository: livekit/agents
Length of output: 288
🏁 Script executed:
#!/bin/bash
# Check mypy configuration to understand strict mode requirement
fd 'pyproject.toml|mypy.ini|setup.cfg' livekit-agents/ | head -5
cat livekit-agents/pyproject.toml | grep -A 20 '\[tool\.mypy\]'Repository: livekit/agents
Length of output: 87
🏁 Script executed:
#!/bin/bash
# Read pyproject.toml to check mypy settings
cat livekit-agents/pyproject.toml | grep -A 15 'tool.mypy'Repository: livekit/agents
Length of output: 40
🏁 Script executed:
#!/bin/bash
# Check if mypy strict mode is enforced elsewhere or in the file directly
cat livekit-agents/pyproject.toml | head -100Repository: livekit/agents
Length of output: 3657
🏁 Script executed:
#!/bin/bash
# Continue reading pyproject.toml to find mypy settings
tail -100 livekit-agents/pyproject.tomlRepository: livekit/agents
Length of output: 3470
🏁 Script executed:
#!/bin/bash
# Search for mypy configuration files
find livekit-agents -name 'mypy.ini' -o -name '.mypy.ini' 2>/dev/null
# Check if there's mypy config in setup.cfg
grep -l 'mypy' livekit-agents/setup.cfg 2>/dev/null || echo "No setup.cfg mypy config"
# Check ruff config since the guidelines mention ruff
grep -A 10 'tool.ruff' livekit-agents/pyproject.toml | head -20Repository: livekit/agents
Length of output: 82
🏁 Script executed:
#!/bin/bash
# Check what from_model_string expects in the inference.TTS class
rg -nP --type=py 'def from_model_string' livekit-agents/livekit/agents/inference/ -A 5
# Also check the TTS class definition to see what it accepts
rg -nP --type=py 'class TTS' livekit-agents/livekit/agents/inference/tts.py -A 10 | head -30Repository: livekit/agents
Length of output: 1954
🏁 Script executed:
#!/bin/bash
# Check what self._tts is typed as to understand the full picture
rg -nP --type=py 'self\._tts\s*:' livekit-agents/livekit/agents/voice/agent.py
# Also check if there are any type annotations on _tts in the class
rg -nP --type=py '_tts' livekit-agents/livekit/agents/voice/agent.py | grep -E ':\s*(tts\.|TTS|NotGivenOr)' | head -5Repository: livekit/agents
Length of output: 126
🏁 Script executed:
#!/bin/bash
# Get the full class definition to find type annotations
sed -n '41,300p' livekit-agents/livekit/agents/voice/agent.py | grep -E '(class Agent|self\._tts|self\._stt|self\._llm)' | head -20Repository: livekit/agents
Length of output: 274
🏁 Script executed:
#!/bin/bash
# Let's verify if there are type stubs or if the fields have type annotations elsewhere
sed -n '1,100p' livekit-agents/livekit/agents/voice/agent.py | grep -A 50 'class Agent'Repository: livekit/agents
Length of output: 2250
Inconsistency in type narrowing and # type: ignore usage across similar code blocks.
In the configure() method, the tts parameter handling (lines 140-142) adds # type: ignore to suppress a mypy strict mode type narrowing issue. However, the identical logic in __init__ (lines 78-79) does not include # type: ignore.
The issue: TTSModels is Union[CartesiaModels, ElevenlabsModels, RimeModels, InworldModels], where each is a Literal of strings. The code only explicitly checks isinstance(tts, str) and converts it. While TTSModels values are strings at runtime and will be caught by this check, mypy in strict mode cannot narrow Union[TTSModels, str] properly because TTSModels is itself a string union. This leaves remaining union members unresolved after the isinstance check, which is why # type: ignore is needed.
Either:
- Remove the
# type: ignorefrom line 142 and add it to line 83 in__init__for consistency, or - Improve type narrowing by explicitly checking for and handling
TTSModelsseparately, eliminating the need for# type: ignore
🤖 Prompt for AI Agents
In `@livekit-agents/livekit/agents/voice/agent.py` around lines 139 - 142, The tts
handling is inconsistent between __init__ and configure: either mirror the #
type: ignore usage or improve type narrowing so mypy accepts both; preferred
fix—remove the # type: ignore in configure and explicitly narrow/cast the type
in both places: in __init__ and configure check isinstance(tts, str) and convert
via inference.TTS.from_model_string(tts), then assign self._tts =
typing.cast(inference.TTS, converted_or_original_tts) (or use typing.cast on the
final value) so mypy knows self._tts is inference.TTS; update both __init__ and
configure where the tts parameter is processed (variable name tts and attribute
self._tts) to use the same explicit cast/narrowing approach.
| def _handle_text_request(self, request: agent.TextMessageRequest) -> None: | ||
| logger.debug( | ||
| "received text request", | ||
| extra={ | ||
| "agent_name": self._agent_name, | ||
| "message_id": request.message_id, | ||
| "session_id": request.session_id, | ||
| }, | ||
| ) | ||
| self._text_request_ch.send_nowait(request) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle potential ChanClosed exception from send_nowait.
If aclose() is called while _recv_task is still processing messages, send_nowait will raise a ChanClosed exception when the channel is closed. Consider wrapping in a try/except or checking if the worker is closing.
Suggested fix
def _handle_text_request(self, request: agent.TextMessageRequest) -> None:
logger.debug(
"received text request",
extra={
"agent_name": self._agent_name,
"message_id": request.message_id,
"session_id": request.session_id,
},
)
- self._text_request_ch.send_nowait(request)
+ with contextlib.suppress(utils.aio.ChanClosed):
+ self._text_request_ch.send_nowait(request)🤖 Prompt for AI Agents
In `@livekit-agents/livekit/agents/worker.py` around lines 1376 - 1385,
_handle_text_request currently calls self._text_request_ch.send_nowait(request)
which can raise ChanClosed if aclose() ran while _recv_task is processing; wrap
the send in a try/except catching the ChanClosed (or the specific channel-close
exception type used) and either drop/log the message (use logger.debug/info with
agent_name, message_id, session_id) or check a worker-closing flag before
sending to avoid raising; ensure symbols referenced: _handle_text_request,
self._text_request_ch.send_nowait, aclose(), and _recv_task.
| "livekit==1.0.23", | ||
| "livekit-api>=1.0.7,<2", | ||
| "livekit-protocol>=1.1,<2", | ||
| "livekit-protocol>=1.1.2,<2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
livekit-protocol 1.1.2 PyPI release
💡 Result:
There is no livekit-protocol 1.1.2 on PyPI — the latest release listed is 1.1.1 (uploaded Dec 2, 2025). [1]
[1] livekit-protocol · PyPI.
🏁 Script executed:
#!/bin/bash
# Search for TextMessageRequest usage in the codebase
rg "TextMessageRequest" --type py -A 2 -B 2Repository: livekit/agents
Length of output: 3303
Version 1.1.2 does not exist on PyPI — update the requirement to an available release.
The livekit-protocol version 1.1.2 specified on line 34 is not available on PyPI. The latest release is version 1.1.1 (released Dec 2, 2025). Installing this dependency as-is will fail. Update the requirement to livekit-protocol>=1.1.1,<2 unless version 1.1.2 is planned for imminent release and should be held until it's published.
🤖 Prompt for AI Agents
In `@livekit-agents/pyproject.toml` at line 34, Update the broken dependency spec
"livekit-protocol>=1.1.2,<2" to a published release: change the requirement to
"livekit-protocol>=1.1.1,<2" (or another valid published version) so
installation succeeds; locate the string "livekit-protocol>=1.1.2,<2" in the
pyproject dependency list and replace it with the corrected version specifier.
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.