crewAIInc / crewAIInc/crewAI

[BUG] Custom prompt templates always inject the ReAct `task` slice — wrong instructions for no-tool and native-tool agents

Open Beginner friendly
#7,545 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
58.8k
Forks
8.5k
Avg merge
1d 15h
Merged PRs (30d)
109

Description

Description

Prompts._build_prompt has two code paths: the default one joins the i18n slices selected in task_execution (role_playing, plus tools/no_tools, plus exactly one task slice: task, native_task, or task_no_tools). The custom-template path (taken when both system_template and prompt_template are set) ignores which task slice was selected:

  • {{ .System }} is filled with every component except the literal "task", so native_task and task_no_tools are not excluded — the selected task slice leaks into the system section.
  • {{ .Prompt }} is always filled with the hardcoded "task" slice regardless of the selection.

The "task" slice contains ReAct-only instructions: "use the tools available and give your best Final Answer, your job depends on it!" and a Thought: seed. The result:

  • An agent with no tools (task_no_tools selected) is told to "use the tools available" and gets a Thought: ReAct scaffold — the exact thought-leakage problem the use_system_prompt path was fixed for.
  • An agent using native function calling (native_task selected) gets text ReAct instructions that conflict with the native calling flow.
  • In both cases Current Task: {input} is emitted twice — once via the unfiltered task slice in {{ .System }} and again via the hardcoded task slice in {{ .Prompt }}.

Only the tool-enabled ReAct configuration (task selected) produces correct output today.

Steps to Reproduce
from unittest.mock import MagicMock
from crewai.utilities.prompts import Prompts

agent = MagicMock()
agent.role, agent.goal, agent.backstory = "Writer", "Write", "Pro"

# No tools + custom templates
prompt = Prompts(
    has_tools=False, use_native_tool_calling=False, use_system_prompt=False,
    agent=agent,
    system_template="system:\n{{ .System }}",
    prompt_template="user:\n{{ .Prompt }}",
).task_execution()["prompt"]

print(prompt)
# Actual (buggy): system section contains "Current Task: {input}\nProvide your
# complete response:" AND the user section contains the "task" slice:
#   "use the tools available and give your best Final Answer ... Thought:"
# Expected: user section contains "task_no_tools" ("Provide your complete
# response:"), no tool instructions, "Current Task:" appears exactly once.

# Same failure with native tool calling:
prompt = Prompts(
    has_tools=True, use_native_tool_calling=True, use_system_prompt=False,
    agent=agent,
    system_template="system:\n{{ .System }}",
    prompt_template="user:\n{{ .Prompt }}",
).task_execution()["prompt"]
# Actual (buggy): user section contains the ReAct "task" slice
# ("Thought:" seed, "use the tools available"), and "Current Task: {input}"
# appears twice.

The regression tests in lib/crewai/tests/utilities/test_prompts_no_thought_leakage.py (TestCustomTemplatesPromptGeneration) reproduce both cases — they fail on the unpatched code and pass with the fix; a third test pins the unchanged ReAct-with-tools behavior.

Expected behavior

With custom system_template / prompt_template, {{ .Prompt }} is filled with the task slice that task_execution selected (task_no_tools for an agent without tools, native_task for native tool calling, task otherwise), and that slice does not also appear in {{ .System }}.

Screenshots/Code snippets

lib/crewai/src/crewai/utilities/prompts.py, Prompts._build_prompt, custom-template branch:

  • Line 239: if component != "task" — only excludes the task slice, not native_task/task_no_tools.
  • Line 245: "{{ .Prompt }}", "".join(I18N_DEFAULT.slice("task")) — hardcodes the task slice.

components is built in task_execution (lines 99–118) which appends one of task / native_task / task_no_tools last based on has_tools and use_native_tool_calling. Reached from Agent._build_execution_prompt (lib/crewai/src/crewai/agent/core.py:1133) whenever an agent sets system_template + prompt_template.

Operating System

Ubuntu 22.04

Python Version

3.12

crewAI Version

1.15.22 (main @ 5c33fe4)

crewAI Tools Version

1.15.22

Virtual Environment

Venv

Evidence

Any agent configured with custom system_template/prompt_template that either has no tools or uses native tool calling receives a prompt that (a) instructs it to use tools it does not have / should not call textually, (b) seeds a Thought: prefix that leaks into the final output, and (c) duplicates the Current Task: block. This silently degrades output quality on a documented configuration path (Agent(system_template=..., prompt_template=...)).

Possible Solution

In the custom-template branch, treat all three task-family slices (task, native_task, task_no_tools) as the task component: exclude all of them from the {{ .System }} parts, and fill {{ .Prompt }} with whichever one is present in components (falling back to "task" when none is, preserving prior behavior):

task_components = {"task", "native_task", "task_no_tools"}
template_parts = [
    I18N_DEFAULT.slice(c) for c in components if c not in task_components
]
system = system_template.replace("{{ .System }}", "".join(template_parts))
task_component = next((c for c in components if c in task_components), "task")
prompt = prompt_template.replace("{{ .Prompt }}", I18N_DEFAULT.slice(task_component))
Additional context

Found and written with an AI coding agent (Devin, reviewed by Claude Code); please apply the llm-generated label. A fix with regression tests is ready and will be linked here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in lib/crewai/src/crewai/utilities/prompts.py at Prompts._build_prompt and trace components from task_execution; Agent._build_execution_prompt in lib/crewai/src/crewai/agent/core.py:1133 shows the entry point. Run lib/crewai/tests/utilities/test_prompts_no_thought_leakage.py and confirm custom templates select the matching task slice, exclude it from the system section, and avoid duplicate Current Task text while preserving ReAct behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
ai
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
90/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.