colossal-xylophone-68609
04/10/2026, 7:32 AMtall-airline-16756
04/10/2026, 7:32 AMtall-airline-16756
04/10/2026, 7:32 AMon_enter method and want an example. Good question.
Short answer: No — you should not call a function tool directly (e.g., await self.my_tool(...)) inside on_enter. on_enter is a lifecycle method for initializing agent behavior and generating messages; function tools are intended to be invoked by the LLM during its reasoning. Calling the tool synchronously from on_enter bypasses the LLM-driven tool call flow and can cause incorrect behavior.
What to do instead: prompt the LLM in on_enter so it decides to invoke the tool. Example pattern:
from livekit.agents import Agent, function_tool, RunContext
class WeatherAgent(Agent):
def __init__(self):
super().__init__(instructions="You are a weather assistant. On start, check weather for New York.")
async def on_enter(self) -> None:
# Prompt the model so it will choose to call the tool
await self.session.generate_reply(instructions="Please check the current weather in New York.")
@function_tool()
async def lookup_weather(self, context: RunContext, location: str) -> str:
# This is a tool the LLM can invoke (LLM will supply `location`)
return f"The weather in {location} is sunny and 75°F."
Key points:
• Use on_enter to generate a message that instructs the LLM to call the tool.
• Do not call the tool method directly inside `on_enter`; let the LLM invoke it so the tool call is recorded and handled correctly.
If you'd like, I can adapt the example to your specific tool signature or show how to capture the tool's result back into agent state. Which tool or use case do you have in mind?
Sources: Function tool definition | LiveKit Documentation, with interactive elementscolossal-xylophone-68609
04/10/2026, 7:36 AMtall-airline-16756
04/10/2026, 7:37 AM@function_tool. You cannot decorate an arbitrary standalone function with @function_tool as if that makes it an LLM-invocable tool directly. Instead, define a small wrapper method decorated with @function_tool that calls your normal function. That preserves normal Python logic while exposing the tool to the LLM.
Example pattern:
# normal function (pure Python, reusable)
def compute_tax(amount: float, rate: float) -> float:
return amount * rate
from livekit.agents import function_tool, RunContext
class BillingAgent:
@function_tool()
async def compute_tax_tool(self, context: RunContext, amount: float, rate: float) -> float:
# wrapper calls the normal function
return compute_tax(amount, rate)
Notes:
• Keep business logic in plain functions (testable, reusable).
• Expose only small, well-typed wrappers with @function_tool() so the LLM can invoke them.
• Do not call the tool function directly when you need an LLM-invoked call; let the LLM invoke the decorated wrapper so the tool call is tracked and handled correctly.
If you want, tell me the signature of your existing function and I’ll show the exact wrapper for it.
, with interactive elementscolossal-xylophone-68609
04/10/2026, 7:38 AMtall-airline-16756
04/10/2026, 7:39 AMfunction_tool and how to receive the `ctx`/`context` parameter. Short answer: include a RunContext (commonly named context or ctx) as the first parameter of the tool wrapper; the framework injects it automatically—you don't pass it yourself.
Python example:
from livekit.agents import function_tool, RunContext
def compute_tax(amount: float, rate: float) -> float:
return amount * rate
class BillingAgent:
@function_tool()
async def compute_tax_tool(self, context: RunContext, amount: float, rate: float) -> float:
# `context` is automatically provided by the framework
# you can access session/state via context.session, context.userdata, etc.
return compute_tax(amount, rate)
Node.js example:
// plain function
function computeTax(amount: number, rate: number) {
return amount * rate;
}
export default {
execute: async ({ amount, rate }, { ctx }) => {
// `ctx` is automatically provided
// you can use ctx.session, ctx.userdata, etc.
return computeTax(amount, rate);
}
}
Key points:
• The tool signature must include context: RunContext (Python) or receive { ctx } (Node).
• You never manually pass ctx when the LLM invokes the tool; the system injects it.
• Use context to access session, userdata, interruption status, and playback helpers.
Would you like an example showing use of context.session or context.userdata inside the tool?
Sources: Function tool definition | LiveKit Documentation, with interactive elementscolossal-xylophone-68609
04/10/2026, 7:45 AMtall-airline-16756
04/10/2026, 7:45 AMon_enter returns a value.
Short answer: nothing useful — on_enter is an async lifecycle hook that is expected to return None. Any value you return is not consumed or acted on by the framework. Use on_enter for side effects (generate a reply, set state, etc.) rather than returning data.
If you need to pass data out of on_enter, store it on session/state (for example context.userdata or self.session), or trigger a message that causes the LLM or another handler to run and produce/consume the value. Would you like an example showing how to save data from on_enter into context.userdata?
Sources: Agents and handoffs | LiveKit Documentation | Pipeline nodes and hooks | LiveKit Documentation, with interactive elements