Overview
Loquent agents use tools in two contexts: voice tools run during live phone calls via the realtime API, and task tools run after calls when the todo execution agent processes approved tasks.
Two Tool Systems
Section titled “Two Tool Systems”Voice Tools
Section titled “Voice Tools”Used by the realtime voice model during a live call. Registered at session start via collect_agent_tools, dispatched through handle_tool_call. Results are spoken to the caller.
| Tool | When Registered | Parameters |
|---|---|---|
| end_call | Always | None |
| query_knowledge | Agent has linked knowledge bases | query: String |
| lookup_caller | Org has client_lookup_url configured | None (phone injected) |
| transfer_call | Agent has configured transfer numbers | phone_number: String (enum-restricted) |
Definition type: AgentToolDefinition — provider-agnostic, converted to OpenAI/Gemini formats at session start.
pub struct AgentToolDefinition { pub name: String, pub description: String, pub parameters: serde_json::Value, // JSON Schema}Task Tools
Section titled “Task Tools”Used by the todo execution AI agent (GPT-5) when processing approved todos. Registered per-todo based on the TodoType’s assigned tools. Run in a standard chat completion agentic loop, not a realtime session.
| Tool | What It Does |
|---|---|
| send_email_to_caller | Send a follow-up email to the caller (recipient auto-resolved from contact) |
| send_email | Send an email to any recipient (AI determines recipient from task context) |
Definition type: aisdk::Tool — includes an executable closure, capped at 10 tool-calling steps per todo.
Voice Tool Pipeline
Section titled “Voice Tool Pipeline”Session start → collect_agent_tools(agent_id, org_id, tool_config) → build_end_call_tool_definition() → (definition, prompt_section) → build_knowledge_tool_definition(agent_id) → Option<(definition, prompt_section)> → build_client_lookup_tool_definition(org_id) → Option<(definition, prompt_section)> → build_transfer_call_tool_definition(tool_config) → Option<(definition, prompt_section)> → Assemble all prompt sections into "## Available Tools" markdown → Return (Vec<AgentToolDefinition>, prompt_addendum)
During call → Model invokes a tool → handle_tool_call routes by function_name → Handler executes and returns result string → Result sent back to realtime model as tool responseTool Prompt Instructions
Section titled “Tool Prompt Instructions”Each tool builder returns a tuple: (AgentToolDefinition, String). The AgentToolDefinition is the structured schema sent to the AI provider. The String is a markdown section with behavioral rules for that tool.
collect_agent_tools assembles all prompt sections into a single ## Available Tools block with ### Subsection per tool, then appends it to the agent’s system instructions. This gives the AI model clear behavioral guidance alongside the tool definitions.
Example prompt section (from end_call):
### Ending the Call- When the conversation is naturally over, say your goodbye and IMMEDIATELY call `end_call`.- Do NOT wait for the caller to respond after your farewell.- Do NOT announce that you are ending the call — just say goodbye and invoke the tool.Each tool defines its own rules: lookup_caller instructs proactive use at call start, query_knowledge requires the tool before answering knowledge questions, and transfer_call requires caller confirmation before transferring.
Task Tool Pipeline
Section titled “Task Tool Pipeline”Todo approved → execute_todos_job picks it up (every 30s) → execute_todo(todo_id) Load TodoType → get assigned SystemTools Build aisdk::Tool for each Run GPT-5 agentic loop (max 10 steps) AI decides which tools to call and with what argumentsError Handling
Section titled “Error Handling”Both systems convert errors to strings and return them to the AI model. The conversation or task continues even if a tool fails. Errors are logged via tracing::error!.
Adding a New Tool
Section titled “Adding a New Tool”Voice Tool
Section titled “Voice Tool”- Create a builder returning
Option<AgentToolDefinition> - Call it in
collect_agent_toolsand push to the tools vector - Add a match arm in
handle_tool_call - Implement the handler function
Task Tool
Section titled “Task Tool”- Add a variant to the
SystemToolenum - Implement
display_name(),description(),as_str(),from_str() - Add a match arm in
execute_todoto build theaisdk::Tool - Implement the execution function
Current SystemTool variants: SendEmailToCaller, SendEmail.