-
Notifications
You must be signed in to change notification settings - Fork 2.6k
improve EndCallTool #4563
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
base: main
Are you sure you want to change the base?
improve EndCallTool #4563
Conversation
📝 WalkthroughWalkthroughAdds a new EndCallTool class implementing end-call lifecycle with configurable on_end behavior and optional room deletion; updates the voice agent example to use on_enter, EndCallTool(on_end=...), switches TTS to "cartesia/sonic-3", and changes session.start to await session.start(agent=..., room=...). Changes
Sequence Diagram(s)sequenceDiagram
participant Agent
participant EndCallTool
participant Session as AgentSession
participant JobCtx as JobContext
participant RoomMgr as RoomManager
Agent->>EndCallTool: call end_call tool (_end_call)
EndCallTool->>Session: register session-close listener
EndCallTool->>Agent: execute on_end (string reply or await callable with RunContext)
Agent-->>EndCallTool: on_end completes
EndCallTool->>Session: request shutdown
Session->>JobCtx: emit CloseEvent(reason)
JobCtx->>EndCallTool: invoke _on_session_close(ev)
EndCallTool->>RoomMgr: if delete_room true, schedule delete-on-shutdown
JobCtx->>Session: finalize shutdown/cleanup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used📓 Path-based instructions (1)**/*.py📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧬 Code graph analysis (2)examples/voice_agents/session_close_callback.py (2)
livekit-agents/livekit/agents/beta/tools/end_call.py (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🔇 Additional comments (6)
✏️ Tip: You can disable this entire section by setting Comment |
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: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/voice_agents/session_close_callback.py (1)
19-19: DuplicateAgentServerinstantiation.
server = AgentServer()appears twice (lines 19 and 39). The second instantiation on line 39 overwrites the first, making line 19 dead code.🐛 Proposed fix
Remove one of the duplicate declarations:
server = AgentServer() class MyAgent(Agent): ... - -server = AgentServer() - `@server.rtc_session`() async def entrypoint(ctx: JobContext):Also applies to: 39-39
🧹 Nitpick comments (1)
examples/voice_agents/session_close_callback.py (1)
35-36: Missingawaitforgenerate_reply.The
on_entermethod callsself.session.generate_reply()withoutawait. Looking at thegenerate_replysignature inagent_session.py, it returns aSpeechHandlesynchronously, so this is technically valid. However, for consistency and to potentially handle any returned handle, consider being explicit about the intent.If the intent is fire-and-forget, the current code works. If you want to ensure the greeting completes before proceeding, consider:
async def on_enter(self) -> None: - self.session.generate_reply(instructions="say hello to the user") + handle = self.session.generate_reply(instructions="say hello to the user") + await handle.wait_for_playout()
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
examples/voice_agents/session_close_callback.pylivekit-agents/livekit/agents/beta/tools/end_call.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/beta/tools/end_call.pyexamples/voice_agents/session_close_callback.py
🧬 Code graph analysis (2)
livekit-agents/livekit/agents/beta/tools/end_call.py (3)
livekit-agents/livekit/agents/job.py (3)
get_job_context(56-63)delete_room(423-447)_delete_room(431-442)livekit-agents/livekit/agents/voice/events.py (2)
CloseEvent(221-225)RunContext(32-81)examples/voice_agents/session_close_callback.py (1)
on_end_call(24-28)
examples/voice_agents/session_close_callback.py (3)
livekit-agents/livekit/agents/voice/agent_session.py (3)
AgentSession(135-1324)generate_reply(904-957)tools(429-430)livekit-agents/livekit/agents/voice/events.py (2)
RunContext(32-81)session(48-49)livekit-agents/livekit/agents/beta/tools/end_call.py (2)
tools(82-83)EndCallTool(30-83)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: livekit-plugins-cartesia
- GitHub Check: livekit-plugins-inworld
- GitHub Check: type-check (3.13)
- GitHub Check: livekit-plugins-deepgram
- GitHub Check: livekit-plugins-groq
- GitHub Check: livekit-plugins-openai
- GitHub Check: type-check (3.9)
- GitHub Check: unit-tests
🔇 Additional comments (9)
livekit-agents/livekit/agents/beta/tools/end_call.py (7)
1-7: LGTM!The imports are well-organized and include all necessary types for the implementation:
AwaitableandCallablefor type hints,CloseEventandRunContextfrom the voice events module.
9-23: LGTM!The
END_CALL_INSTRUCTIONSconstant provides clear, well-structured guidance for the LLM on when to invoke the end call tool, with appropriate do/don't scenarios.
26-27: LGTM!The default callback provides sensible behavior by generating a goodbye message with
tool_choice="none"to prevent recursive tool calls.
31-55: LGTM!The constructor is well-designed with sensible defaults. The
function_toolwrapper correctly combines the base instructions with any extra instructions provided.
67-79: LGTM!The
_on_session_closehandler correctly:
- Retrieves the job context
- Conditionally registers a shutdown callback for room deletion
- Shuts down the job context with the close reason
The separation of concerns between session close and job shutdown is well-designed.
81-83: LGTM!The
toolsproperty correctly returns the configured end call tool.
57-65: Use the correct API:ctx.wait_for_playout()instead ofctx.speech_handle.wait_for_playout().The proposed fix has a critical API error. Calling
ctx.speech_handle.wait_for_playout()from within a function tool raisesRuntimeErrorwith the message: "cannot callSpeechHandle.wait_for_playout()from inside the function tool ... that owns this SpeechHandle." TheSpeechHandleclass explicitly directs to useRunContext.wait_for_playout()instead for this use case.Additionally,
ctx.session.shutdown()with its defaultdrain=Trueparameter already awaits the completion of the current speech before closing the session, so the goodbye message should not be interrupted. If you still want to add an explicit wait for clarity, useawait ctx.wait_for_playout().Likely an incorrect or invalid review comment.
examples/voice_agents/session_close_callback.py (2)
1-10: LGTM!Imports are well-organized and include the new
RunContexttype needed for theon_end_callcallback.
42-80: LGTM!The session setup and
on_closehandler are well-implemented. The handler correctly iterates through all chat history item types and provides informative output.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
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: 1
🤖 Fix all issues with AI agents
In `@examples/voice_agents/session_close_callback.py`:
- Around line 33-34: The on_enter async method calls
self.session.generate_reply(...) which returns an awaitable SpeechHandle but is
not awaited; update on_enter to await the result (i.e., await
self.session.generate_reply(...)) so the greeting completes before the handler
continues, ensuring the speech is enqueued and executed as intended.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
examples/voice_agents/session_close_callback.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:
examples/voice_agents/session_close_callback.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.9)
- GitHub Check: livekit-plugins-cartesia
- GitHub Check: livekit-plugins-inworld
- GitHub Check: livekit-plugins-elevenlabs
- GitHub Check: livekit-plugins-openai
- GitHub Check: livekit-plugins-deepgram
- GitHub Check: unit-tests
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
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: 1
🤖 Fix all issues with AI agents
In `@examples/voice_agents/session_close_callback.py`:
- Line 5: Remove the unused RunContext import from the import list in
session_close_callback.py: edit the line importing from livekit.agents (which
currently includes Agent, AgentServer, AgentSession, CloseEvent, JobContext,
RunContext, cli) and delete RunContext so the import list only includes used
symbols (Agent, AgentServer, AgentSession, CloseEvent, JobContext, cli); this
will resolve the Ruff F401 unused-import failure.
♻️ Duplicate comments (1)
examples/voice_agents/session_close_callback.py (1)
27-28: Awaitgenerate_replyso the greeting actually runs.
Line 28 returns an awaitable; withoutawait, the greeting may never execute.✅ Proposed fix
- self.session.generate_reply(instructions="say hello to the user") + await self.session.generate_reply(instructions="say hello to the user")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
examples/voice_agents/session_close_callback.pylivekit-agents/livekit/agents/beta/tools/end_call.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:
examples/voice_agents/session_close_callback.pylivekit-agents/livekit/agents/beta/tools/end_call.py
🧬 Code graph analysis (1)
examples/voice_agents/session_close_callback.py (4)
livekit-agents/livekit/agents/voice/agent.py (5)
Agent(34-642)tools(107-113)session(635-642)instructions(99-104)tts(534-544)livekit-agents/livekit/agents/voice/agent_session.py (7)
AgentSession(135-1324)tools(429-430)generate_reply(904-957)tts(1264-1265)start(442-453)start(456-467)start(469-715)livekit-agents/livekit/agents/voice/events.py (3)
CloseEvent(221-225)RunContext(32-81)session(48-49)livekit-agents/livekit/agents/beta/tools/end_call.py (2)
tools(84-85)EndCallTool(26-85)
🪛 GitHub Actions: CI
examples/voice_agents/session_close_callback.py
[error] 5-5: F401 'livekit.agents.RunContext' imported but unused
🪛 GitHub Check: ruff
examples/voice_agents/session_close_callback.py
[failure] 5-5: Ruff (F401)
examples/voice_agents/session_close_callback.py:5:86: F401 livekit.agents.RunContext imported but unused
🔇 Additional comments (6)
livekit-agents/livekit/agents/beta/tools/end_call.py (4)
27-53: Clean EndCallTool wiring and config flow.
The constructor cleanly captures configuration and builds the tool description.
55-67: End-call execution flow looks solid.
The try/finally ensures shutdown even if end instructions fail.
69-81: Session-close handling is clear and safe.
Room deletion is correctly gated and shutdown reason is propagated.
83-85: Tools exposure is straightforward.
Returning a single configured tool here is appropriate.examples/voice_agents/session_close_callback.py (2)
21-25: EndCallTool integration looks good.
Usingend_instructionshere aligns with the new API.
36-43: Verify ElevenLabs TTS configuration for this example.
Line 39 switches totts="elevenlabs"—please confirm the provider/credentials are available in your dev environment so the example doesn’t fail at runtime.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
Co-authored-by: David Zhao <dz@livekit.io>
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: 1
🤖 Fix all issues with AI agents
In `@livekit-agents/livekit/agents/beta/tools/end_call.py`:
- Around line 30-55: The initializer uses undefined names: change the parameter
extra_description to extra_instructions (or update all uses to match the
declared name) so self._extra_instructions is set from the actual arg, and
replace or define the missing END_CALL_INSTRUCTIONS constant—either
import/rename to the existing module-level constant or add a new
END_CALL_INSTRUCTIONS string constant—and use that in the function_tool
description; update the docstring param name to match the final parameter name
and ensure self._end_call_tool uses the corrected identifiers (references:
__init__, self._extra_instructions, self._end_call_tool, END_CALL_INSTRUCTIONS).
♻️ Duplicate comments (1)
examples/voice_agents/session_close_callback.py (1)
27-28: Await the greeting generation to ensure it actually runs.
generate_replyis awaitable; withoutawait, the greeting may not complete before the handler continues. (Duplicate of earlier feedback.)✅ Proposed fix
async def on_enter(self) -> None: - self.session.generate_reply(instructions="say hello to the user") + await self.session.generate_reply(instructions="say hello to the user")
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
examples/voice_agents/session_close_callback.pylivekit-agents/livekit/agents/beta/tools/end_call.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:
examples/voice_agents/session_close_callback.pylivekit-agents/livekit/agents/beta/tools/end_call.py
🧬 Code graph analysis (2)
examples/voice_agents/session_close_callback.py (4)
livekit-agents/livekit/agents/voice/agent.py (5)
Agent(34-642)tools(107-113)on_enter(206-208)session(635-642)instructions(99-104)livekit-agents/livekit/agents/voice/agent_session.py (2)
tools(429-430)generate_reply(904-957)livekit-agents/livekit/agents/voice/events.py (2)
CloseEvent(221-225)session(48-49)livekit-agents/livekit/agents/beta/tools/end_call.py (2)
tools(86-87)EndCallTool(26-87)
livekit-agents/livekit/agents/beta/tools/end_call.py (3)
livekit-agents/livekit/agents/job.py (4)
get_job_context(56-63)delete_room(423-447)_delete_room(431-442)add_shutdown_callback(358-375)livekit-agents/livekit/agents/llm/tool_context.py (2)
Toolset(41-46)info(142-143)livekit-agents/livekit/agents/voice/events.py (2)
CloseEvent(221-225)RunContext(32-81)
🪛 GitHub Check: ruff
livekit-agents/livekit/agents/beta/tools/end_call.py
[failure] 54-54: Ruff (F821)
livekit-agents/livekit/agents/beta/tools/end_call.py:54:53: F821 Undefined name extra_instructions
[failure] 54-54: Ruff (F821)
livekit-agents/livekit/agents/beta/tools/end_call.py:54:28: F821 Undefined name END_CALL_INSTRUCTIONS
[failure] 48-48: Ruff (F821)
livekit-agents/livekit/agents/beta/tools/end_call.py:48:36: F821 Undefined name extra_instructions
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: unit-tests
- GitHub Check: livekit-plugins-groq
- GitHub Check: livekit-plugins-deepgram
- GitHub Check: livekit-plugins-openai
- GitHub Check: livekit-plugins-inworld
- GitHub Check: livekit-plugins-cartesia
- GitHub Check: type-check (3.13)
- GitHub Check: type-check (3.9)
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
extra_descriptionandon_endSummary by CodeRabbit
New Features
Updates
✏️ Tip: You can customize this high-level summary in your review settings.