Skip to content

fix(agents): keep null in the task output schema embedded in the prompt - #6775

Open
monkscode wants to merge 2 commits into
crewAIInc:mainfrom
monkscode:fix/task-prompt-schema-preserves-null
Open

fix(agents): keep null in the task output schema embedded in the prompt#6775
monkscode wants to merge 2 commits into
crewAIInc:mainfrom
monkscode:fix/task-prompt-schema-preserves-null

Conversation

@monkscode

Copy link
Copy Markdown

build_task_prompt_with_schema embeds the task output schema into the prompt using
generate_model_description, whose strip_null_types defaults to True. Combined with
ensure_all_properties_required, an Optional[str] = None field is presented to the
model as a required, non-nullable string — leaving it no way to express "not
applicable", and contradicting the provider-side response schema generated from the
same model.

That sanitizer targets OpenAI strict function-calling schemas. This call site produces
prompt prose, where those constraints do not apply.

This passes strip_null_types=False, matching the existing call for tool schemas at
utilities/agent_utils.py:268. required still lists every property, which is the
standard strict-mode idiom once the type is nullable.

Before / after

For class Step(BaseModel): name: str; note: Optional[str] = None:

before   note: {"default": null, "type": "string"}                              <- cannot be null
after    note: {"anyOf": [{"type": "string"}, {"type": "null"}], "default": null}

required is ['name', 'note'] in both cases — unchanged by this PR.

Tests

Adds lib/crewai/tests/agents/test_agent_utils.py. No existing test referenced
build_task_prompt_with_schema, so the file is new; maintainers may prefer it
elsewhere. It fails on main with KeyError: 'anyOf' and passes with this change.

Existing cassette-based tests are unaffected: vcr_config matches on
["method", "scheme", "host", "port", "path"], not on the request body.

Fixes #6774

build_task_prompt_with_schema embeds the task output schema into the prompt
via generate_model_description, whose strip_null_types defaults to True.
Combined with ensure_all_properties_required, an Optional[str] = None field
reaches the model as a required, non-nullable string, contradicting the
provider-side response schema generated from the same model.

That sanitizer targets OpenAI strict function-calling schemas. This call site
produces prompt prose, where those constraints do not apply.

Pass strip_null_types=False, matching the existing call for tool schemas in
utilities/agent_utils.py.

Fixes crewAIInc#6774
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The task prompt schema now preserves null types for JSON and Pydantic outputs. Tests verify that optional Pydantic fields produce schemas accepting both strings and null values.

Changes

Nullable task output schemas

Layer / File(s) Summary
Schema generation and nullable-field validation
lib/crewai/src/crewai/agent/utils.py, lib/crewai/tests/agents/test_agent_utils.py
build_task_prompt_with_schema passes strip_null_types=False when generating JSON and Pydantic schemas. Tests verify that optional fields retain an anyOf schema for string and null values.

Suggested reviewers: lorenzejay

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: preserving null values in task output schemas embedded in prompts.
Description check ✅ Passed The description directly explains the schema bug, the fix, the expected behavior, and the added tests.
Linked Issues check ✅ Passed The changes implement issue #6774 by preserving nullable optional fields and adding tests for the generated prompt schema.
Out of Scope Changes check ✅ Passed The code and test changes are limited to the linked issue objectives and contain no unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
lib/crewai/tests/agents/test_agent_utils.py (2)

25-27: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Cover the output_json branch.

This test constructs Task with output_pydantic only. It never executes the task.output_json branch changed in build_task_prompt_with_schema. Add a matching JSON-output case or parameterize the test over both output attributes.

Based on PR objectives: nullable prompt schemas must be preserved for both JSON and Pydantic outputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/tests/agents/test_agent_utils.py` around lines 25 - 27, Extend the
test around build_task_prompt_with_schema to cover Task configured with
output_json in addition to output_pydantic, either by adding a matching
JSON-output case or parameterizing both configurations. Ensure the assertions
verify nullable prompt schemas are preserved for both output attributes.

33-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the anyOf assertion order-independent.

The exact list comparison makes member order part of the test contract. JSON Schema alternatives are order-independent, so a valid generator change can fail this test.

Proposed assertion
-    assert schema["properties"]["note"]["anyOf"] == [
-        {"type": "string"},
-        {"type": "null"},
-    ]
+    assert {
+        entry["type"] for entry in schema["properties"]["note"]["anyOf"]
+    } == {"string", "null"}

Based on coding guidelines: tests should focus on behavior rather than implementation details.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/tests/agents/test_agent_utils.py` around lines 33 - 36, Update the
`anyOf` assertion in the agent schema test to compare alternatives without
relying on list order, while still requiring exactly the string and null schema
members. Preserve the existing validation of the `note` property’s schema.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/crewai/tests/agents/test_agent_utils.py`:
- Around line 25-27: Extend the test around build_task_prompt_with_schema to
cover Task configured with output_json in addition to output_pydantic, either by
adding a matching JSON-output case or parameterizing both configurations. Ensure
the assertions verify nullable prompt schemas are preserved for both output
attributes.
- Around line 33-36: Update the `anyOf` assertion in the agent schema test to
compare alternatives without relying on list order, while still requiring
exactly the string and null schema members. Preserve the existing validation of
the `note` property’s schema.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fe8f54e9-1bab-4281-b4e9-a21ba24e21be

📥 Commits

Reviewing files that changed from the base of the PR and between c8f441c and 4ca325a.

📒 Files selected for processing (2)
  • lib/crewai/src/crewai/agent/utils.py
  • lib/crewai/tests/agents/test_agent_utils.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Task output schema in the prompt marks Optional fields as required and strips null, so the model cannot express "not applicable"

1 participant