Skip to content

fix(tools): resolve a coworker that a model spelled as a quoted list - #7615

Open
Lesereingrape wants to merge 4 commits into
crewAIInc:mainfrom
Lesereingrape:fix/coworker-python-repr-quotes
Open

Lesereingrape wants to merge 4 commits into
crewAIInc:mainfrom
Lesereingrape:fix/coworker-python-repr-quotes

Conversation

@Lesereingrape

@Lesereingrape Lesereingrape commented Sep 19, 2026 •

Copy link
Copy Markdown

Related issue

Fixes #7614

Summary

_get_coworker() already knows that a weak model may hand over a list where a string was expected, and unwraps [...] to its first entry — but it leaves that entry's quotes in place, and role matching (sanitize_agent_name(), same file) strips " only. So the JSON spelling ["researcher"] delegates fine while the Python-repr spelling ['researcher'] — what str(list) produces — comes back as "coworker mentioned not found" while listing that very role as available:

coworker='["Senior Researcher"]'             -> delegates
coworker="['Senior Researcher']"             -> "coworker mentioned not found… - senior researcher"
coworker="['Senior Researcher', 'Analyst']"  -> same
coworker="'Senior Researcher'"               -> same

The unwrap now strips the wrapping quotes (and surrounding whitespace) once, after it, which covers the list form and the quoted-scalar form together for both DelegateWorkTool and AskQuestionTool, since they share this method.

Deliberately not done: teaching sanitize_agent_name() to drop ' too. Its own docstring ("quotes removed") invites that reading, but the function is applied to the agents' real role names as well as to the model's argument, so a role containing an apostrophe would stop matching. _get_coworker() only ever sees the incoming argument.

Behavior is unchanged for every spelling that works today: .strip() and .strip("'\"") are no-ops on a bare name, on [researcher], and on ["researcher"] (the double quotes were already removed later, and the two paths now agree).

Verification

  • Tests added or updated for the changed behavior

  • Relevant tests and quality checks pass locally

  • New test_delegate_work_resolves_coworker_spellings, parametrized over the five spellings, with Agent.execute_task stubbed so no LLM or cassette is involved. On 3831e8b: 2 failed, 3 passed — the two single-quote spellings fail, and the three controls (researcher, [researcher], ["researcher"]) pass both before and after, which is the no-regression evidence. On this branch: 5 passed.

  • uv run pytest lib/crewai/tests/tools/agent_tools/test_agent_tools.py -q → 13 passed (the 8 pre-existing VCR-replay tests included).

  • Blast radius: lib/crewai/tests/tools + lib/crewai/tests/agents run on the base and on this branch, fail-sets diffed → exactly the 2 new cases flip, 0 regressions. 32 failures remain identical on both sides in this environment (crewai_files is not installed here, plus the platform/a2a suites that need it); CI installs the full workspace.

  • uv run ruff check / ruff format --check → clean on the changed source. uv run mypy → no error in base_agent_tools.py (the 10 reported errors are the pre-existing no-any-unimported findings in crew_docling_source.py).

Additional context

The comment above the matching code spells out why the tolerance exists — "less-powerful LLM's have difficulty producing valid JSON" — so a single-quoted argument is squarely inside the case this branch was written for, and it is the half that was missed. The user-visible symptom is the loop where the tool refuses a role and then prints it as an allowed option, which a model usually retries by passing the bare name; so it costs a wasted tool call rather than breaking the crew outright.

Follow-up this PR does not attempt: coworker[1:-1].split(",")[0] silently drops every entry after the first, so ['Researcher', 'Analyst'] never considers Analyst. Splitting a quoted name on , is also wrong for a role that contains a comma. Both are about which coworker a multi-entry list should pick, i.e. a design call rather than a missed guard, so they belong in their own issue if maintainers want them addressed.

Authored with an AI coding assistant. .github/CONTRIBUTING.md requires the llm-generated label for agent-authored contributions and external contributors cannot apply it here — maintainers, please add it.


Note

Low Risk
Small input-normalization change in shared coworker parsing for delegate/ask tools; existing spellings stay no-ops and behavior is covered by new tests.

Overview
Fixes coworker resolution when models pass Python-style quoted list strings (e.g. ['researcher']) to agent delegation tools.

After _get_coworker() unwraps bracketed list forms, it now strips surrounding whitespace and wrapping '/" on the chosen entry. That aligns single-quoted spellings with JSON-style ["researcher"] before role matching, without changing sanitize_agent_name() (which would break roles with apostrophes).

Adds a parametrized test so DelegateWorkTool resolves bare names, bracket forms, and both quote styles to the same agent.

Reviewed by Cursor Bugbot for commit 118a37f. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 3250bf6d-f30b-436b-9565-4d6cb6681409

📥 Commits

Reviewing files that changed from the base of the PR and between e84ec8c and 118a37f.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: fe6108ff-f52e-4082-9f56-7242bbafde47

📥 Commits

Reviewing files that changed from the base of the PR and between 93269c6 and e84ec8c.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The change normalizes coworker values by removing surrounding whitespace and single or double quotes. A parameterized test verifies delegation for direct, list-style, JSON-style, and Python-repr spellings.

Changes

Coworker resolution

Layer / File(s) Summary
Normalize coworker values and validate delegation
lib/crewai/src/crewai/tools/agent_tools/base_agent_tools.py, lib/crewai/tests/tools/agent_tools/test_agent_tools.py
_get_coworker strips whitespace and wrapping single or double quotes after list extraction. The parameterized test verifies five coworker spellings resolve to the researcher agent and return "answered".

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to e84ec

The supported coworker spellings resolve through the shared normalization path, with no concrete behavior regression identified. The change is ready to merge after normal checks.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The change in BaseAgentTool._get_coworker() strips whitespace and single or double wrapping quotes after list extraction. This implements the required normalization for both shared tools in issue #7… Add a parametrized test case for a quoted scalar coworker value, such as "'researcher'", and verify that it resolves to the intended agent.
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: resolving coworker values provided as quoted lists.
Description check ✅ Passed The description includes the related issue, a detailed summary, verification results, regression information, and additional context. It documents the changed behavior and test coverage clearly.
Out of Scope Changes check ✅ Passed The production change updates the shared coworker normalization, and the added test verifies delegation spellings required by issue #7614. No unrelated production behavior or unrelated file change is …
Full details: Linked Issues check

Explanation

The change in BaseAgentTool._get_coworker() strips whitespace and single or double wrapping quotes after list extraction. This implements the required normalization for both shared tools in issue #7614. The regression test covers bare, bracketed, JSON-list, Python-repr list, and multi-item Python-repr list values, but it does not cover the required quoted scalar form such as 'researcher'.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

@Lesereingrape

Copy link
Copy Markdown
Author

Heads-up for maintainers so this does not get reviewed twice: #7620 (opened a few hours after this one, same issue #7614) fixes the same defect in sanitize_agent_name so both quote styles are stripped on both sides of the comparison, while this commit strips wrapping quotes at the extraction point in _get_coworker.

They are equivalent for every spelling in the issue. The strip here sits in the if coworker: branch, not inside if is_list:, so a plain quoted scalar (coworker="'Senior Researcher'") resolves too, and .strip("'\"") only removes wrapping quotes, so a role whose own name contains an apostrophe is unaffected.

Either one closes #7614 — merging one and closing the other is fine by me. If the sanitizer route is preferred, the parametrized spelling table in this PR's test (researcher, [researcher], ["researcher"], ['researcher'], ['researcher', 'writer']) is copy-pasteable into #7620 as extra coverage.

@Lesereingrape

Copy link
Copy Markdown
Author

Two contributor-side items I cannot close myself — both need a maintainer with write access.

1. CI has not been allowed to run on this PR. On the current head, seven workflow runs are
parked in the action_required state (Run Tests, Lint, Type Checks, CodeQL, Vuln Scan,
plus the PR title/size jobs) — that is how this repo gates pull requests opened from a fork, and it
is why the only check visible here is require-issue. Nothing is failing; the required checks have
simply not been permitted to start. Could someone approve the pending runs?

In the meantime, the equivalent evidence I can produce locally: the exact pytest and ruff commands
with their output are recorded in the PR body above, run in this repo's locked venv. One caveat so
nothing is oversold: in my venv the knowledge tests also show test_docling_source and
test_multiple_docling_sources failing, and those two reproduce identically on a clean main
checkout — they need the optional docling extra, which is not installed here, so they are
unrelated to this diff.

2. The llm-generated label. .github/CONTRIBUTING.md:5-7 requires it on any PR authored by an
AI agent, and this PR is one — the body already says so. As the author of a fork PR I have no
permission to add labels to this repository (the API returns 403 for me), so this is the one
requirement of that policy I cannot satisfy myself.

Three sibling PRs from the same account were prepared the same way and need both items: #7610, #7612,
#7615, #7617. Each links its own open issue (#7609, #7611, #7614, #7616), each carries RED -> GREEN
measurements in its body, and each touches only one function plus its test file.

One deliberate non-request: I have not pushed a merge of main into this branch. The change is small
and self-contained, and since merges here are squashes a refreshed branch would only replace the
pending runs with a new set that still needs approving.

@Lesereingrape
Lesereingrape force-pushed the fix/coworker-python-repr-quotes branch from 1c44fca to 89b0a57 Compare September 24, 2026 11:31

This branch has not been deployed

No deployments
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.

Delegating to a coworker fails when the model emits a Python-repr list: coworker="['researcher']"

1 participant