Hi! I'd like to know if there is an inbuilt system...
# ask-ai
b
Hi! I'd like to know if there is an inbuilt system in Livekit to make the Agent speak before running a function? Something like please wait while i check the information, or pull up the rates or etc? Because currently all LLMS i've tried will send the function response and the agent will run the function and then start speaking after the function has responded.
t
Thanks for reaching out, Aryan. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — this is a great question. You're asking whether LiveKit has a built‑in way for an agent to speak a short status message (e.g., “Please wait while I check that”) before running a function, because you’ve seen agents wait until after the function returns before speaking. Short answer: Yes — LiveKit supports this behavior, but it’s not a single automatic switch. You implement it by running the long‑running work asynchronously and sending a brief verbal update from the function (or tool) while the work runs. How it works (overview) • The agent can schedule a background task that sends a short spoken reply (for example via
context.session.generate_reply
or
session.say
) after a small delay. • Meanwhile the function continues the long‑running operation. • If the operation finishes quickly, cancel the scheduled status message so you don’t speak unnecessarily. • This decouples speech from waiting on the tool result and gives users a proactive “I’m checking that now…” message. Example pattern (Python) 1. Create a short background task that waits a bit (e.g., 0.5s) and then triggers a spoken update. 2. Start that task, perform the long operation, cancel the task if the operation completes quickly, then return the result.
Copy code
import asyncio
from livekit.agents import function_tool, RunContext

@function_tool()
async def search_knowledge_base(self, context: RunContext, query: str) -> str:
    async def _speak_status_update(delay: float = 0.5):
        await asyncio.sleep(delay)
        await context.session.generate_reply(instructions=f"""
            You are searching the knowledge base for "{query}" but it is taking a little while.
            Update the user on your progress, but be very brief.
        """)

    status_update_task = asyncio.create_task(_speak_status_update(0.5))

    result = await _perform_search(query)  # your long-running call

    status_update_task.cancel()
    return result
Notes and best practices • Use a short delay (0.3–0.7s) so the status message only triggers on noticeably long operations. • Cancel the background task when the result is ready to avoid duplicate or unnecessary speech. • The same concept is supported in Node.js using equivalent async/task utilities. • Optionally combine verbal updates with short background “thinking” audio for a more natural UX. If you’d like, I can: • Provide a Node.js example that uses
Task.from()
or equivalent, or • Help adapt this pattern to a specific function you have (share the function signature or a brief snippet). Sources: External data and RAG | LiveKit Documentation
b
No I'd like to know if there is a method to see the function call itself? So I'd like to be able to store the function call. and the response from the function in a txt, so i can think through it a bit more and see how to get the function to speak while making the customer wait
t
Thanks — I’m glad you want to capture the function call and its response so you can inspect and iterate on the agent’s speech behavior. You can absolutely record both the invocation (name + arguments) and the function output in LiveKit by logging inside your function tool, and you can also write those logs to a .txt file. Below are concrete ways to do that and a few practical tips for using the logs to tune when the agent speaks. How to capture and store function calls and responses (Python) 1. Log inputs and outputs inside the
@function_tool
implementation:
Copy code
import logging
from livekit.agents import function_tool, RunContext

# configure logging to write to a file
logging.basicConfig(filename='function_calls.txt', level=<http://logging.INFO|logging.INFO>, format='%(asctime)s %(message)s')
logger = logging.getLogger(__name__)

@function_tool()
async def search_knowledge_base(self, context: RunContext, query: str) -> str:
    <http://logger.info|logger.info>(f'Function called: search_knowledge_base(query={query!r})')  # capture invocation

    # Optionally send an early spoken update to users (see "Speak while waiting" below)
    # await context.session.generate_reply(instructions="Please wait while I look that up.")
    # or await context.session.say("Please wait while I look that up.")

    result = await _perform_search(query)  # your long-running call

    <http://logger.info|logger.info>(f'Function response: {result!r}')  # capture output
    return result
1. The
logging.basicConfig(filename=...)
line writes entries into
function_calls.txt
. Each invocation will add a timestamped line for the call and a line for the response. Node.js approach (concept) • Use the same idea: log the function name, args, and response to a file (e.g., with
fs.appendFile
) inside your tool implementation. • If using an async task helper (like
Task.from()
), log around the awaited call so you capture both the start and completion. Testing & programmatic inspection • Use test utilities like
mock_tools()
and assertions (if you are unit-testing agents) to assert and inspect that a function was called with certain arguments and check returned values programmatically. This is useful for automated validation before relying on the text logs. Make the agent speak while the function runs • Send a brief spoken message early in the function (or schedule a background verbal update) so the user hears a status update while the tool runs. • Pattern: schedule a short delayed announcement (0.3–0.7s) and cancel it if the function finishes quickly. That prevents unnecessary spoken messages for fast calls. Example: schedule-and-cancel pattern (Python)
Copy code
import asyncio

async def _speak_status_update():
    await asyncio.sleep(0.5)
    await context.session.generate_reply(instructions=f'Looking up "{query}". I will be right back with the result.')

status_task = asyncio.create_task(_speak_status_update())

result = await _perform_search(query)

status_task.cancel()
Tips for using the logs to tune speech behavior • Inspect the timestamps in your log file to measure how long calls actually take; use that to choose your delay threshold for the status message. • Log both start and end times or include durations to identify which functions are frequently slow. • If you log the generated spoken messages as well, you can correlate what users heard with the function timing and output. • For privacy/PII, avoid logging sensitive user data or redact it before writing to disk. If you want, I can: • Provide a full Node.js example that appends calls/results to a .txt file. • Help adapt the Python pattern to a specific function you’re using (share the function signature or a small snippet). • Suggest a format for the log file (e.g., JSON lines) that’s easier to parse for analytics. Which option would be most helpful? Sources: SIP Lifecycle Management Agent | LiveKit Documentation | Testing and evaluation | LiveKit Documentation | Playing Audio | LiveKit Documentation