Skip to content

fix(tools): serialize plain structured outputs as json#6312

Open
fengjikui wants to merge 3 commits into
crewAIInc:mainfrom
fengjikui:fix/tool-usage-structured-output-json
Open

fix(tools): serialize plain structured outputs as json#6312
fengjikui wants to merge 3 commits into
crewAIInc:mainfrom
fengjikui:fix/tool-usage-structured-output-json

Conversation

@fengjikui

@fengjikui fengjikui commented Jun 24, 2026

Copy link
Copy Markdown

Summary

Fixes #6267.

This makes plain JSON-like tool outputs (for example nested dict/list responses from LangChain-style tools) serialize to JSON before they are sent back to the agent. Non-JSON-serializable outputs still fall back to the existing str(raw_result) behavior.

Why

CrewAI already supports format_output_for_agent() for Pydantic result schemas, but tools without a Pydantic result_schema still used Python repr for dict/list outputs. That leaves nested API responses as single-quoted Python dict strings instead of JSON the LLM can reliably parse.

Validation

  • env -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u http_proxy -u https_proxy -u all_proxy uv run pytest lib/crewai/tests/tools/test_structured_tool.py lib/crewai/tests/tools/test_base_tool.py lib/crewai/tests/tools/test_tool_usage.py -q -> 96 passed
  • env -u HTTP_PROXY -u HTTPS_PROXY -u ALL_PROXY -u http_proxy -u https_proxy -u all_proxy uv run ruff check lib/crewai/src/crewai/tools/structured_tool.py lib/crewai/tests/tools/test_structured_tool.py lib/crewai/tests/tools/test_base_tool.py lib/crewai/tests/tools/test_tool_usage.py -> All checks passed!
  • Manual smoke: a LangChain-shaped mock_api_tool returning {"status": "success", "data": {"items": [...]}} now produces json.loads(result.result)-parseable agent text.

AI assistance

AI assistance was used to inspect the issue and current tool execution path, implement this focused change, and run the validation above. I reviewed the final diff and test output.

Summary by CodeRabbit

  • New Features / Improvements

    • Tool outputs that are structured mappings (and non-string sequences) are now serialized as JSON for clearer, agent-friendly consumption.
    • If the output can’t be serialized to JSON (for example, circular references), formatting falls back to plain string output.
  • Tests

    • Updated and expanded coverage for base tools, structured tools, and end-to-end tool usage to verify JSON output for non-Pydantic mapping returns, including circular-reference behavior.

@corridor-security corridor-security 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.

Summary: This PR changes tool output formatting to JSON-serialize plain mapping and sequence results before passing them back to agents.

Risk: Low risk. No exploitable security vulnerabilities were identified; the change does not add authentication, authorization, file, network, subprocess, or database attack surface.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f8afed7-bb77-438a-b779-daa1cc057b2b

📥 Commits

Reviewing files that changed from the base of the PR and between 3cc01e2 and 1802925.

📒 Files selected for processing (1)
  • lib/crewai/tests/tools/test_base_tool.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/tests/tools/test_base_tool.py

📝 Walkthrough

Walkthrough

_format_tool_output_for_agent now JSON-serializes mapping and non-text sequence outputs before falling back to string coercion. The affected tool tests were updated to expect JSON-parseable results, including an end-to-end nested-dict tool execution case.

Changes

JSON serialization fallback for tool outputs

Layer / File(s) Summary
JSON serialization fallback in _format_tool_output_for_agent
lib/crewai/src/crewai/tools/structured_tool.py
Adds Mapping and Sequence checks and attempts json.dumps(raw_result) for those outputs before falling back to str(raw_result) on serialization failure.
Tool output tests updated for JSON serialization
lib/crewai/tests/tools/test_base_tool.py, lib/crewai/tests/tools/test_structured_tool.py, lib/crewai/tests/tools/test_tool_usage.py
Updates assertions to parse formatted output as JSON, renames the affected tests, adds a nested-dict LangChain tool mock, and verifies the execution path returns the expected JSON payload.

Suggested Reviewers

  • lucasgomide
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: serializing plain structured tool outputs as JSON.
Linked Issues check ✅ Passed The PR addresses #6267 by JSON-serializing nested dict-like tool outputs before agent formatting, preventing the reported TypeError.
Out of Scope Changes check ✅ Passed The code and tests stay focused on serialization of structured tool outputs and fallback behavior, with no clear unrelated changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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.

@fengjikui

Copy link
Copy Markdown
Author

Per CONTRIBUTING.md, this PR should have the llm-generated label because AI assistance was used. I attempted to add it, but GitHub returned:

GraphQL: fengjikui does not have the correct permissions to execute `AddLabelsToLabelable` (addLabelsToLabelable)

Please apply the label if needed. The PR body includes the AI assistance disclosure and validation evidence.

@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/crewai/tests/tools/test_base_tool.py (1)

463-472: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add one regression test for non-serializable mapping fallback.

These tests cover successful JSON serialization, but not the new “fallback to str(raw_result)” branch for mapping outputs when json.dumps fails. A small test with a self-referential dict (or similarly unserializable payload) would lock that behavior.

Also applies to: 512-526

🤖 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/tools/test_base_tool.py` around lines 463 - 472, The test
coverage is missing a regression test for the fallback behavior when JSON
serialization fails for mapping outputs. Add a new test method in the same test
class that creates a non-serializable mapping (such as a self-referential
dictionary) and verifies that the format_output_for_agent method falls back to
using str(raw_result) instead of json.dumps when json.dumps fails with an
exception.
🤖 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.

Inline comments:
In `@lib/crewai/src/crewai/tools/structured_tool.py`:
- Around line 65-68: The exception handler in the try-except block around
json.dumps only catches TypeError, but json.dumps can also raise ValueError for
cases like circular references, which would bypass the fallback to
str(raw_result). Modify the except clause to catch both TypeError and ValueError
instead of just TypeError to ensure all serialization failures properly fall
back to the string representation of the raw_result.

---

Nitpick comments:
In `@lib/crewai/tests/tools/test_base_tool.py`:
- Around line 463-472: The test coverage is missing a regression test for the
fallback behavior when JSON serialization fails for mapping outputs. Add a new
test method in the same test class that creates a non-serializable mapping (such
as a self-referential dictionary) and verifies that the format_output_for_agent
method falls back to using str(raw_result) instead of json.dumps when json.dumps
fails with an exception.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 61cabb7d-c6c7-43dc-87db-00ded78ae45d

📥 Commits

Reviewing files that changed from the base of the PR and between a046e6a and c695417.

📒 Files selected for processing (4)
  • lib/crewai/src/crewai/tools/structured_tool.py
  • lib/crewai/tests/tools/test_base_tool.py
  • lib/crewai/tests/tools/test_structured_tool.py
  • lib/crewai/tests/tools/test_tool_usage.py

Comment thread lib/crewai/src/crewai/tools/structured_tool.py
@fengjikui fengjikui force-pushed the fix/tool-usage-structured-output-json branch from f25cf85 to dd33b66 Compare June 24, 2026 16:44
@fengjikui fengjikui force-pushed the fix/tool-usage-structured-output-json branch from dd33b66 to 3cc01e2 Compare June 24, 2026 18:23
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]Agent execution loop crashes with TypeError when custom tool returns a nested dict

1 participant