busy-spoon-35253
03/06/2026, 4:15 AMtall-airline-16756
03/06/2026, 4:15 AMtall-airline-16756
03/06/2026, 4:15 AM@function_tool() decorator to create a tool method on your agent. This attaches a human-readable description to the tool and makes it available to the LLM at each turn.
Example (Python-like pseudocode):
@function_tool()
async def send_metadata(self, context: RunContext, metadata: str):
"""Send metadata to frontend via RPC.
Args:
metadata: The metadata string to send to remote participants.
"""
try:
room = get_job_context().room
participant_identity = next(iter(room.remote_participants))
response = await room.local_participant.perform_rpc(
destination_identity=participant_identity,
method="sendMetadata",
payload=json.dumps({"metadata": metadata}),
response_timeout=5.0,
)
return {"status": "success", "response": response}
except Exception:
raise ToolError("Failed to send metadata")
Why this works:
• @function_tool() exposes the tool and its docstring/description to the LLM so it can decide to call it during any turn.
• The tool implementation uses the room and local_participant.perform_rpc to send the metadata payload to a remote participant via the RPC channel.
2) Ensure the agent includes instructions that encourage using the tool
• Put a brief instruction when constructing the agent so the LLM knows when to use send_metadata.
Example:
class MyAgent(Agent):
def __init__(self):
super().__init__(
instructions="You are a helpful assistant. Use the send_metadata tool to forward metadata to the client whenever you need to send non-speech metadata or state updates."
)
Why this matters:
• The tool is available automatically once defined on the agent instance, but clear instructions help the LLM choose the tool at the appropriate times.
3) Frontend: register the RPC handler to receive metadata
• On the client side, register a handler for the RPC method name you call ("sendMetadata" in the example).
Example (TypeScript-like):
localParticipant.registerRpcMethod(
'sendMetadata',
async (data: RpcInvocationData) => {
const payload = JSON.parse(data.payload);
console.log('Received metadata:', payload.metadata);
// Update UI or store metadata as needed
return JSON.stringify({ received: true });
}
);
4) Persistence across turns
• Tools defined on the agent instance persist for the session. The LLM receives the tool description as part of the decision inputs each turn, so you do not need to re-register the tool per turn.
5) Quick diagnostics / checklist if it’s not working
• Confirm the agent actually has the tool defined on the running instance (same process as the decision loop).
• Verify room.remote_participants contains the expected participant identity.
• Make sure the frontend has registered the RPC method name you call.
• Check RPC timeouts and catch exceptions/log them inside the tool for visibility.
Would you like:
• A copy-ready code sample adapted to your existing agent class?
• Guidance on sending structured JSON metadata (vs. plain strings) and error-handling patterns?
• Help mapping this to your specific method names or room/participant selection logic?
If you share a small snippet of your current agent code (agent class + how you manage job/room context), I can show the exact insertion points and a tailored example.
Sources: Tool definition and use | LiveKit Documentation