Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 18 additions & 9 deletions livekit-agents/livekit/agents/beta/workflows/address.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class GetAddressTask(AgentTask[GetAddressResult]):
def __init__(
self,
extra_instructions: str = "",
require_confirmation: bool = True,
chat_ctx: NotGivenOr[llm.ChatContext] = NOT_GIVEN,
turn_detection: NotGivenOr[TurnDetectionMode | None] = NOT_GIVEN,
tools: NotGivenOr[list[llm.Tool | llm.Toolset]] = NOT_GIVEN,
Expand Down Expand Up @@ -51,8 +52,12 @@ def __init__(
"Call `update_address` at the first opportunity whenever you form a new hypothesis about the address. "
"(before asking any questions or providing any answers.) \n"
"Don't invent new addresses, stick strictly to what the user said. \n"
"Call `confirm_address` after the user confirmed the address is correct. \n"
"When reading a numerical ordinal suffix (st, nd, rd, th), the number must be verbally expanded into its full, correctly pronounced word form.\n"
+ (
"Call `confirm_address` after the user confirmed the address is correct. \n"
if require_confirmation
else ""
)
+ "When reading a numerical ordinal suffix (st, nd, rd, th), the number must be verbally expanded into its full, correctly pronounced word form.\n"
"Do not read the number and the suffix letters separately.\n"
"Confirm postal codes by reading them out digit-by-digit as a sequence of single numbers. Do not read them as cardinal numbers.\n"
"For example, read 90210 as 'nine zero two one zero.'\n"
Expand All @@ -74,7 +79,7 @@ def __init__(
)

self._current_address = ""

self._require_confirmation = require_confirmation
self._address_update_speech_handle: SpeechHandle | None = None

async def on_enter(self) -> None:
Expand All @@ -83,7 +88,7 @@ async def on_enter(self) -> None:
@function_tool()
async def update_address(
self, street_address: str, unit_number: str, locality: str, country: str, ctx: RunContext
) -> str:
) -> str | None:
"""Update the address provided by the user.

Args:
Expand All @@ -101,11 +106,15 @@ async def update_address(
address = " ".join(address_fields)
self._current_address = address

return (
f"The address has been updated to {address}\n"
f"Repeat the address field by field: {address_fields} if needed\n"
f"Prompt the user for confirmation, do not call `confirm_address` directly"
)
if self._require_confirmation:
return (
f"The address has been updated to {address}\n"
f"Repeat the address field by field: {address_fields} if needed\n"
f"Prompt the user for confirmation, do not call `confirm_address` directly"
)
else:
self.complete(GetAddressResult(address=self._current_address))
return None

@function_tool(flags=ToolFlag.IGNORE_ON_ENTER)
async def confirm_address(self, ctx: RunContext) -> None:
Expand Down
27 changes: 18 additions & 9 deletions livekit-agents/livekit/agents/beta/workflows/email_address.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class GetEmailTask(AgentTask[GetEmailResult]):
def __init__(
self,
extra_instructions: str = "",
require_confirmation: bool = True,
chat_ctx: NotGivenOr[llm.ChatContext] = NOT_GIVEN,
turn_detection: NotGivenOr[TurnDetectionMode | None] = NOT_GIVEN,
tools: NotGivenOr[list[llm.Tool | llm.Toolset]] = NOT_GIVEN,
Expand Down Expand Up @@ -56,8 +57,12 @@ def __init__(
"Call `update_email_address` at the first opportunity whenever you form a new hypothesis about the email. "
"(before asking any questions or providing any answers.) \n"
"Don't invent new email addresses, stick strictly to what the user said. \n"
"Call `confirm_email_address` after the user confirmed the email address is correct. \n"
"If the email is unclear or invalid, or it takes too much back-and-forth, prompt for it in parts: first the part before the '@', then the domain—only if needed. \n"
+ (
"Call `confirm_email_address` after the user confirmed the email address is correct. \n"
if require_confirmation
else ""
)
+ "If the email is unclear or invalid, or it takes too much back-and-forth, prompt for it in parts: first the part before the '@', then the domain—only if needed. \n"
"Ignore unrelated input and avoid going off-topic. Do not generate markdown, greetings, or unnecessary commentary. \n"
"Always explicitly invoke a tool when applicable. Do not simulate tool usage, no real action is taken unless the tool is explicitly called."
+ extra_instructions
Expand All @@ -73,7 +78,7 @@ def __init__(
)

self._current_email = ""

self._require_confirmation = require_confirmation
# speech_handle/turn used to update the email address.
# used to ignore the call to confirm_email_address in case the LLM is hallucinating and not asking for user confirmation
self._email_update_speech_handle: SpeechHandle | None = None
Expand All @@ -82,7 +87,7 @@ async def on_enter(self) -> None:
self.session.generate_reply(instructions="Ask the user to provide an email address.")

@function_tool
async def update_email_address(self, email: str, ctx: RunContext) -> str:
async def update_email_address(self, email: str, ctx: RunContext) -> str | None:
"""Update the email address provided by the user.

Args:
Expand All @@ -96,12 +101,16 @@ async def update_email_address(self, email: str, ctx: RunContext) -> str:

self._current_email = email
separated_email = " ".join(email)
if self._require_confirmation:
return (
f"The email has been updated to {email}\n"
f"Repeat the email character by character: {separated_email} if needed\n"
f"Prompt the user for confirmation, do not call `confirm_email_address` directly"
)

return (
f"The email has been updated to {email}\n"
f"Repeat the email character by character: {separated_email} if needed\n"
f"Prompt the user for confirmation, do not call `confirm_email_address` directly"
)
else:
self.complete(GetEmailResult(email_address=email))
return None

@function_tool(flags=ToolFlag.IGNORE_ON_ENTER)
async def confirm_email_address(self, ctx: RunContext) -> None:
Expand Down