Overview
ToolManager owns everything an Agent does with tools. It builds the tool executor, turns your callables into schemas, registers handoffs, defers schemas behind tool_search, normalizes model output, runs tool calls (local callables, MCP servers, handoffs, tool search), retries a failed batch, summarizes tool output, and prints tool activity.
Every Agent builds one automatically as agent.tool_manager. You rarely construct it yourself, but it is where tool behavior lives.
All tool handling now lives in this class instead of
swarms/structs/agent.py. Agent keeps only add_tool, add_tools, remove_tool, remove_tools, and the mcp_enabled property. Every other tool method is called on agent.tool_manager. See Agent-level API for what moved.Import
ToolManager is not re-exported from swarms or swarms.agents. Use the module path above.
Design
ToolManager holds a reference back to its owning agent and keeps no state of its own. Every value it reads or writes lives on the agent, so agent.tools_list_dictionary, agent.tool_struct, and agent.tool_loader stay the source of truth, and the autonomous loop and LLMManager see the same values.
It also reads configuration from the agent:
tool_schema, list_base_models, handoffs, dynamic_tools, mcp_enabled, max_loops, tool_retry_attempts, tool_call_summary, show_tool_execution_output, print_on, and verbose.
Any
required
The owning
Agent. Its tool state is read and written through this reference.Lifecycle at construction
1
Build the manager
Agent.__init__ creates ToolManager(agent=self) right after LLMManager, once its configuration is set.2
setup_tools
After
short_memory exists, the agent calls setup_tools(). It builds BaseTool(tools=agent.tools, verbose=agent.verbose) as agent.tool_struct, then adds any tool_schema or list_base_models schemas to memory.3
load_tools
After the reasoning and ReAct prompts are appended, the agent calls
load_tools(). Handoffs are registered first. Then the tools are either deferred behind tool_search or registered eagerly.4
Build the LLM
The agent builds its LLM, which reads
tools_list_dictionary. With MCP servers configured, LLMManager calls defer_mcp_tools() when a loader exists, or add_mcp_tools_to_memory() otherwise. See LLMManager.How a tool call runs
Each loop ofAgent.run with an integer max_loops sends one request, then hands the reply to the manager:
1
Parse the reply
parse_response turns the raw reply into text or a list of tool-call dicts. The agent adds it to short_memory and records the assistant turn in the run transcript.2
Run tool searches
When
agent.tool_loader is set, tool_search calls run first. Each result is recorded and removed from the batch. If nothing else is left, the turn ends here.3
Run handoffs
Each
handoff_task call delegates to the named agents through handoff_task_tool. The combined responses are recorded as "Handoff Result: ...".4
Run local callables
When
agent.tools is non-empty, tool_execution_retry runs the batch through execute_tools. The output is mapped back to each tool-call id.5
Run MCP calls
When
agent.mcp_enabled is true, mcp_tool_handling sends the reply to the agent’s MCPManager, which routes each call to the server that exposes it.6
Answer every call
Every tool call recorded in the transcript gets exactly one tool result. A call with no recorded result gets a
(no result recorded for <name>) placeholder, because a gap makes the next request invalid.output_type="final" and swarm structures that read each agent’s answer correct.
Local callables
execute_tools calls agent.tool_struct.execute_function_calls_from_api_response(response). Calls in one batch run in parallel on up to four threads, and results come back in call order. Each result is formatted as Function '<name>' result: followed by the value.
MCP servers
mcp_tool_handling executes the calls through agent.mcp_manager.execute_tool_calls(response, output_type="dict"). Non-empty results are recorded as "MCP Tool Response: ...". A summary call over the whole conversation always follows, whatever tool_call_summary is set to. If that summary call fails, a fixed sentence is recorded instead.
Handoffs
handoff_task calls run through swarms.tools.handoffs_tool.handoff_task. Each request names an agent, a task, and a reasoning string. One target runs directly; several run in parallel threads. Unknown agent names and missing fields are returned to the model as validation errors, not raised.
Tool search
Withdynamic_tools=True, tool_search calls run through tool_search_tool, which loads matching schemas from the catalog. The newly loaded tools are callable from the next request. See Dynamic Tool Loading.
Retries and failures
tool_retry_attempts (default 3) sets how many times the local batch runs before the manager gives up.
- Each attempt runs the whole batch once. Calls in the batch that succeeded run again with it.
- An exception anywhere in
execute_toolscounts as a failed attempt. That includes thetool_call_summarymodel call. - After the last attempt,
tool_execution_retryraisesAgentToolExecutionError, chained from the last error.
AgentToolExecutionError apart from provider errors. It answers any recorded tool calls, reports the error to telemetry as Agent.tool_error, adds Tool execution failed after N attempts: ... to memory as a "Tool Executor" turn, and leaves the request retry loop without calling the model again. The run continues, so on the next loop the model reads the failure and can choose differently. A broken tool never consumes retry_attempts, which is reserved for provider failures.
You can drive the retry path directly, without a model call:
Printing tool activity
All output below is gated onagent.print_on. With print_on=False, the manager prints nothing.
Setup
setup_tools
agent.tool_struct from agent.tools, then call handle_tool_schema_ops when tool_schema or list_base_models is set. Returns the executor.
handle_tool_schema_ops
short_memory as JSON text under the agent’s name. These schemas are context for the model. They are not added to tools_list_dictionary, so they are not sent as callable tools.
load_tools
- When
handoffsis set, append thehandoff_taskschema totools_list_dictionaryand append a prompt describing the handoff agents tosystem_prompt. - When
dynamic_tools=Trueand the agent has non-emptytools, an MCP server, ormax_loops="auto", append the dynamic-tools notice tosystem_promptand callsetup_dynamic_tools(). - Otherwise, when
toolsis non-empty, calltool_handling().
tool_handling
agent.tools to an OpenAI function schema and append it to tools_list_dictionary, skipping names already present. The full schema list is then added to short_memory under the agent’s name.
Dynamic tools
setup_dynamic_tools
DynamicToolLoader from agent.tools and store it as agent.tool_loader.
Optional[List[dict]]
default:"None"
Schemas that are never deferred, such as the autonomous loop’s control tools.
tools_list_dictionary, such as the handoff tool, stay always loaded. Your own deferred tools and tool_search are dropped first, because the loader re-adds them. MCP schemas cached by an earlier fetch are re-registered. tools_list_dictionary is then set to loader.schemas(). A rebuilt loader starts with nothing loaded; the autonomous loop rebuilds it at the start of every run.
defer_tool_schemas
tools_list_dictionary. Does nothing when no loader is active. Use this instead of appending to tools_list_dictionary, which the loader overwrites.
defer_mcp_tools
0 when MCP or dynamic tools are off or nothing is new. An unreachable server is logged and treated as zero tools, so agent setup still succeeds.
tool_search_tool
tool_search calls. Searches the catalog with DynamicToolLoader.run_search, loads the matches, refreshes tools_list_dictionary, and rebuilds agent.llm so the next request carries the new schemas.
str
required
Keywords, or
select:name1,name2 for exact names.int
default:"5"
Most tools to load.
float
default:"0.0"
Minimum score relative to the best match.
Tool search is unavailable: this agent was not built with dynamic_tools=True.
MCP
add_mcp_tools_to_memory
agent.mcp_manager.get_tools(). Despite the name, nothing is written to memory; the schemas are returned. Errors are logged and re-raised, for example AgentMCPConnectionError when no server can be reached.
mcp_tool_handling
Handoffs
get_agent_registry
agent.handoffs is returned as is. A list or tuple is keyed by each target’s agent_name. Anything else returns {}.
handoff_task_tool
List[Dict[str, str]]
required
Requests, each with
agent_name, task, and reasoning keys.Parsing
parse_llm_output
Raises
ValueError if the reply cannot be normalized.
parse_response
tools_list_dictionary is set, then calls parse_llm_output.
Execution
handle_tool_calls
Any
required
The parsed model reply.
int
required
The current loop number, used in logs and panels.
Optional[Transcript]
default:"None"
The run’s transcript.
None when the agent uses transforms.Optional[list]
default:"None"
The tool calls recorded in the transcript this turn.
Optional[dict]
default:"None"
Results keyed by tool-call id, updated in place.
AgentToolExecutionError when the local batch fails every attempt.
execute_tools
None reply is logged and skipped. When the executor returns nothing (a text reply), the method returns without recording, printing, or summarizing. Otherwise it records the formatted output as a "Tool Executor" turn, prints it, and, when tool_call_summary=True, records a summary from temp_llm_instance_for_tool_summary(). Raises whatever the executor raises.
tool_execution_retry
execute_tools up to max(1, agent.tool_retry_attempts) times. Returns the executor output on the first success, or None when response is None. Raises AgentToolExecutionError when every attempt fails.
temp_llm_instance_for_tool_summary
LiteLLM for summarizing tool output. It uses the agent’s model, temperature, top_p, max_tokens, system prompt (plus the selected skills), llm_base_url, and llm_api_key. Its token usage is added to the agent’s running total, so summaries show up in agent.usage.
Autonomous loop
These back thecomplete_task tool of the autonomous loop.
complete_task_tool
Task Completion Summary with the task id, status, summary, optional results and lessons, and a breakdown of every subtask in agent.autonomous_subtasks. The text is added to memory under the agent’s name and returned. With verbose=True, subtasks that are not completed or failed are logged as a warning.
handle_complete_task
complete_task call in a final-summary reply, record its result, and return it. Returns None when the reply is not a list or holds no complete_task call.
Printing
visualize_function_call
result to 500. Does nothing when print_on is off.
visualize_handoff_call
handoff_task call. Does nothing when print_on is off.
Agent-level API
These stay onAgent:
These methods are no longer on
Agent. Call the manager instead:
Related
Agent Tools
How to write tools and configure tool execution
Dynamic Tool Loading
Defer schemas behind tool_search
LLMManager
Builds the LLM that carries the tool schemas
MCPManager
Connects MCP servers and routes their tool calls