diff --git a/src/crewai/agents/agent_builder/base_agent.py b/src/crewai/agents/agent_builder/base_agent.py index e602e42a9..0ecf83b82 100644 --- a/src/crewai/agents/agent_builder/base_agent.py +++ b/src/crewai/agents/agent_builder/base_agent.py @@ -314,6 +314,15 @@ class BaseAgent(ABC, BaseModel): return copied_agent + def _interpolate_only(self, input_string: str, inputs: Dict[str, Any]) -> str: + """Interpolate placeholders (e.g., {key}) in a string while leaving JSON untouched.""" + escaped_string = input_string.replace("{", "{{").replace("}", "}}") + + for key in inputs.keys(): + escaped_string = escaped_string.replace(f"{{{{{key}}}}}", f"{{{key}}}") + + return escaped_string.format(**inputs) + def interpolate_inputs(self, inputs: Dict[str, Any]) -> None: """Interpolate inputs into the agent description and backstory.""" if self._original_role is None: @@ -324,9 +333,9 @@ class BaseAgent(ABC, BaseModel): self._original_backstory = self.backstory if inputs: - self.role = self._original_role.format(**inputs) - self.goal = self._original_goal.format(**inputs) - self.backstory = self._original_backstory.format(**inputs) + self.role = self._interpolate_only(self._original_role, inputs) + self.goal = self._interpolate_only(self._original_goal, inputs) + self.backstory = self._interpolate_only(self._original_backstory, inputs) def set_cache_handler(self, cache_handler: CacheHandler) -> None: """Set the cache handler for the agent. diff --git a/tests/agent_test.py b/tests/agent_test.py index e67a7454a..4874c2b30 100644 --- a/tests/agent_test.py +++ b/tests/agent_test.py @@ -1357,6 +1357,32 @@ def test_handle_context_length_exceeds_limit_cli_no(): mock_handle_context.assert_not_called() +def test_interpolate_inputs_with_tool_description(): + from crewai.tools import BaseTool + + class DummyTool(BaseTool): + name: str = "dummy_tool" + description: str = "Tool Arguments: {'arg': {'description': 'test arg', 'type': 'str'}}" + + def _run(self, arg: str) -> str: + """Run the tool.""" + return f"Dummy result for: {arg}" + + tool = DummyTool() + agent = Agent( + role="{topic} specialist", + goal="Figure {goal} out", + backstory="I am the master of {role}\nTools: {tool_desc}", + ) + + agent.interpolate_inputs({ + "topic": "AI", + "goal": "life", + "role": "all things", + "tool_desc": tool.description + }) + assert "Tool Arguments: {'arg': {'description': 'test arg', 'type': 'str'}}" in agent.backstory + def test_agent_with_all_llm_attributes(): agent = Agent( role="test role",