Repository: crewAIInc/crewAI (python)

Issue:
[BUG]If only system_template is provided and prompt_template is missing,error occurred!
### Description

The CrewAI framework throws an AttributeError: 'NoneType' object has no attribute 'replace' when attempting to execute a Crew with an Agent configured with only the system_template parameter, while the prompt_template is left undefined (i.e., None).
And ,if prompt_template proveded also,but response_template not provided,error occurred also!

### Steps to Reproduce

simple example 

### Expected behavior

no error,if these three parameters are optional

### Screenshots/Code snippets

from crewai import Agent, Task, Crew

# Incorrect Agent configuration (missing prompt_template)
designer = Agent(
  name="WeChat Layout Expert",
  role="WeChat Layout Expert",
  goal="Design and optimize the generated article for WeChat public accounts.",
  backstory="You are a professional WeChat public account layout designer, familiar with WeChat layout rules.",
  allow_delegation=False,
  memory=True,
  max_rpm=150,
  system_template="You are a professional WeChat public account layout designer...", # system_template present
  # prompt_template is missing
)

# Task and Crew setup (example)
task = Task(description="Layout task", agent=designer)
crew = Crew(agents=[designer], tasks=[task])

# Attempting to execute the Crew will result in the error
crew.kickoff()

### Operating System

Windows 11

### Python Version

3.10

### crewAI Version

102

### crewAI Tools Version

no tool

### Virtual Environment

Venv

### Evidence

Traceback (most recent call last):
  File "C:\Users\X\Desktop\test\src\test\main.py", line 26, in run
    Test().crew().kickoff(inputs=inputs)
    ^^^^^^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 36, in __init__
    self.map_all_task_variables()
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 203, in map_all_task_variables
    self._map_task_variables(
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 236, in _map_task_variables
    self.tasks_config[task_name]["agent"] = agents[agent_name]()
                                            ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\utils.py", line 11, in memoized_func
    cache[key] = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X\Desktop\test\src\test\crew.py", line 37, in designer
    return Agent(
           ^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\pydantic\main.py", line 214, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 133, in post_init_setup
    self._setup_agent_executor()
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 143, in _setup_agent_executor
    self.set_cache_handler(self.cache_handler)
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agents\agent_builder\base_agent.py", line 341, in set_cache_handler
    self.create_agent_executor()
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 291, in create_agent_executor
    ).task_execution()
      ^^^^^^^^^^^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\utilities\prompts.py", line 41, in task_execution
    "prompt": self._build_prompt(
              ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\X\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\utilities\prompts.py", line 67, in _build_prompt
    prompt = prompt_template.replace(
             ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'replace'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\X\Desktop\test\src\test\main.py", line 175, in <module>
    test()
  File "C:\Users\X\Desktop\test\src\test\main.py", line 171, in test
    run(inputs)
  File "C:\Users\X\Desktop\test\src\test\main.py", line 28, in run
    raise Exception(f"An error occurred while running the crew: {e}")
Exception: An error occurred while running the crew: 'NoneType' object has no attribute 'replace'
---------------
Traceback (most recent call last):
  File "C:\Users\XX\Desktop\test\src\test\main.py", line 26, in run
    Test().crew().kickoff(inputs=inputs)
    ^^^^^^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 36, in __init__
    self.map_all_task_variables()
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 203, in map_all_task_variables
    self._map_task_variables(
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\crew_base.py", line 236, in _map_task_variables
    self.tasks_config[task_name]["agent"] = agents[agent_name]()
                                            ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\project\utils.py", line 11, in memoized_func
    cache[key] = func(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\XX\Desktop\test\src\test\crew.py", line 37, in designer
    return Agent(
           ^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\pydantic\main.py", line 214, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 133, in post_init_setup
    self._setup_agent_executor()
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 143, in _setup_agent_executor
    self.set_cache_handler(self.cache_handler)
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agents\agent_builder\base_agent.py", line 341, in set_cache_handler
    self.create_agent_executor()
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\agent.py", line 291, in create_agent_executor
    ).task_execution()
      ^^^^^^^^^^^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\utilities\prompts.py", line 41, in task_execution
    "prompt": self._build_prompt(
              ^^^^^^^^^^^^^^^^^^^
  File "C:\Users\XX\AppData\Local\Programs\Python\Python311\Lib\site-packages\crewai\utilities\prompts.py", line 70, in _build_prompt
    response = response_template.split("{{ .Response }}")[0]
               ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'split'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\XX\Desktop\test\src\test\main.py", line 175, in <module>
    test()
  File "C:\Users\XX\Desktop\test\src\test\main.py", line 171, in test
    run(inputs)
  File "C:\Users\XX\Desktop\test\src\test\main.py", line 28, in run
    raise Exception(f"An error occurred while running the crew: {e}")
Exception: An error occurred while running the crew: 'NoneType' object has no attribute 'split'

### Possible Solution

i dont know 

### Additional context

use system_template（prompt_template、response_template provided）,gemini cant run correctly,,,but deepseek 、qwq32b run no error

Pull request description:
Fixes missing prompt template or system template
Fixes #2402

Built on top of #2403, 
Changed the structure of files and added test cases in the test_agent itself.

Patch:
diff --git a/docs/concepts/agents.mdx b/docs/concepts/agents.mdx
index fa954d4f..4234e642 100644
--- a/docs/concepts/agents.mdx
+++ b/docs/concepts/agents.mdx
@@ -255,7 +255,11 @@ custom_agent = Agent(
 - `response_template`: Formats agent responses
 
 <Note>
-When using custom templates, you can use variables like `{role}`, `{goal}`, and `{input}` in your templates. These will be automatically populated during execution.
+When using custom templates, ensure that both `system_template` and `prompt_template` are defined. The `response_template` is optional but recommended for consistent output formatting.
+</Note>  
+
+<Note>
+When using custom templates, you can use variables like `{role}`, `{goal}`, and `{backstory}` in your templates. These will be automatically populated during execution.
 </Note>
 
 ## Agent Tools
diff --git a/src/crewai/utilities/prompts.py b/src/crewai/utilities/prompts.py
index 0100f0f0..cd357787 100644
--- a/src/crewai/utilities/prompts.py
+++ b/src/crewai/utilities/prompts.py
@@ -54,10 +54,12 @@ class Prompts(BaseModel):
         response_template=None,
     ) -> str:
         """Constructs a prompt string from specified components."""
-        if not system_template and not prompt_template:
+        if not system_template or not prompt_template:
+            # If any of the required templates are missing, fall back to the default format
             prompt_parts = [self.i18n.slice(component) for component in components]
             prompt = "".join(prompt_parts)
         else:
+            # All templates are provided, use them
             prompt_parts = [
                 self.i18n.slice(component)
                 for component in components
@@ -67,8 +69,12 @@ class Prompts(BaseModel):
             prompt = prompt_template.replace(
                 "{{ .Prompt }}", "".join(self.i18n.slice("task"))
             )
-            response = response_template.split("{{ .Response }}")[0]
-            prompt = f"{system}\n{prompt}\n{response}"
+            # Handle missing response_template
+            if response_template:
+                response = response_template.split("{{ .Response }}")[0]
+                prompt = f"{system}\n{prompt}\n{response}"
+            else:
+                prompt = f"{system}\n{prompt}"
 
         prompt = (
             prompt.replace("{goal}", self.agent.goal)


Test patch:
diff --git a/tests/agent_test.py b/tests/agent_test.py
index 94d68cab..b3d243a5 100644
--- a/tests/agent_test.py
+++ b/tests/agent_test.py
@@ -72,9 +72,54 @@ def test_agent_creation():
     assert agent.role == "test role"
     assert agent.goal == "test goal"
     assert agent.backstory == "test backstory"
-    assert agent.tools == []
 
+def test_agent_with_only_system_template():
+    """Test that an agent with only system_template works without errors."""
+    agent = Agent(
+        role="Test Role",
+        goal="Test Goal",
+        backstory="Test Backstory",
+        allow_delegation=False,
+        system_template="You are a test agent...",
+        # prompt_template is intentionally missing
+    )
+
+    assert agent.role == "Test Role"
+    assert agent.goal == "Test Goal"
+    assert agent.backstory == "Test Backstory"
+
+def test_agent_with_only_prompt_template():
+    """Test that an agent with only system_template works without errors."""
+    agent = Agent(
+        role="Test Role",
+        goal="Test Goal",
+        backstory="Test Backstory",
+        allow_delegation=False,
+        prompt_template="You are a test agent...",
+        # prompt_template is intentionally missing
+    )
+
+    assert agent.role == "Test Role"
+    assert agent.goal == "Test Goal"
+    assert agent.backstory == "Test Backstory"
+
+
+def test_agent_with_missing_response_template():
+    """Test that an agent with system_template and prompt_template but no response_template works without errors."""
+    agent = Agent(
+        role="Test Role",
+        goal="Test Goal",
+        backstory="Test Backstory",
+        allow_delegation=False,
+        system_template="You are a test agent...",
+        prompt_template="This is a test prompt...",
+        # response_template is intentionally missing
+    )
 
+    assert agent.role == "Test Role"
+    assert agent.goal == "Test Goal"
+    assert agent.backstory == "Test Backstory"
+    
 def test_agent_default_values():
     agent = Agent(role="test role", goal="test goal", backstory="test backstory")
     assert agent.llm.model == "gpt-4o-mini"