How to add multiple functions to ctx.add_shutdown_...
# ask-ai
h
How to add multiple functions to ctx.add_shutdown_callback ?
t
Thanks for reaching out, James. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding to your question about adding multiple functions to
ctx.add_shutdown_callback
. You can register as many shutdown callbacks as you need by calling
ctx.add_shutdown_callback
once per function. Each registered callback will be executed when the session shuts down (they run asynchronously). The framework waits up to 10 seconds by default for callbacks to finish. Example:
Copy code
async def entrypoint(ctx: JobContext):
    async def cleanup_one():
        <http://logger.info|logger.info>("Performing cleanup task one")
        # cleanup logic here

    async def cleanup_two():
        <http://logger.info|logger.info>("Performing cleanup task two")
        # cleanup logic here

    ctx.add_shutdown_callback(cleanup_one)
    ctx.add_shutdown_callback(cleanup_two)
If you expect callbacks might take longer than 10 seconds, or you need ordering guarantees, tell me which behavior you need and I can suggest patterns (for example, a single wrapper callback that awaits multiple tasks in sequence or with a timeout). Sources: Job lifecycle | LiveKit Documentation
h
What do I do if the callbacks take longer than 10 seconds?
t
You're asking what to do when shutdown callbacks registered with
ctx.add_shutdown_callback
take longer than the default 10 seconds. Good question — here are practical options you can use depending on how critical the work is. 1) Increase the shutdown callback timeout • Configure the agent server with a longer
shutdown_process_timeout
. Example:
Copy code
server = AgentServer(
    shutdown_process_timeout=60,  # increase to 60 seconds
)
Use this when you need more time for callbacks to finish cleanly. 2) Keep callbacks short and offload heavy work • Make the shutdown callback perform only quick, essential actions (persist critical state, mark job as finishing). • Offload longer tasks to external systems (enqueue a job, call a background worker API, write a DB flag that a worker will pick up). 3) Fire-and-forget within the callback • If the work is non-critical, start an asynchronous background task without awaiting it:
Copy code
async def shutdown_hook():
    asyncio.create_task(long_running_cleanup())
    save_critical_state()
This returns quickly but note it won't guarantee completion before process exit unless you also increase the timeout. 4) Use a single wrapper callback to control ordering or parallelism • If you need ordered or coordinated cleanup, register one shutdown callback that awaits multiple tasks in sequence or concurrently with a timeout:
Copy code
async def wrapper():
    await asyncio.gather(
        asyncio.wait_for(cleanup_one(), 10),
        asyncio.wait_for(cleanup_two(), 10),
    )

ctx.add_shutdown_callback(wrapper)
This lets you enforce per-task timeouts and control total duration. 5) Consider process-level graceful-termination settings for long conversations • For use cases such as voice or long-running sessions, extend the deployment’s termination grace period (e.g., Kubernetes
terminationGracePeriodSeconds
) so active jobs can finish before shutdown hooks run. The framework also supports draining active jobs for longer periods (drain_timeout) separate from the 10s shutdown callback allowance. If you tell me: • whether the long work is critical to complete before exit, and • your deployment environment (local, Kubernetes, or other), I can recommend a concrete pattern and show the exact code or server option changes to implement it. Sources: Job lifecycle | LiveKit Documentation | Self-hosted deployments | LiveKit Documentation | Server options | LiveKit Documentation
h
How do i ensure that the agent stays silent after a function call?
t
You're asking how to make the agent remain silent after a function call — great question. There are two straightforward approaches depending on where you define the tool (Agent Builder vs SDK) and how strict you need the silence to be. Short answer • Use a silent tool: mark the tool as Silent so the tool result is hidden from the agent and the agent will not produce a follow-up response. • Or, in code, have the tool return nothing (or a value the agent ignores) or use a wrapper that triggers no output. Combine that with LLM instruction tuning if you need stricter guarantees. Details and options 1) Use the Agent Builder “Silent” option (recommended when available) • When defining the tool in the Agent Builder, enable the Silent option. ◦ For HTTP tools: the call result is hidden from the agent and no response is generated. ◦ For Client tools: the result is also hidden and the agent will not generate a response. • This is the simplest way to ensure the agent stays silent after the tool runs. 2) Programmatic / SDK approach • Return no response from the tool (e.g., return
None
or an empty payload) so the agent has nothing to echo back. • Or implement the tool to perform its action but not emit any messages that the agent will surface. • If you need ordering or additional control, wrap the function in a tool that explicitly suppresses agent output. 3) Combine silent tools with LLM instructions • Add instruction-level guidance to the agent’s system prompt: tell the model not to produce any output after specific tool calls. • This reduces the risk of the LLM generating commentary even if a tool returns something. 4) For critical guarantees (best-effort) • Use the Silent tool configuration as the primary control point. • As a fallback, have the tool start any long-running work as fire-and-forget and return quickly (or enqueue a job), so the agent has nothing to respond to. If you tell me: • whether you’re using the Agent Builder UI or the SDK, and • whether the silence must be guaranteed (no spoken/text response ever) or just “no immediate acknowledgement,” I’ll give exact configuration steps or a small code example tailored to your setup. Sources: Agent Builder | LiveKit Documentation | Agent speech and audio | LiveKit Documentation