Files
crewAI/AGENTS.md
João Moura 6ad3bf9390 fix(agents): render message content parts as text, not a python repr (#7109)
* fix(agents): render message content parts as text, not a Python repr

A message whose `content` is a multimodal parts list collapsed to
`str(content)` wherever a message had to become a string, so the model
saw `[{'type': 'text', 'text': 'hello'}]` in Current Task, and memory
stored and searched that same repr.

Four sites flattened it that way: the turn promoted into the executor
prompt, the memory recall query, what `_save_kickoff_to_memory` writes,
and `_message_content_text` (token estimation and oversized-message
splitting).

The extraction already existed, inline in `_format_messages_for_summary`
-- text blocks joined, or `[multimodal content]` when a list carries
none. This lifts it to `_content_parts_text` and routes all five callers
through it, so summary, prompt, memory and token counting agree.

`_message_content_text` becomes `message_content_text`: it now has a
caller outside its module, and `agent/core.py` imports only public names
from `agent_utils`. It is not re-exported from any `__init__`, so no
public import path changes.

`test_list_content_uses_str` pinned the repr, so it is intentionally
rewritten to pin the text. Every other existing caller is unchanged:
30 failures on main, 30 on this branch, identical names.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwxiogL9mQg9q8cx4qLfYJ

* fix(agents): skip a content part whose text is not a string

`_content_parts_text` joined `block["text"]` straight into a string, and
content blocks are `dict[str, Any]` arriving from a model, so a `text`
key holding an int, dict or None raised `TypeError`. That was contained
to summarization before; routing the prompt, memory and token-estimation
paths through the same helper widened it to `Agent.kickoff`, where the
old `str()` had merely produced an ugly string.

Such a block carries no usable text, so it is skipped. A list left with
nothing usable still falls back to `[multimodal content]`.

Writes the convention down in AGENTS.md rather than leaving it in a
review thread: never `str()` a message's content, use
`message_content_text`. Four sites had independently reached for
`str()`, which is what this whole change is undoing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwxiogL9mQg9q8cx4qLfYJ

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 19:34:05 +00:00

1.8 KiB

Agent Instructions for CrewAI OSS

CrewAI is a Python based framework for building AI agents and agentic systems. Follow these guidelines when contributing:

Key Guidelines

  1. Follow Python best practices and idiomatic patterns.
  2. Maintain existing code structure and organization.
  3. Write unit tests for new functionality focusing on behaivor and not implementation.
  4. Document public APIs and complex logic.
  5. Suggest changes to the docs/ folder when appropriate
  6. Follow software principles such as DRY and YAGNI.
  7. Keep diffs as minimal as possible.

Message Content

LLMMessage.content is str | list[dict[str, Any]] | None; the list form is multimodal content parts. Never str() it — that puts a Python repr ([{'type': 'text', 'text': 'hi'}]) in front of the model and into memory. Collapse a message to text with the helper instead:

from crewai.utilities.agent_utils import message_content_text

text = message_content_text(msg)  # "" for None; joined text for a parts list

Parts arrive from a model and are typed dict[str, Any], so a text key that is not a string is possible. _content_parts_text skips those blocks rather than raising, and names a list with no usable text [multimodal content].

Changing Docs

  1. Edit MDX under docs/edge/en/* and reference it from docs/docs.json if needed.
  2. Do not modify files under docs/v*/. Those are frozen release snapshots managed by devtools.
  3. Do not delete or rename files under docs/images/ as frozen snapshots may reference them.
  4. If you want to preview your changes locally, use cd docs && mintlify dev. To check for broken links, run cd docs && mintlify broken-links.
  5. After editing English docs, sync translations to ar, ko, and pt-BR before finishing the task. Follow DOCS_TRANSLATIONS.md.