From d0e629ee8df232dc50a1556f33999cd56ddddd34 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 11 Oct 2025 06:34:20 +0000 Subject: [PATCH] Fix task configuration with None context parameter in YAML MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #3696 When context: None is specified in YAML, yaml.safe_load() converts it to the string 'None' instead of Python's None object. The code was attempting to iterate over this string character by character, causing KeyError: 'N' when trying to look up task names. Changes: - Added isinstance(context_list, list) check in crew_base.py before iterating context_list to handle YAML's conversion of None to string - Added test case test_task_with_none_context_from_yaml to verify tasks can be configured with context: None without errors - Added test YAML configurations in tests/config_none_context/ to reproduce and verify the fix The fix ensures that only actual list values are processed, allowing None and other non-list values to pass through without causing errors. Co-Authored-By: João --- src/crewai/project/crew_base.py | 7 +++--- tests/config_none_context/agents.yaml | 5 ++++ tests/config_none_context/tasks.yaml | 11 +++++++++ tests/test_project.py | 35 +++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 tests/config_none_context/agents.yaml create mode 100644 tests/config_none_context/tasks.yaml diff --git a/src/crewai/project/crew_base.py b/src/crewai/project/crew_base.py index 44871f6a0..b21853c47 100644 --- a/src/crewai/project/crew_base.py +++ b/src/crewai/project/crew_base.py @@ -260,9 +260,10 @@ def CrewBase(cls: T) -> T: # noqa: N802 output_pydantic_functions: dict[str, Callable], ) -> None: if context_list := task_info.get("context"): - self.tasks_config[task_name]["context"] = [ - tasks[context_task_name]() for context_task_name in context_list - ] + if isinstance(context_list, list): + self.tasks_config[task_name]["context"] = [ + tasks[context_task_name]() for context_task_name in context_list + ] if tools := task_info.get("tools"): self.tasks_config[task_name]["tools"] = [ diff --git a/tests/config_none_context/agents.yaml b/tests/config_none_context/agents.yaml new file mode 100644 index 000000000..cf3401e9c --- /dev/null +++ b/tests/config_none_context/agents.yaml @@ -0,0 +1,5 @@ +test_agent: + role: Test Agent + goal: Test goal + backstory: Test backstory + verbose: true diff --git a/tests/config_none_context/tasks.yaml b/tests/config_none_context/tasks.yaml new file mode 100644 index 000000000..a282a08a7 --- /dev/null +++ b/tests/config_none_context/tasks.yaml @@ -0,0 +1,11 @@ +task_with_none_context: + description: A test task with None context + expected_output: Some output + agent: test_agent + context: None + +task_with_valid_context: + description: A test task with valid context + expected_output: Some output + agent: test_agent + context: [task_with_none_context] diff --git a/tests/test_project.py b/tests/test_project.py index c6708d92f..a6ee5bb90 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -287,3 +287,38 @@ def test_internal_crew_with_mcp(): adapter_mock.assert_called_once_with( {"host": "localhost", "port": 8000}, connect_timeout=120 ) + + +def test_task_with_none_context_from_yaml(): + @CrewBase + class CrewWithNoneContext: + agents_config = "config_none_context/agents.yaml" + tasks_config = "config_none_context/tasks.yaml" + + agents: list[BaseAgent] + tasks: list[Task] + + @agent + def test_agent(self): + return Agent(config=self.agents_config["test_agent"]) + + @task + def task_with_none_context(self): + return Task(config=self.tasks_config["task_with_none_context"]) + + @task + def task_with_valid_context(self): + return Task(config=self.tasks_config["task_with_valid_context"]) + + @crew + def crew(self): + return Crew(agents=self.agents, tasks=self.tasks, verbose=True) + + crew_instance = CrewWithNoneContext() + + task_none = crew_instance.task_with_none_context() + assert task_none is not None + + task_valid = crew_instance.task_with_valid_context() + assert task_valid.context is not None + assert len(task_valid.context) == 1