Consent and Escalations
Operational workflows for real deployments
Production deployments must respect compliance requirements and hand off gracefully when the caller needs a human. We will add:
- A task that collects recording consent
- A manager agent and a function tool that escalates the call
Collecting recording consent
Consent workflows capture a yes/no answer before the main conversation begins.
Imports
Add at the top of agent.py:
from livekit.agents import AgentTask
Reuse function_tool from the previous lesson. No new imports required!
Task implementation
Define the task class below your Assistant declaration:
from livekit.agents import AgentTask, function_tool
class CollectConsent(AgentTask[bool]):
def __init__(self, chat_ctx=None):
super().__init__(
instructions="""
Ask for recording consent and get a clear yes or no answer.
Be polite and professional.
""",
chat_ctx=chat_ctx,
)
async def on_enter(self) -> None:
await self.session.generate_reply(
instructions="""
Briefly introduce yourself, then ask for permission to record the call for quality assurance and training purposes.
Make it clear that they can decline.
"""
)
@function_tool
async def consent_given(self) -> None:
"""Use this when the user gives consent to record."""
self.complete(True)
@function_tool
async def consent_denied(self) -> None:
"""Use this when the user denies consent to record."""
self.complete(False)
Kick off the task
Extend Assistant.on_enter to run the task before normal assistance:
class Assistant(Agent):
# __init__ ...
async def on_enter(self) -> None:
if await CollectConsent(chat_ctx=self.chat_ctx):
await self.session.generate_reply(instructions="Offer your assistance to the user.")
else:
await self.session.generate_reply(instructions="Inform the user that you are unable to proceed and will end the call.")
job_ctx = get_job_context()
Notice how we start the task with run(self.session), which keeps the conversational context consistent.
Escalating to a manager
Add a dedicated manager agent:
class Manager(Agent):
def __init__(self, chat_ctx=None) -> None:
super().__init__(
instructions=(
"You are a manager for a team of helpful voice AI assistants. "
"Handle escalations professionally."
),
tts="inworld/inworld-tts-1:ashley",
chat_ctx=chat_ctx,
)
Then register a function tool on Assistant that returns the manager:
@function_tool
async def escalate_to_manager(self, context: RunContext):
"""Escalate the call to a manager on user request."""
return Manager(chat_ctx=self.chat_ctx), "Escalating you to my manager now."
The LiveKit agent runtime handles the handoff automatically once the tool returns the new agent instance.
Consent principles
Keep the consent flow crisp, explicit, and region-appropriate:
- State purpose plainly: recording for quality and training; that participation is optional.
- Ask a yes/no question; avoid compound prompts that bury the ask.
- Confirm the outcome back to the caller in your own words.
Latency and UX tips
- Don’t block on long tools during consent; keep it self-contained.
- Use preemptive generation (Lesson 4) so acknowledgments start speaking quickly.
- Keep voices distinct (Lesson 3): one for assistant, one for manager, to make role changes obvious.