-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Problem
When deserializing a CodeAgent (or TreeAgent) with managed agents (sub-agents), the MultiStepAgent.from_dict() method incorrectly passes the parent agent's **kwargs to child agents during deserialization, causing child agent configurations (especially additional_authorized_imports) to be overridden by the parent's configuration.
This results in child agents losing their custom authorized_imports after deserialization, causing runtime errors when they try to execute code that depends on those imports (e.g., sympy).
Steps to reproduce
- Create a sub-agent with custom
additional_authorized_imports(e.g.,["sympy"]) - Create a main agent with the sub-agent as a managed agent
- Serialize the main agent using
.to_dict() - Deserialize using
.from_dict() - Check the sub-agent's
authorized_imports- the custom imports are missing
from smolagents import CodeAgent, LiteLLMModel
import os
# Initialize model
model = LiteLLMModel(
model_id="deepseek/deepseek-chat",
api_key=os.environ.get("DEEPSEEK_API_KEY"),
api_base="https://api.deepseek.com",
)
# Create sub-agent with custom authorized_imports
sub_agent = CodeAgent(
tools=[],
model=model,
max_steps=3,
additional_authorized_imports=["sympy"], # Custom import
name="sympy_agent",
description="Math expert using sympy",
)
# Create main agent with the sub-agent
main_agent = CodeAgent(
tools=[],
model=model,
managed_agents=[sub_agent],
max_steps=2,
)
# Serialize and check
agent_dict = main_agent.to_dict()
print("=== Serialized data ===")
for ma_dict in agent_dict.get("managed_agents", []):
print(f"Sub-agent '{ma_dict['name']}' authorized_imports:")
print(f" {ma_dict.get('authorized_imports')}")
print(f" Has 'sympy': {'sympy' in ma_dict.get('authorized_imports', [])}")
# Deserialize
restored_agent = CodeAgent.from_dict(agent_dict)
# Check restored data
print("\n=== Restored agent ===")
for name, sub_agent_restored in restored_agent.managed_agents.items():
print(f"Sub-agent '{name}' authorized_imports:")
print(f" {sub_agent_restored.authorized_imports}")
print(f" Has 'sympy': {'sympy' in sub_agent_restored.authorized_imports}")Actual behavior and error logs
=== Serialized data ===
Sub-agent 'sympy_agent' authorized_imports:
['collections', 'datetime', 'itertools', 'math', 'queue', 'random', 're', 'stat', 'statistics', 'sympy', 'time', 'unicodedata']
Has 'sympy': True
=== Restored agent ===
Sub-agent 'sympy_agent' authorized_imports:
['collections', 'datetime', 'itertools', 'math', 'queue', 'random', 're', 'stat', 'statistics', 'time', 'unicodedata']
Has 'sympy': False
The custom import 'sympy' is present in the serialized dictionary but missing after deserialization.
When the sub-agent tries to execute code using sympy, it raises:
AgentExecutionError: Import of 'sympy' is not allowed
Expected behavior
The restored sub-agent should retain its authorized_imports from the serialized dictionary, including 'sympy'. The deserialized agent should be functionally identical to the original agent.
Root Cause
In smolagents/agents.py, line 1027 in MultiStepAgent.from_dict():
managed_agent = agent_class.from_dict(managed_agent_dict, **kwargs)The **kwargs contains the parent agent's code_agent_kwargs (including additional_authorized_imports), which is then passed to child agents.
Then in CodeAgent.from_dict() at line 1774:
code_agent_kwargs.update(kwargs) # Parent's kwargs override child's configThis causes the parent agent's additional_authorized_imports (without sympy) to override the child agent's own configuration (with sympy).
Proposed Fix
Option 1: Don't pass kwargs to child agents (simplest fix)
In MultiStepAgent.from_dict(), line 1027:
# Current (buggy)
managed_agent = agent_class.from_dict(managed_agent_dict, **kwargs)
# Fixed
managed_agent = agent_class.from_dict(managed_agent_dict) # Don't pass **kwargsOption 2: Use a whitelist for shared parameters (better design)
Only pass parameters that should be shared (e.g., model):
# Define which parameters should be shared with child agents
SHARED_PARAMS = {"model", "verbosity_level"}
shared_kwargs = {k: v for k, v in kwargs.items() if k in SHARED_PARAMS}
# Pass only shared parameters
managed_agent = agent_class.from_dict(managed_agent_dict, **shared_kwargs)Rationale:
- Agent-specific parameters like
additional_authorized_imports,max_steps,tools, etc. should not be passed to child agents - Only truly shared resources like
modelinstances should propagate down - This preserves child agent independence while allowing resource sharing
Environment:
- OS: macOS
- Python version: 3.12
- Package version:
Name: smolagents
Version: 1.22.0
Additional context
This bug affects any workflow that:
- Uses managed agents (multi-agent systems)
- Requires child agents to have custom
additional_authorized_imports - Needs to serialize/deserialize agents (e.g., for checkpointing, tree search, distributed training)
Temporary workaround: Override from_dict() in a custom agent class to manually load managed agents without passing **kwargs.
Checklist
- I have searched the existing issues and have not found a similar bug report.
- I have provided a minimal, reproducible example.
- I have provided the full traceback of the error.
- I have provided my environment details.
- I am willing to work on this issue and submit a pull request.