Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/smolagents/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,10 +1022,22 @@ def from_dict(cls, agent_dict: dict[str, Any], **kwargs) -> "MultiStepAgent":
for tool_info in agent_dict["tools"]:
tools.append(Tool.from_code(tool_info["code"]))
# Load managed agents

# Only pass shared parameters to avoid overriding child agent configurations
# Shared params are global resources/runtime settings that should be consistent across all agents
SHARED_PARAMS = {
"model", # Shared model instance (contains API key)
"verbosity_level", # Logging level should be consistent
"logger", # Share the same logger instance if provided
"executor_type", # Code execution environment should be consistent
"executor_kwargs", # Executor configuration should be consistent
}
shared_kwargs = {k: v for k, v in kwargs.items() if k in SHARED_PARAMS}

managed_agents = []
for managed_agent_dict in agent_dict["managed_agents"]:
agent_class = getattr(importlib.import_module("smolagents.agents"), managed_agent_dict["class"])
managed_agent = agent_class.from_dict(managed_agent_dict, **kwargs)
managed_agent = agent_class.from_dict(managed_agent_dict, **shared_kwargs)
managed_agents.append(managed_agent)
# Extract base agent parameters
agent_args = {
Expand Down
83 changes: 83 additions & 0 deletions tests/test_agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,89 @@ def side_effect(module_name):
assert recreated_managed_agent.description == "A managed agent for testing"
assert recreated_managed_agent.max_steps == 5

def test_from_dict_propagates_shared_kwargs_to_managed_agents(self):
"""Test that shared runtime kwargs (model, logger, executor settings) are correctly propagated to managed agents."""
@tool
def fake_tool() -> str:
"""A fake tool"""
return None

# Create managed agent with unique tool and authorized_imports
managed_agent = CodeAgent(
tools=[fake_tool],
model=MagicMock(),
name="managed_agent",
description="A managed agent for testing",
max_steps=5,
additional_authorized_imports=["sympy"],
)

# Create main agent without child's tool and imports
main_agent = CodeAgent(
tools=[],
managed_agents=[managed_agent],
model=MagicMock(),
name="main_agent",
description="Main agent with managed agents",
max_steps=10,
)

# Convert to dict
main_agent_dict = main_agent.to_dict()

# Prepare shared runtime parameters
shared_model = MagicMock()
shared_logger = AgentLogger(LogLevel.DEBUG)
executor_kwargs = {"max_print_outputs_length": 10_000}

# Mock model reconstruction
with patch("smolagents.agents.importlib.import_module") as mock_import:
mock_models_module = MagicMock()
mock_model_class = MagicMock()
mock_model_class.from_dict.return_value = shared_model
mock_models_module.MagicMock = mock_model_class

mock_agents_module = MagicMock()
mock_agents_module.CodeAgent = CodeAgent

def side_effect(module_name):
if module_name == "smolagents.models":
return mock_models_module
elif module_name == "smolagents.agents":
return mock_agents_module
return MagicMock()

mock_import.side_effect = side_effect

# Recreate agent with shared kwargs
recreated_agent = CodeAgent.from_dict(
main_agent_dict,
model=shared_model,
logger=shared_logger,
executor_kwargs=executor_kwargs,
)

# Verify parent agent uses shared resources
assert recreated_agent.model is shared_model
assert recreated_agent.logger is shared_logger
assert recreated_agent.executor_kwargs is executor_kwargs
assert "sympy" not in recreated_agent.authorized_imports
assert "fake_tool" not in recreated_agent.tools

# Verify child agent inherits shared resources
assert "managed_agent" in recreated_agent.managed_agents
child_agent = recreated_agent.managed_agents["managed_agent"]

assert child_agent.model is shared_model
assert child_agent.logger is shared_logger
assert child_agent.executor_kwargs is executor_kwargs

# Verify child preserves its own config
assert "sympy" in child_agent.authorized_imports

# Verify child preserves its own tools
assert "fake_tool" in child_agent.tools


class TestToolCallingAgent:
def test_toolcalling_agent_instructions(self):
Expand Down