Compare commits

..

4 Commits

Author SHA1 Message Date
Vinicius Brasil
e1ddb32e56 Initialize Git repositories for generated projects (#6364)
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Check Documentation Broken Links / Check broken links (push) Waiting to run
Vulnerability Scan / pip-audit (push) Waiting to run
2026-06-26 16:29:49 -07:00
Ossama Alami
05ab1ece8e docs(readme): improve open source positioning (#6363) 2026-06-26 16:06:16 -07:00
Lorenze Jay
e716f3de8b docs: snapshot and changelog for v1.15.1a1 (#6362) 2026-06-26 15:16:43 -07:00
Lorenze Jay
1e2c965a75 feat: bump versions to 1.15.1a1 (#6361) 2026-06-26 15:12:37 -07:00
24 changed files with 218 additions and 247 deletions

View File

@@ -12,6 +12,8 @@
<p align="center">
<a href="https://crewai.com">Homepage</a>
·
<a href="https://crewai.com/open-source">Open Source</a>
·
<a href="https://docs.crewai.com">Docs</a>
·
<a href="https://app.crewai.com">Start Cloud Trial</a>
@@ -53,20 +55,20 @@
### Fast and Flexible Multi-Agent Automation Framework
> CrewAI is a lean, lightning-fast Python framework built entirely from scratch—completely **independent of LangChain or other agent frameworks**.
> It empowers developers with both high-level simplicity and precise low-level control, ideal for creating autonomous AI agents tailored to any scenario.
> CrewAI is an open-source Python framework with high-level abstractions and low-level APIs for building production-ready multi-agent workflows.
> It gives developers autonomous agent collaboration through Crews and precise, event-driven control through Flows.
- **CrewAI Crews**: Optimize for autonomy and collaborative intelligence.
- **CrewAI Flows**: The **enterprise and production architecture** for building and deploying multi-agent systems. Enable granular, event-driven control, single LLM calls for precise task orchestration and supports Crews natively
- **CrewAI Crews**: Optimize for autonomy and collaborative intelligence with role-based AI agents.
- **CrewAI Flows**: Build event-driven automations that combine precise workflow control, single LLM calls, and native support for Crews.
With over 100,000 developers certified through our community courses at [learn.crewai.com](https://learn.crewai.com), CrewAI is rapidly becoming the
standard for enterprise-ready AI automation.
standard for production-ready agentic automation.
# CrewAI AMP Suite
CrewAI AMP Suite is a comprehensive bundle tailored for organizations that require secure, scalable, and easy-to-manage agent-driven automation.
For organizations that need a commercial control plane around CrewAI, [CrewAI AMP Suite](https://www.crewai.com/enterprise) adds managed deployment, observability, governance, security, and enterprise support.
You can try one part of the suite the [Crew Control Plane for free](https://app.crewai.com)
You can try one part of the suite, the [Crew Control Plane, for free](https://app.crewai.com).
## Crew Control Plane Key Features:
@@ -88,7 +90,6 @@ intelligent automations.
- [Getting Started](#getting-started)
- [Key Features](#key-features)
- [Understanding Flows and Crews](#understanding-flows-and-crews)
- [CrewAI vs LangGraph](#how-crewai-compares)
- [Examples](#examples)
- [Quick Tutorial](#quick-tutorial)
- [Write Job Descriptions](#write-job-descriptions)
@@ -96,11 +97,11 @@ intelligent automations.
- [Stock Analysis](#stock-analysis)
- [Using Crews and Flows Together](#using-crews-and-flows-together)
- [Connecting Your Crew to a Model](#connecting-your-crew-to-a-model)
- [How CrewAI Compares](#how-crewai-compares)
- [Frequently Asked Questions (FAQ)](#frequently-asked-questions-faq)
- [When to Use CrewAI](#when-to-use-crewai)
- [Contribution](#contribution)
- [Telemetry](#telemetry)
- [License](#license)
- [Frequently Asked Questions (FAQ)](#frequently-asked-questions-faq)
## Build with AI
@@ -134,15 +135,15 @@ This installs the official [CrewAI Skills](https://github.com/crewAIInc/skills)
<img src="docs/images/asset.png" alt="CrewAI Logo" width="100%">
</div>
CrewAI unlocks the true potential of multi-agent automation, delivering the best-in-class combination of speed, flexibility, and control with either Crews of AI Agents or Flows of Events:
CrewAI unlocks the true potential of multi-agent automation, delivering speed, flexibility, and control through Crews of AI agents and event-driven Flows:
- **Standalone Framework**: Built from scratch, independent of LangChain or any other agent framework.
- **Purpose-built architecture**: Designed specifically for agent orchestration, with a lightweight Python core and clean primitives for real-world automation.
- **High Performance**: Optimized for speed and minimal resource usage, enabling faster execution.
- **Flexible Low Level Customization**: Complete freedom to customize at both high and low levels - from overall workflows and system architecture to granular agent behaviors, internal prompts, and execution logic.
- **Ideal for Every Use Case**: Proven effective for both simple tasks and highly complex, real-world, enterprise-grade scenarios.
- **Flexible Low-Level Customization**: Complete freedom to customize everything from workflows and system architecture to agent behaviors, internal prompts, and execution logic.
- **Ideal for Every Use Case**: Proven effective for simple tasks, complex workflows, and production-grade automation.
- **Robust Community**: Backed by a rapidly growing community of over **100,000 certified** developers offering comprehensive support and resources.
CrewAI empowers developers and enterprises to confidently build intelligent automations, bridging the gap between simplicity, flexibility, and performance.
CrewAI empowers developers and teams to build intelligent automations that balance simplicity, flexibility, and production-grade control.
## Getting Started
@@ -433,16 +434,17 @@ In addition to the sequential process, you can use the hierarchical process, whi
## Key Features
CrewAI stands apart as a lean, standalone, high-performance multi-AI Agent framework delivering simplicity, flexibility, and precise control—free from the complexity and limitations found in other agent frameworks.
CrewAI gives developers a practical foundation for building agentic systems that move from prototype to production: autonomous collaboration where it helps, explicit workflow control where it matters, and Python-native customization throughout.
- **Standalone & Lean**: Completely independent from other frameworks like LangChain, offering faster execution and lighter resource demands.
- **Flexible & Precise**: Easily orchestrate autonomous agents through intuitive [Crews](https://docs.crewai.com/concepts/crews) or precise [Flows](https://docs.crewai.com/concepts/flows), achieving perfect balance for your needs.
- **Seamless Integration**: Effortlessly combine Crews (autonomy) and Flows (precision) to create complex, real-world automations.
- **Deep Customization**: Tailor every aspect—from high-level workflows down to low-level internal prompts and agent behaviors.
- **Reliable Performance**: Consistent results across simple tasks and complex, enterprise-level automations.
- **Thriving Community**: Backed by robust documentation and over 100,000 certified developers, providing exceptional support and guidance.
- **Crews for autonomy**: Model teams of specialized AI agents with roles, goals, tools, and tasks.
- **Flows for control**: Build event-driven workflows with state, branching, routing, and production logic.
- **Seamless integration**: Combine Crews and Flows to create complex, real-world automations.
- **Python-native customization**: Customize prompts, tools, execution paths, state, and integrations without fighting the framework.
- **Agent-ready capabilities**: Use tools, memory, knowledge, checkpointing, async execution, and MCP/A2A support for more capable production agents.
- **Production-ready patterns**: Add deterministic steps, human input, structured outputs, and checkpointing as your system grows.
- **Thriving community**: Backed by robust documentation and over 100,000 certified developers, providing exceptional support and guidance.
Choose CrewAI to easily build powerful, adaptable, and production-ready AI automations.
Choose CrewAI to build powerful, adaptable, and production-ready AI automations.
## Examples
@@ -580,16 +582,17 @@ CrewAI supports using various LLMs through a variety of connection options. By d
Please refer to the [Connect CrewAI to LLMs](https://docs.crewai.com/how-to/LLM-Connections/) page for details on configuring your agents' connections to models.
## How CrewAI Compares
## When to Use CrewAI
**CrewAI's Advantage**: CrewAI combines autonomous agent intelligence with precise workflow control through its unique Crews and Flows architecture. The framework excels at both high-level orchestration and low-level customization, enabling complex, production-grade systems with granular control.
Use CrewAI when you need more than a single prompt or chatbot: multi-step work, specialized agents, tool use, structured outputs, human review, or workflows that combine autonomous reasoning with explicit business logic.
- **LangGraph**: While LangGraph provides a foundation for building agent workflows, its approach requires significant boilerplate code and complex state management patterns. The framework's tight coupling with LangChain can limit flexibility when implementing custom agent behaviors or integrating with external systems.
CrewAI is especially useful when you want to:
_P.S. CrewAI demonstrates significant performance advantages over LangGraph, executing 5.76x faster in certain cases like this QA task example ([see comparison](https://github.com/crewAIInc/crewAI-examples/tree/main/Notebooks/CrewAI%20Flows%20%26%20Langgraph/QA%20Agent)) while achieving higher evaluation scores with faster completion times in certain coding tasks, like in this example ([detailed analysis](https://github.com/crewAIInc/crewAI-examples/blob/main/Notebooks/CrewAI%20Flows%20%26%20Langgraph/Coding%20Assistant/coding_assistant_eval.ipynb))._
- **Autogen**: While Autogen excels at creating conversational agents capable of working together, it lacks an inherent concept of process. In Autogen, orchestrating agents' interactions requires additional programming, which can become complex and cumbersome as the scale of tasks grows.
- **ChatDev**: ChatDev introduced the idea of processes into the realm of AI agents, but its implementation is quite rigid. Customizations in ChatDev are limited and not geared towards production environments, which can hinder scalability and flexibility in real-world applications.
- Coordinate multiple agents with clear roles and tasks.
- Wrap agent work in deterministic, event-driven workflows.
- Keep application logic in regular Python.
- Move from experiment to production without changing frameworks.
- Add tools, memory, checkpointing, and async execution as your system grows.
## Contribution
@@ -698,7 +701,7 @@ CrewAI is released under the [MIT License](https://github.com/crewAIInc/crewAI/b
- [What exactly is CrewAI?](#q-what-exactly-is-crewai)
- [How do I install CrewAI?](#q-how-do-i-install-crewai)
- [Does CrewAI depend on LangChain?](#q-does-crewai-depend-on-langchain)
- [Is CrewAI a standalone framework?](#q-is-crewai-a-standalone-framework)
- [Is CrewAI open-source?](#q-is-crewai-open-source)
- [Does CrewAI collect data from users?](#q-does-crewai-collect-data-from-users)
@@ -707,7 +710,6 @@ CrewAI is released under the [MIT License](https://github.com/crewAIInc/crewAI/b
- [Can CrewAI handle complex use cases?](#q-can-crewai-handle-complex-use-cases)
- [Can I use CrewAI with local AI models?](#q-can-i-use-crewai-with-local-ai-models)
- [What makes Crews different from Flows?](#q-what-makes-crews-different-from-flows)
- [How is CrewAI better than LangChain?](#q-how-is-crewai-better-than-langchain)
- [Does CrewAI support fine-tuning or training custom models?](#q-does-crewai-support-fine-tuning-or-training-custom-models)
### Resources and Community
@@ -723,7 +725,7 @@ CrewAI is released under the [MIT License](https://github.com/crewAIInc/crewAI/b
### Q: What exactly is CrewAI?
A: CrewAI is a standalone, lean, and fast Python framework built specifically for orchestrating autonomous AI agents. Unlike frameworks like LangChain, CrewAI does not rely on external dependencies, making it leaner, faster, and simpler.
A: CrewAI is a lean, fast Python framework built specifically for orchestrating autonomous AI agents and production-ready agentic workflows.
### Q: How do I install CrewAI?
@@ -739,9 +741,9 @@ For additional tools, use:
uv pip install 'crewai[tools]'
```
### Q: Does CrewAI depend on LangChain?
### Q: Is CrewAI a standalone framework?
A: No. CrewAI is built entirely from the ground up, with no dependencies on LangChain or other agent frameworks. This ensures a lean, fast, and flexible experience.
A: Yes. CrewAI is a standalone Python framework with its own primitives for agents, tasks, crews, flows, tools, and orchestration.
### Q: Can CrewAI handle complex use cases?
@@ -755,10 +757,6 @@ A: Absolutely! CrewAI supports various language models, including local ones. To
A: Crews provide autonomous agent collaboration, ideal for tasks requiring flexible decision-making and dynamic interaction. Flows offer precise, event-driven control, ideal for managing detailed execution paths and secure state management. You can seamlessly combine both for maximum effectiveness.
### Q: How is CrewAI better than LangChain?
A: CrewAI provides simpler, more intuitive APIs, faster execution speeds, more reliable and consistent results, robust documentation, and an active community—addressing common criticisms and limitations associated with LangChain.
### Q: Is CrewAI open-source?
A: Yes, CrewAI is open-source and actively encourages community contributions and collaboration.
@@ -797,11 +795,11 @@ A: Absolutely! CrewAI agents can easily integrate with external tools, APIs, and
### Q: Is CrewAI suitable for production environments?
A: Yes, CrewAI is explicitly designed with production-grade standards, ensuring reliability, stability, and scalability for enterprise deployments.
A: Yes, CrewAI is designed with production-grade patterns that support reliable, stable, and scalable agentic workflows.
### Q: How scalable is CrewAI?
A: CrewAI is highly scalable, supporting simple automations and large-scale enterprise workflows involving numerous agents and complex tasks simultaneously.
A: CrewAI is highly scalable, supporting simple automations and large-scale workflows involving numerous agents and complex tasks simultaneously.
### Q: Does CrewAI offer debugging and monitoring tools?

View File

@@ -4,6 +4,33 @@ description: "تحديثات المنتج والتحسينات وإصلاحات
icon: "clock"
mode: "wide"
---
<Update label="26 يونيو 2026">
## v1.15.1a1
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1a1)
## ما الذي تغير
### الميزات
- تتبع بيانات الزر TUI
- يتطلب تعريفات مشروع CrewAI بشكل صريح
- فتح صفحة النشر بعد نشر CLI
### إصلاحات الأخطاء
- إصلاح عرض قالب الطاقم بصيغة JSON
- إصلاح تثبيت إصدار الطاقم بصيغة JSON
- إصلاح تجاوز إعادة التوجيه SSRF في عمليات جلب البيانات
### الوثائق
- تحسين دعوة إعداد وكيل البرمجة
- لقطة وتغيير السجل للإصدار v1.15.0
## المساهمون
@joaomdmoura, @lorenzejay, @theCyberTech, @vinibrsl
</Update>
<Update label="25 يونيو 2026">
## v1.15.0

View File

@@ -4,6 +4,33 @@ description: "Product updates, improvements, and bug fixes for CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="Jun 26, 2026">
## v1.15.1a1
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1a1)
## What's Changed
### Features
- Track TUI button telemetry
- Require explicit CrewAI project definitions
- Open deployment page after CLI deploy
### Bug Fixes
- Fix JSON crew template rendering
- Fix JSON crew version pin
- Fix SSRF redirect bypass in scraping fetches
### Documentation
- Improve coding agent setup CTA
- Snapshot and changelog for v1.15.0
## Contributors
@joaomdmoura, @lorenzejay, @theCyberTech, @vinibrsl
</Update>
<Update label="Jun 25, 2026">
## v1.15.0

View File

@@ -4,6 +4,33 @@ description: "CrewAI의 제품 업데이트, 개선 사항 및 버그 수정"
icon: "clock"
mode: "wide"
---
<Update label="2026년 6월 26일">
## v1.15.1a1
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1a1)
## 변경 사항
### 기능
- TUI 버튼 텔레메트리 추적
- 명시적인 CrewAI 프로젝트 정의 필요
- CLI 배포 후 배포 페이지 열기
### 버그 수정
- JSON 크루 템플릿 렌더링 수정
- JSON 크루 버전 고정 수정
- 스크래핑 페치에서 SSRF 리다이렉트 우회 수정
### 문서
- 코딩 에이전트 설정 CTA 개선
- v1.15.0에 대한 스냅샷 및 변경 로그
## 기여자
@joaomdmoura, @lorenzejay, @theCyberTech, @vinibrsl
</Update>
<Update label="2026년 6월 25일">
## v1.15.0

View File

@@ -4,6 +4,33 @@ description: "Atualizações de produto, melhorias e correções do CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="26 jun 2026">
## v1.15.1a1
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1a1)
## O que Mudou
### Funcionalidades
- Rastrear a telemetria dos botões TUI
- Exigir definições explícitas de projetos CrewAI
- Abrir a página de implantação após o deploy via CLI
### Correções de Bugs
- Corrigir a renderização do template de equipe em JSON
- Corrigir o pin de versão da equipe em JSON
- Corrigir a bypass de redirecionamento SSRF em fetches de scraping
### Documentação
- Melhorar o CTA de configuração do agente de codificação
- Snapshot e changelog para v1.15.0
## Contribuidores
@joaomdmoura, @lorenzejay, @theCyberTech, @vinibrsl
</Update>
<Update label="25 jun 2026">
## v1.15.0

View File

@@ -8,7 +8,7 @@ authors = [
]
requires-python = ">=3.10, <3.14"
dependencies = [
"crewai-core==1.15.0",
"crewai-core==1.15.1a1",
"click>=8.1.7,<9",
"pydantic>=2.11.9,<2.13",
"pydantic-settings~=2.10.1",

View File

@@ -1 +1 @@
__version__ = "1.15.0"
__version__ = "1.15.1a1"

View File

@@ -6,6 +6,7 @@ import click
import tomli
from crewai_cli.constants import ENV_VARS, MODELS
from crewai_cli.git import initialize_if_git_available
from crewai_cli.provider import (
get_provider_data,
select_model,
@@ -318,4 +319,7 @@ def create_crew(
dst_file = src_folder / file_name
copy_template(src_file, dst_file, name, class_name, folder_name)
if not parent_folder:
initialize_if_git_available(folder_path)
click.secho(f"Crew {name} created successfully!", fg="green", bold=True)

View File

@@ -4,6 +4,7 @@ import shutil
import click
from crewai_core.telemetry import Telemetry
from crewai_cli.git import initialize_if_git_available
from crewai_cli.version import get_crewai_tools_dependency
@@ -30,6 +31,8 @@ def create_flow(name: str, *, declarative: bool = False) -> None:
else:
_create_python_flow(name, class_name, folder_name, project_root)
initialize_if_git_available(project_root)
click.secho(f"Flow {name} created successfully!", fg="green", bold=True)

View File

@@ -13,6 +13,7 @@ from rich.console import Console
from rich.text import Text
from crewai_cli.constants import ENV_VARS
from crewai_cli.git import initialize_if_git_available
from crewai_cli.tui_picker import pick_many, pick_one
from crewai_cli.utils import (
enable_prompt_line_editing,
@@ -955,6 +956,8 @@ def create_json_crew(
for model in models:
_setup_env(folder_path, model)
initialize_if_git_available(folder_path)
click.echo()
click.secho(f" ✔ Crew {name} created successfully!", fg="green", bold=True)
click.echo()

View File

@@ -4,7 +4,6 @@ Two-column layout: left sidebar (tasks/agents/tokens) + main content
(task header, plan checklist, activity timeline, streaming output).
"""
from collections.abc import Iterable
import json as _json
import re
import threading
@@ -47,19 +46,6 @@ def _is_save_to_memory_tool(tool_name: str | None) -> bool:
return (tool_name or "").replace(" ", "_").lower() == "save_to_memory"
def _is_streaming_output(value: Any) -> bool:
if not isinstance(value, Iterable):
return False
value_type = type(value)
try:
value_type.get_full_text # noqa: B018
value_type.result # noqa: B018
except AttributeError:
return False
return True
def _truncate_log_text(value: Any, limit: int) -> str | None:
if value is None:
return None
@@ -850,18 +836,14 @@ FooterKey .footer-key--key {
set_suppress_tracing_messages(True)
try:
result = self._flow.handle_turn(message)
result = self._consume_conversation_streaming_result(result)
if hasattr(result, "get_full_text") and hasattr(result, "result"):
for _chunk in result:
pass
result = result.result
self.call_from_thread(self._on_conversation_turn_done, result)
except Exception as e:
self.call_from_thread(self._on_conversation_turn_failed, str(e))
def _consume_conversation_streaming_result(self, result: Any) -> Any:
if not _is_streaming_output(result):
return result
for _chunk in result:
pass
return result.result
def _on_conversation_turn_done(self, result: Any) -> None:
with self._lock:
output = self._stringify_output(result)

View File

@@ -201,3 +201,12 @@ class Repository:
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
def initialize_if_git_available(path: Path) -> bool:
"""Initialize a Git repository when Git is available."""
if not Repository.is_git_installed():
return False
subprocess.run(["git", "init"], cwd=path, check=True) # noqa: S607
return True

View File

@@ -11,6 +11,7 @@ from packaging.requirements import Requirement
from packaging.version import Version
import crewai_cli.create_json_crew as json_crew
import crewai_cli.tui_picker as tui_picker
from crewai_cli.cli import crewai
from crewai_cli.create_crew import create_crew, create_folder_structure
from crewai_cli.utils import render_template
from crewai_cli.version import get_crewai_tools_dependency
@@ -109,6 +110,7 @@ def test_create_crew_with_trailing_slash_creates_valid_project(
"crewai_cli.create_crew.create_folder_structure"
) as mock_create_folder:
mock_folder_path = Path(work_dir) / "test_project"
mock_folder_path.mkdir()
mock_create_folder.return_value = (
mock_folder_path,
"test_project",
@@ -143,6 +145,7 @@ def test_create_crew_with_multiple_trailing_slashes(
"crewai_cli.create_crew.create_folder_structure"
) as mock_create_folder:
mock_folder_path = Path(work_dir) / "test_project"
mock_folder_path.mkdir()
mock_create_folder.return_value = (
mock_folder_path,
"test_project",
@@ -167,6 +170,7 @@ def test_create_crew_normal_name_still_works(
"crewai_cli.create_crew.create_folder_structure"
) as mock_create_folder:
mock_folder_path = Path(work_dir) / "normal_project"
mock_folder_path.mkdir()
mock_create_folder.return_value = (
mock_folder_path,
"normal_project",
@@ -178,6 +182,26 @@ def test_create_crew_normal_name_still_works(
mock_create_folder.assert_called_once_with("normal-project", None)
@pytest.mark.skipif(shutil.which("git") is None, reason="git is not installed")
@pytest.mark.parametrize(
("args", "project_root"),
[
(["create", "crew", "Git Crew"], "git_crew"),
(["create", "flow", "Git Flow"], "git_flow"),
],
)
def test_create_initializes_git_repo_when_git_is_available(
args, project_root, tmp_path, monkeypatch, runner
):
monkeypatch.chdir(tmp_path)
monkeypatch.setenv("CREWAI_DMN", "True")
result = runner.invoke(crewai, args)
assert result.exit_code == 0, result.output
assert (tmp_path / project_root / ".git").is_dir()
def test_create_folder_structure_handles_spaces_and_dashes_with_slash():
with tempfile.TemporaryDirectory() as temp_dir:
folder_path, folder_name, class_name = create_folder_structure(

View File

@@ -26,7 +26,6 @@ from crewai.events.types.tool_usage_events import (
ToolUsageFinishedEvent,
ToolUsageStartedEvent,
)
from crewai.types.streaming import FlowStreamingOutput, StreamChunk
from crewai_cli.command import AuthenticationRequiredError
from crewai_cli import run_crew
from crewai_cli.crew_run_tui import (
@@ -178,29 +177,6 @@ def test_conversation_turn_done_records_assistant_message() -> None:
assert isinstance(app._crew_result, RawResult)
def test_conversation_streaming_result_is_consumed_before_result_access() -> None:
streaming = FlowStreamingOutput()
result_accessed_before_completion = False
def chunks():
yield StreamChunk(content="hello ")
yield StreamChunk(content="world")
streaming._set_result("hello world")
streaming._sync_iterator = chunks()
try:
streaming.result
except RuntimeError:
result_accessed_before_completion = True
app = CrewRunApp(conversational=True)
assert result_accessed_before_completion is True
assert app._consume_conversation_streaming_result(streaming) == "hello world"
assert streaming.get_full_text() == "hello world"
@pytest.mark.asyncio
async def test_conversation_input_submits_turn() -> None:
class FakeFlow:

View File

@@ -1 +1 @@
__version__ = "1.15.0"
__version__ = "1.15.1a1"

View File

@@ -152,4 +152,4 @@ __all__ = [
"wrap_file_source",
]
__version__ = "1.15.0"
__version__ = "1.15.1a1"

View File

@@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14"
dependencies = [
"pytube~=15.0.0",
"requests>=2.33.0,<3",
"crewai==1.15.0",
"crewai==1.15.1a1",
"tiktoken>=0.8.0,<0.13",
"beautifulsoup4~=4.13.4",
"python-docx~=1.2.0",

View File

@@ -330,4 +330,4 @@ __all__ = [
"ZapierActionTools",
]
__version__ = "1.15.0"
__version__ = "1.15.1a1"

View File

@@ -8,8 +8,8 @@ authors = [
]
requires-python = ">=3.10, <3.14"
dependencies = [
"crewai-core==1.15.0",
"crewai-cli==1.15.0",
"crewai-core==1.15.1a1",
"crewai-cli==1.15.1a1",
# Core Dependencies
"pydantic>=2.11.9,<2.13",
"openai>=2.30.0,<3",
@@ -55,7 +55,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = [
"crewai-tools==1.15.0",
"crewai-tools==1.15.1a1",
]
embeddings = [
"tiktoken>=0.8.0,<0.13"

View File

@@ -48,7 +48,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
_suppress_pydantic_deprecation_warnings()
__version__ = "1.15.0"
__version__ = "1.15.1a1"
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
"Memory": ("crewai.memory.unified_memory", "Memory"),

View File

@@ -19,7 +19,6 @@ Import surface:
from __future__ import annotations
from collections.abc import Callable, Mapping, Sequence
from contextlib import contextmanager
from enum import Enum
import json
import logging
@@ -63,21 +62,6 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
@contextmanager
def _streaming_conversation_llm(llm: BaseLLM, *, enabled: bool) -> Any:
"""Temporarily enable LLM streaming for Flow streaming turns."""
if not enabled:
yield
return
previous_stream = llm.stream
llm.stream = True
try:
yield
finally:
llm.stream = previous_stream
def _iter_condition_labels(condition: Any) -> set[str]:
if isinstance(condition, str):
return {condition}
@@ -162,9 +146,6 @@ class _ConversationalMixin:
def _copy_and_serialize_state(self) -> dict[str, Any]:
pass
def _should_stream_llm_calls(self) -> bool:
pass
def kickoff(self, *args: Any, **kwargs: Any) -> Any:
pass
@@ -240,12 +221,7 @@ class _ConversationalMixin:
messages.append({"role": "system", "content": system_prompt})
messages.extend(self.conversation_messages)
llm_instance = self._coerce_llm(llm)
with _streaming_conversation_llm(
llm_instance,
enabled=self._should_stream_llm_calls(),
):
response = llm_instance.call(messages=messages)
response = self._coerce_llm(llm).call(messages=messages)
content = self._stringify_result(response)
self.append_assistant_message(content)
return content
@@ -727,27 +703,6 @@ class _ConversationalMixin:
def _apply_pending_kickoff_context(self) -> None:
self._apply_pending_conversational_turn()
def _capture_pending_kickoff_context(self) -> dict[str, Any] | None:
if not self._should_apply_pending_kickoff_context():
return None
return {
"user_message": self._pending_user_message,
"intents": self._pending_intents,
"intent_llm": self._pending_intent_llm,
}
def _restore_pending_kickoff_context(self, context: Any) -> None:
if not isinstance(context, dict):
return
self._pending_user_message = context["user_message"]
self._pending_intents = context["intents"]
self._pending_intent_llm = context["intent_llm"]
def _clear_pending_kickoff_context(self) -> None:
self._pending_user_message = None
self._pending_intents = None
self._pending_intent_llm = None
def _order_start_methods_for_kickoff(
self,
start_methods: list[Any],

View File

@@ -15,7 +15,6 @@ from collections.abc import (
Sequence,
)
from concurrent.futures import Future, ThreadPoolExecutor
from contextlib import contextmanager
import contextvars
import copy
from datetime import datetime
@@ -461,16 +460,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
def _apply_pending_kickoff_context(self) -> None:
"""Apply optional runtime-extension kickoff context."""
def _capture_pending_kickoff_context(self) -> Any | None:
"""Capture optional pending kickoff context for deferred execution."""
return None
def _restore_pending_kickoff_context(self, context: Any) -> None:
"""Restore optional pending kickoff context in deferred execution."""
def _clear_pending_kickoff_context(self) -> None:
"""Clear optional pending kickoff context after deferred execution."""
def _order_start_methods_for_kickoff(
self,
start_methods: list[FlowMethodName],
@@ -482,19 +471,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
"""Whether this kickoff should defer final flow trace finalization."""
return bool(getattr(self, "defer_trace_finalization", False))
def _should_stream_llm_calls(self) -> bool:
"""Whether LLM calls inside the current flow run should stream chunks."""
return self.stream or self._streaming_run_active
@contextmanager
def _streaming_run(self) -> Iterator[None]:
previous_streaming_run = self._streaming_run_active
self._streaming_run_active = True
try:
yield
finally:
self._streaming_run_active = previous_streaming_run
@classmethod
def flow_definition(cls) -> FlowDefinition:
"""Return the static Flow Definition built from this Flow class."""
@@ -759,7 +735,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
_usage_aggregation_handler: Callable[..., Any] | None = PrivateAttr(default=None)
_persist_backends: dict[int, FlowPersistence] = PrivateAttr(default_factory=dict)
_instance_persistence: bool = PrivateAttr(default=False)
_streaming_run_active: bool = PrivateAttr(default=False)
def __class_getitem__(cls: type[Flow[T]], item: type[T]) -> type[Flow[T]]: # type: ignore[override]
class _FlowGeneric(cls): # type: ignore[valid-type,misc]
@@ -1897,7 +1872,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
return restored.kickoff(inputs=inputs, input_files=input_files)
if self.stream:
result_holder: list[Any] = []
pending_kickoff_context = self._capture_pending_kickoff_context()
current_task_info: TaskInfo = {
"index": 0,
"name": "",
@@ -1913,15 +1887,12 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
def run_flow() -> None:
try:
if pending_kickoff_context is not None:
self._restore_pending_kickoff_context(pending_kickoff_context)
with self._streaming_run():
self.stream = False
result = self.kickoff(
inputs=inputs,
input_files=input_files,
restore_from_state_id=restore_from_state_id,
)
self.stream = False
result = self.kickoff(
inputs=inputs,
input_files=input_files,
restore_from_state_id=restore_from_state_id,
)
result_holder.append(result)
except Exception as e:
# HumanFeedbackPending is expected control flow, not an error
@@ -1930,8 +1901,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
else:
signal_error(state, e)
finally:
if pending_kickoff_context is not None:
self._clear_pending_kickoff_context()
self.stream = True
signal_end(state)
@@ -2003,7 +1972,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
return await restored.kickoff_async(inputs=inputs, input_files=input_files)
if self.stream:
result_holder: list[Any] = []
pending_kickoff_context = self._capture_pending_kickoff_context()
current_task_info: TaskInfo = {
"index": 0,
"name": "",
@@ -2019,15 +1987,12 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
async def run_flow() -> None:
try:
if pending_kickoff_context is not None:
self._restore_pending_kickoff_context(pending_kickoff_context)
with self._streaming_run():
self.stream = False
result = await self.kickoff_async(
inputs=inputs,
input_files=input_files,
restore_from_state_id=restore_from_state_id,
)
self.stream = False
result = await self.kickoff_async(
inputs=inputs,
input_files=input_files,
restore_from_state_id=restore_from_state_id,
)
result_holder.append(result)
except Exception as e:
# HumanFeedbackPending is expected control flow, not an error
@@ -2036,8 +2001,6 @@ class Flow(BaseModel, Generic[T], metaclass=FlowMeta):
else:
signal_error(state, e, is_async=True)
finally:
if pending_kickoff_context is not None:
self._clear_pending_kickoff_context()
self.stream = True
signal_end(state, is_async=True)

View File

@@ -204,60 +204,6 @@ class TestConversationalFlow:
assert flow.state.events[0].agent_name == "researcher"
assert flow.state.events[0].visibility == "public"
def test_builtin_converse_enables_llm_streaming_for_streaming_flow(self) -> None:
llm = MagicMock()
llm.stream = False
stream_values_seen: list[bool | None] = []
def call(*args: Any, **kwargs: Any) -> str:
stream_values_seen.append(llm.stream)
return "streamed reply"
llm.call.side_effect = call
@ConversationConfig(llm=llm)
class StreamingFlow(ConversationalFlow):
pass
flow = StreamingFlow()
flow.stream = False
with flow._streaming_run():
result = flow.converse_turn()
assert result == "streamed reply"
assert stream_values_seen == [True]
assert llm.stream is False
assert flow._should_stream_llm_calls() is False
assert flow.state.messages[-1].content == "streamed reply"
def test_streaming_handle_turn_preserves_pending_user_message(self) -> None:
@ConversationConfig(llm="unused")
class StreamingEchoFlow(ConversationalFlow):
stream = True
def route_turn(self, context: dict[str, Any]) -> str:
return "echo"
@listen("echo")
def handle_echo(self) -> str:
reply = f"heard: {self.state.current_user_message}"
self.append_assistant_message(reply)
return reply
flow = StreamingEchoFlow()
result = flow.handle_turn("hello streaming")
for _chunk in result:
pass
assert result.result == "heard: hello streaming"
assert [message.role for message in flow.state.messages] == [
"user",
"assistant",
]
assert flow.state.messages[0].content == "hello streaming"
assert flow.state.messages[1].content == "heard: hello streaming"
@conversational_graph_broken
def test_private_agent_results_stay_out_of_shared_history(self) -> None:
class PrivateFlow(ConversationalFlow):

View File

@@ -1,3 +1,3 @@
"""CrewAI development tools."""
__version__ = "1.15.0"
__version__ = "1.15.1a1"