Skip to content

fix(crewai): unwrap Part before DataPart check so structured inputs are used#2231

Open
anxkhn wants to merge 1 commit into
kagent-dev:mainfrom
anxkhn:fix/crewai-datapart-inputs
Open

fix(crewai): unwrap Part before DataPart check so structured inputs are used#2231
anxkhn wants to merge 1 commit into
kagent-dev:mainfrom
anxkhn:fix/crewai-datapart-inputs

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

What

In the CrewAI A2A executor, the loop that extracts structured inputs from the
incoming request message guarded on isinstance(part, DataPart):

inputs = None
if context.message and context.message.parts:
    for part in context.message.parts:
        if isinstance(part, DataPart):      # never True
            inputs = part.root.data
            break

Each element of Message.parts is an a2a Part, which is a
RootModel[TextPart | FilePart | DataPart], so the actual DataPart lives at
part.root. The isinstance(part, DataPart) check is therefore always False:
the branch never runs, inputs stays None, and a crew invoked with a structured
DataPart silently falls back to the free-text get_user_input() path and ignores
the payload. Note that the very next line already reads part.root.data, which
contradicts the guard one line above it.

Fix

Check isinstance(part.root, DataPart) instead, so the wrapper is unwrapped before
the type test:

if isinstance(part.root, DataPart):
    inputs = part.root.data
    break

This matches how the rest of the codebase handles Part wrappers, for example
converters/event_converter.py (which checks isinstance(a2a_part.root, DataPart)
before reading the data). One-line change; no behavior change for the text-input
path.

Tests

Added packages/kagent-crewai/tests/test_executor.py with two tests that drive
CrewAIAgentExecutor.execute end to end with a mocked crew:

  • test_execute_passes_datapart_data_as_inputs: sends a DataPart and asserts the
    crew is kicked off with inputs={"topic": "ai"}. This test fails on main
    (the crew is kicked off with inputs={}) and passes with the fix.
  • test_execute_falls_back_to_text_input_without_datapart: sends a TextPart and
    asserts the existing text-fallback path still yields inputs={"input": "hello"}.

Also added packages/kagent-crewai/tests/conftest.py to set KAGENT_URL,
KAGENT_NAME, and KAGENT_NAMESPACE before import, because KAgentConfig() is
evaluated at import time (as a default argument in _a2a.py) and requires them, so
test collection would otherwise fail.

Verification

cd python
uv run pytest packages/kagent-crewai/tests/ -v      # 2 passed
uv run ruff check packages/kagent-crewai/...          # All checks passed
uv run ruff format --check packages/kagent-crewai/... # already formatted

The change is Python agent-runtime only and is fully covered by unit tests; it does
not touch controllers, CRDs, or require a cluster, so no E2E test is added (per the
CONTRIBUTING note that minor behavior changes can be excepted from E2E).

…re used

In the CrewAI A2A executor, the loop that pulls structured inputs from the
request message guarded on `isinstance(part, DataPart)`. Each element of
`Message.parts` is an a2a `Part`, which is a `RootModel[TextPart | FilePart |
DataPart]`, so the actual `DataPart` lives at `part.root`. The check was
therefore always False, the branch never ran, and `inputs` stayed None: a crew
invoked with a structured `DataPart` silently fell back to the free-text
`get_user_input()` path and ignored the payload. The very next line already
read `part.root.data`, contradicting the guard.

Check `isinstance(part.root, DataPart)` instead, matching how every other call
site in the codebase (e.g. converters/part_converter.py and event_converter.py)
unwraps the part. Add regression tests covering both the DataPart and the
text-fallback paths.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
@anxkhn anxkhn requested a review from a team as a code owner July 13, 2026 23:17
Copilot AI review requested due to automatic review settings July 13, 2026 23:17
@github-actions github-actions Bot added the bug Something isn't working label Jul 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes structured-input extraction in the CrewAI A2A executor by unwrapping Part wrappers before checking for DataPart, ensuring DataPart.data payloads are actually passed through to crew.kickoff_async(...) instead of silently falling back to free-text input.

Changes:

  • Update CrewAIAgentExecutor.execute to check isinstance(part.root, DataPart) when scanning incoming Message.parts.
  • Add end-to-end unit tests covering both DataPart (structured) and TextPart (fallback) input paths.
  • Add a test conftest.py to set required KAGENT_* env vars early to avoid import-time config failures during test collection.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
python/packages/kagent-crewai/src/kagent/crewai/_executor.py Fixes DataPart detection by checking part.root so structured inputs are used.
python/packages/kagent-crewai/tests/test_executor.py Adds async tests validating DataPart inputs are passed through and TextPart still falls back correctly.
python/packages/kagent-crewai/tests/conftest.py Sets required KAGENT_* env vars before imports to prevent test collection failures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +25 to +32
async def _run(crew: MagicMock, context: RequestContext) -> None:
executor = CrewAIAgentExecutor(
crew=crew,
app_name="test",
http_client=httpx.AsyncClient(),
)
await executor.execute(context, EventQueue())

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants