Skip to content

feat(crew): add stream_frames opt-in for full event frame streaming#6451

Open
C0d3N1nja97342 wants to merge 3 commits into
crewAIInc:mainfrom
C0d3N1nja97342:feat/crew-stream-frames
Open

feat(crew): add stream_frames opt-in for full event frame streaming#6451
C0d3N1nja97342 wants to merge 3 commits into
crewAIInc:mainfrom
C0d3N1nja97342:feat/crew-stream-frames

Conversation

@C0d3N1nja97342

Copy link
Copy Markdown

Problem

Crew.kickoff(stream=True) streams only LLMStreamChunkEvent token chunks — the stream handler (utilities/streaming.py:_create_stream_handler) filters out every other event type. So consumers iterating a streaming crew cannot observe tool calls, agent/task lifecycle, or reasoning steps as they happen, which limits real-time observability for multi-agent runs.

Solution

Add an opt-in Crew.stream_frames flag (default False). When stream=True and stream_frames=True, kickoff / kickoff_async route through the existing frame streaming pipeline (create_frame_streaming_state + create_frame_generator / create_async_frame_generator), which already converts all bus events into StreamFrame objects via stream_frame_from_event. The crew returns a StreamSession / AsyncStreamSession (the same public types already used by BaseLLM.stream_events() and Flow.stream_events()), whose .subscribe(channels=...) lets consumers filter by channel (llm, tools, messages, flow, lifecycle).

This reuses the existing frame infrastructure — no new event emission points and no new output types. The default chunk path (stream=True, stream_frames=False) is unchanged, so the change is fully backward compatible.

Changes

  • lib/crewai/src/crewai/crew.py: new stream_frames Field; kickoff / kickoff_async add an early-return branch to _kickoff_frame_stream / _akickoff_frame_stream when stream_frames is set; return-type union extended with StreamSession / AsyncStreamSession.
  • lib/crewai/tests/test_streaming.py: TestCrewFrameStreaming covering mixed-event streaming (non-LLM tools channel frames pass through), result accessibility after exhaustion, default-False compatibility, and the async path.

Testing

  • New unit tests pass: uv run pytest lib/crewai/tests/test_streaming.py::TestCrewFrameStreaming4 passed (Python 3.12).
  • ruff check and ruff format --check clean on the changed files.
  • A minimal runtime demo verified that LLM token frames and tool-call frames coexist in a single stream.

Notes for Reviewer

  • This is an AI-assisted contribution; per .github/CONTRIBUTING.md, the llm-generated label is requested (applied if permissions allow).
  • Design choice: reused the existing StreamSession / AsyncStreamSession public types rather than introducing a new CrewFrameStreamingOutput, and reused the existing frame pipeline rather than widening the chunk handler — keeps the change additive and backward compatible. kickoff_for_each* is intentionally out of scope for this PR.

When stream=True and stream_frames=True, kickoff/kickoff_async now stream full StreamFrame events (LLM tokens, tool calls, agent/task lifecycle) via the existing frame pipeline, instead of the default StreamChunk token-only stream. Returns a StreamSession / AsyncStreamSession whose .subscribe(channels=...) allows filtering by channel (llm, tools, messages, flow, lifecycle).

Reuses the existing frame infrastructure (create_frame_streaming_state / create_frame_generator / stream_frame_from_event) already used by BaseLLM.stream_events() and Flow.stream_events(); no new event emission points and no new output types. The default chunk path (stream=True, stream_frames=False) is unchanged, so the change is fully backward compatible.
Add TestCrewFrameStreaming covering: mixed-event streaming (asserts non-LLM 'tools' channel frames pass through, which the chunk path drops), result accessibility after exhaustion, default stream_frames=False compatibility, and the async _akickoff_frame_stream path.
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

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: 33e4359e-1d40-45a8-ba5e-12c207a17858

📥 Commits

Reviewing files that changed from the base of the PR and between 1689a92 and 3910252.

📒 Files selected for processing (2)
  • lib/crewai/src/crewai/crew.py
  • lib/crewai/tests/test_streaming.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/crewai/src/crewai/crew.py
  • lib/crewai/tests/test_streaming.py

📝 Walkthrough

Walkthrough

Adds a stream_frames option to Crew, routes kickoff and kickoff_async through frame-based streaming paths, and adds tests covering mixed event frames, result access, and the stream flag contract.

Changes

Frame Streaming Feature

Layer / File(s) Summary
Imports, field, and validator
lib/crewai/src/crewai/crew.py
Adds frame-streaming imports, the stream_frames field, and a validator that enables stream when stream_frames is set.
Kickoff branching
lib/crewai/src/crewai/crew.py
Updates kickoff return annotations and adds sync/async branches that select frame streaming when stream_frames is enabled.
Frame streaming implementation
lib/crewai/src/crewai/crew.py
Implements the sync and async frame-streaming helpers that build frame state, run kickoff with streaming disabled, and return generator-backed sessions.
Frame streaming tests
lib/crewai/tests/test_streaming.py
Adds tests for mixed frame channels, completion/result access, stream_frames flag behavior, and async frame streaming.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Crew
  participant FrameGenerator
  participant StreamSession

  Caller->>Crew: kickoff(stream_frames=True)
  Crew->>Crew: _kickoff_frame_stream()
  Crew->>Crew: create_frame_streaming_state()
  Crew->>Crew: run kickoff() with stream disabled
  Crew->>FrameGenerator: create_frame_generator(state)
  Crew->>StreamSession: wrap generator + captured CrewOutput
  StreamSession-->>Caller: yield frames (llm, tools)
  Caller->>StreamSession: access .result after exhaustion
  StreamSession-->>Caller: CrewOutput
Loading

Suggested reviewers: lucasgomide

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the new opt-in stream_frames support for full event-frame streaming.
Description check ✅ Passed The description directly explains the stream_frames feature, implementation, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

Actionable comments posted: 2

🤖 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/crew.py`:
- Around line 303-312: The stream_frames setting currently implies streaming but
is silently ignored when stream is false, so fix the Crew model to enforce that
contract. Add a model_validator on the Crew class (or equivalent validation near
stream_frames) to either raise when stream_frames=True and stream=False, or
automatically enable stream before kickoff; ensure kickoff() and kickoff_async()
stay consistent with the validated behavior.

In `@lib/crewai/tests/test_streaming.py`:
- Around line 1084-1088: The assertion in test_streaming’s tools-channel check
is only attaching the first string to the assert, leaving the trailing strings
as no-op expressions. Update the assert expression so the full failure message
is part of the same assertion, using the existing channels check in
test_streaming and keeping the message strings grouped together for implicit
concatenation.
🪄 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: c58f516b-0cbc-47fb-aaaf-da1845729769

📥 Commits

Reviewing files that changed from the base of the PR and between 2b90117 and 1689a92.

📒 Files selected for processing (2)
  • lib/crewai/src/crewai/crew.py
  • lib/crewai/tests/test_streaming.py

Comment thread lib/crewai/src/crewai/crew.py
Comment thread lib/crewai/tests/test_streaming.py Outdated
…sage

Address CodeRabbit review: (1) add a model_validator so stream_frames=True auto-enables stream=True instead of being silently ignored when stream=False, and update the field docstring; (2) fix the split assertion in test_frame_stream_yields_mixed_events so the full failure message is part of the assert (the trailing strings were no-op expressions). Add a test covering the stream_frames->stream implication.
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.

1 participant