Compare commits

...
Author SHA1 Message Date
Joao Moura aee571b775 feat: add support for agents to invoke Flows as tools
Agents can now declare flows=[MyFlow] and invoke them as regular tools.
Each Flow class is wrapped as a FlowTool(BaseTool) — the agent decides
WHEN to use it (via tool selection), the Flow handles HOW (deterministic
execution).

- Add flows field to Agent
- Add FlowTool and create_flow_tools in tools/flow_tool.py
- Export from crewai.__init__
- 14 tests

No dependency changes. No memory changes. Just the flow-tool feature.
2026-04-27 05:10:38 -07:00
Greyson LaLonde cb46a1c4ba docs: update changelog and version for v1.14.3
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Check Documentation Broken Links / Check broken links (push) Has been cancelled
Vulnerability Scan / pip-audit (push) Has been cancelled
Nightly Canary Release / Check for new commits (push) Has been cancelled
Nightly Canary Release / Build nightly packages (push) Has been cancelled
Nightly Canary Release / Publish nightly to PyPI (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
2026-04-25 00:13:43 +08:00
Greyson LaLonde d9046b98dd feat: bump versions to 1.14.3 2026-04-25 00:04:46 +08:00
18 changed files with 2372 additions and 14 deletions

No files matched your search

+48
View File
@@ -4,6 +4,54 @@ description: "تحديثات المنتج والتحسينات وإصلاحات
icon: "clock"
mode: "wide"
---
<Update label="25 أبريل 2026">
## v1.14.3
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3)
## ما الذي تغير
### الميزات
- إضافة أحداث دورة الحياة لعمليات نقطة التحقق
- إضافة دعم لـ e2b
- الرجوع إلى DefaultAzureCredential عند عدم توفير مفتاح API في تكامل Azure
- إضافة دعم Bedrock V4
- إضافة أدوات Daytona sandbox لوظائف محسّنة
- إضافة دعم نقطة التحقق والتفرع للوكلاء المستقلين
### إصلاحات الأخطاء
- إصلاح execution_id ليكون منفصلًا عن state.id
- حل مشكلة إعادة تشغيل أحداث الطريقة المسجلة عند استئناف نقطة التحقق
- إصلاح تسلسل مراجع class initial_state كـ JSON schema
- الحفاظ على مهارات الوكلاء التي تحتوي على بيانات وصفية فقط
- تمرير أسماء @CrewBase الضمنية إلى أحداث الطاقم
- دمج بيانات التنفيذ عند تهيئة دفعة مكررة
- إصلاح تسلسل حقول مراجع class Task لنقاط التحقق
- التعامل مع نتيجة BaseModel في حلقة إعادة المحاولة guardrail
- الحفاظ على thought_signature في استدعاءات أدوات Gemini للبث
- إصدار task_started عند استئناف التفرع وإعادة تصميم واجهة المستخدم النصية لنقطة التحقق
- استخدام تواريخ مستقبلية في اختبارات تقليم نقطة التحقق لمنع الفشل المعتمد على الوقت
- إصلاح ترتيب التشغيل الجاف والتعامل مع الفرع القديم الذي تم التحقق منه في إصدار أدوات التطوير
- ترقية lxml إلى >=6.1.0 لرقعة الأمان
- رفع python-dotenv إلى >=1.2.2 لرقعة الأمان
### الوثائق
- تحديث سجل التغييرات والإصدار لـ v1.14.3
- إضافة صفحة "بناء باستخدام الذكاء الاصطناعي" وتحديث التنقل لجميع اللغات
- إزالة الأسئلة الشائعة حول التسعير من صفحة البناء باستخدام الذكاء الاصطناعي عبر جميع المواقع
### الأداء
- تحسين MCP SDK وأنواع الأحداث لتقليل بدء التشغيل البارد بنسبة ~29%
### إعادة الهيكلة
- إعادة هيكلة مساعدي نقطة التحقق للقضاء على التكرار وتشديد تلميحات نوع الحالة
## المساهمون
@MatthiasHowellYopp, @akaKuruma, @alex-clawd, @github-actions[bot], @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha, @renatonitta
</Update>
<Update label="23 أبريل 2026">
## v1.14.3a3
+1881 -4
View File
File diff suppressed because it is too large. Load diff
+48
View File
@@ -4,6 +4,54 @@ description: "Product updates, improvements, and bug fixes for CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="Apr 25, 2026">
## v1.14.3
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3)
## What's Changed
### Features
- Add lifecycle events for checkpoint operations
- Add support for e2b
- Fall back to DefaultAzureCredential when no API key is provided in Azure integration
- Add Bedrock V4 support
- Add Daytona sandbox tools for enhanced functionality
- Add checkpoint and fork support to standalone agents
### Bug Fixes
- Fix execution_id to be separate from state.id
- Resolve replay of recorded method events on checkpoint resume
- Fix serialization of initial_state class references as JSON schema
- Preserve metadata-only agent skills
- Propagate implicit @CrewBase names to crew events
- Merge execution metadata on duplicate batch initialization
- Fix serialization of Task class-reference fields for checkpointing
- Handle BaseModel result in guardrail retry loop
- Preserve thought_signature in Gemini streaming tool calls
- Emit task_started on fork resume and redesign checkpoint TUI
- Use future dates in checkpoint prune tests to prevent time-dependent failures
- Fix dry-run order and handle checked-out stale branch in devtools release
- Upgrade lxml to >=6.1.0 for security patch
- Bump python-dotenv to >=1.2.2 for security patch
### Documentation
- Update changelog and version for v1.14.3
- Add 'Build with AI' page and update navigation for all languages
- Remove pricing FAQ from build-with-ai page across all locales
### Performance
- Optimize MCP SDK and event types to reduce cold start by ~29%
### Refactoring
- Refactor checkpoint helpers to eliminate duplication and tighten state type hints
## Contributors
@MatthiasHowellYopp, @akaKuruma, @alex-clawd, @github-actions[bot], @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha, @renatonitta
</Update>
<Update label="Apr 23, 2026">
## v1.14.3a3
+48
View File
@@ -4,6 +4,54 @@ description: "CrewAI의 제품 업데이트, 개선 사항 및 버그 수정"
icon: "clock"
mode: "wide"
---
<Update label="2026년 4월 25일">
## v1.14.3
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3)
## 변경 사항
### 기능
- 체크포인트 작업을 위한 생명주기 이벤트 추가
- e2b 지원 추가
- Azure 통합에서 API 키가 제공되지 않을 경우 DefaultAzureCredential로 대체
- Bedrock V4 지원 추가
- 향상된 기능을 위한 Daytona 샌드박스 도구 추가
- 독립형 에이전트에 체크포인트 및 포크 지원 추가
### 버그 수정
- execution_id를 state.id와 분리되도록 수정
- 체크포인트 재개 시 기록된 메서드 이벤트 재생 문제 해결
- initial_state 클래스 참조의 JSON 스키마 직렬화 수정
- 메타데이터 전용 에이전트 기술 보존
- 암묵적인 @CrewBase 이름을 크루 이벤트로 전파
- 중복 배치 초기화 시 실행 메타데이터 병합
- 체크포인트를 위한 Task 클래스 참조 필드의 직렬화 수정
- 가드레일 재시도 루프에서 BaseModel 결과 처리
- Gemini 스트리밍 도구 호출에서 thought_signature 보존
- 포크 재개 시 task_started 방출 및 체크포인트 TUI 재설계
- 체크포인트 가지치기 테스트에서 미래 날짜 사용하여 시간 의존적 실패 방지
- 드라이 런 주문 수정 및 devtools 릴리스에서 체크아웃된 오래된 브랜치 처리
- 보안 패치를 위해 lxml을 >=6.1.0으로 업그레이드
- 보안 패치를 위해 python-dotenv를 >=1.2.2로 업그레이드
### 문서
- v1.14.3에 대한 변경 로그 및 버전 업데이트
- 'AI로 빌드하기' 페이지 추가 및 모든 언어에 대한 내비게이션 업데이트
- 모든 로케일에서 build-with-ai 페이지의 가격 FAQ 제거
### 성능
- MCP SDK 및 이벤트 유형 최적화하여 콜드 스타트를 약 29% 감소
### 리팩토링
- 중복 제거 및 상태 유형 힌트를 강화하기 위해 체크포인트 헬퍼 리팩토링
## 기여자
@MatthiasHowellYopp, @akaKuruma, @alex-clawd, @github-actions[bot], @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha, @renatonitta
</Update>
<Update label="2026년 4월 23일">
## v1.14.3a3
+48
View File
@@ -4,6 +4,54 @@ description: "Atualizações de produto, melhorias e correções do CrewAI"
icon: "clock"
mode: "wide"
---
<Update label="25 abr 2026">
## v1.14.3
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.3)
## O que Mudou
### Recursos
- Adicionar eventos de ciclo de vida para operações de checkpoint
- Adicionar suporte para e2b
- Reverter para DefaultAzureCredential quando nenhuma chave de API for fornecida na integração com o Azure
- Adicionar suporte ao Bedrock V4
- Adicionar ferramentas de sandbox Daytona para funcionalidade aprimorada
- Adicionar suporte a checkpoint e fork para agentes autônomos
### Correções de Bugs
- Corrigir execution_id para ser separado de state.id
- Resolver a reprodução de eventos de método gravados na retomada do checkpoint
- Corrigir a serialização de referências de classe initial_state como esquema JSON
- Preservar habilidades de agente somente de metadados
- Propagar nomes implícitos @CrewBase para eventos da equipe
- Mesclar metadados de execução na inicialização de lote duplicado
- Corrigir a serialização de campos de referência de classe Task para checkpointing
- Lidar com o resultado BaseModel no loop de retry do guardrail
- Preservar thought_signature em chamadas de ferramentas de streaming Gemini
- Emitir task_started na retomada do fork e redesenhar TUI de checkpoint
- Usar datas futuras em testes de poda de checkpoint para evitar falhas dependentes do tempo
- Corrigir a ordem de dry-run e lidar com branch obsoleta verificada na liberação do devtools
- Atualizar lxml para >=6.1.0 para patch de segurança
- Aumentar python-dotenv para >=1.2.2 para patch de segurança
### Documentação
- Atualizar changelog e versão para v1.14.3
- Adicionar página 'Construir com IA' e atualizar navegação para todos os idiomas
- Remover FAQ de preços da página construir-com-ia em todos os locais
### Desempenho
- Otimizar MCP SDK e tipos de eventos para reduzir o tempo de inicialização a frio em ~29%
### Refatoração
- Refatorar auxiliares de checkpoint para eliminar duplicação e apertar dicas de tipo de estado
## Contribuidores
@MatthiasHowellYopp, @akaKuruma, @alex-clawd, @github-actions[bot], @github-advanced-security[bot], @greysonlalonde, @iris-clawd, @lorenzejay, @mattatcha, @renatonitta
</Update>
<Update label="23 abr 2026">
## v1.14.3a3
@@ -152,4 +152,4 @@ __all__ = [
"wrap_file_source",
]
__version__ = "1.14.3a3"
__version__ = "1.14.3"
+1 -1
View File
@@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14"
dependencies = [
"pytube~=15.0.0",
"requests>=2.33.0,<3",
"crewai==1.14.3a3",
"crewai==1.14.3",
"tiktoken~=0.8.0",
"beautifulsoup4~=4.13.4",
"python-docx~=1.2.0",
@@ -321,4 +321,4 @@ __all__ = [
"ZapierActionTools",
]
__version__ = "1.14.3a3"
__version__ = "1.14.3"
+1 -1
View File
@@ -55,7 +55,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = [
"crewai-tools==1.14.3a3",
"crewai-tools==1.14.3",
]
embeddings = [
"tiktoken~=0.8.0"
+7 -1
View File
@@ -48,7 +48,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
_suppress_pydantic_deprecation_warnings()
__version__ = "1.14.3a3"
__version__ = "1.14.3"
_LAZY_IMPORTS: dict[str, tuple[str, str]] = {
"Memory": ("crewai.memory.unified_memory", "Memory"),
@@ -94,10 +94,16 @@ try:
}
from crewai.tools.base_tool import BaseTool as _BaseTool
from crewai.tools.flow_tool import (
FlowTool as _FlowTool,
create_flow_tools as _create_flow_tools,
)
from crewai.tools.structured_tool import CrewStructuredTool as _CrewStructuredTool
_base_namespace["BaseTool"] = _BaseTool
_base_namespace["CrewStructuredTool"] = _CrewStructuredTool
_base_namespace["FlowTool"] = _FlowTool
_base_namespace["create_flow_tools"] = _create_flow_tools # type: ignore[assignment]
try:
from crewai.a2a.config import (
+16
View File
@@ -85,6 +85,7 @@ from crewai.skills.loader import activate_skill, discover_skills
from crewai.skills.models import INSTRUCTIONS, Skill as SkillModel
from crewai.state.checkpoint_config import CheckpointConfig, apply_checkpoint
from crewai.tools.agent_tools.agent_tools import AgentTools
from crewai.tools.flow_tool import create_flow_tools
from crewai.types.callback import SerializableCallable
from crewai.utilities.agent_utils import (
get_tool_names,
@@ -305,6 +306,10 @@ class Agent(BaseAgent):
Can be a single A2AConfig/A2AClientConfig/A2AServerConfig, or a list of any number of A2AConfig/A2AClientConfig with a single A2AServerConfig.
""",
)
flows: list[Any] | None = Field(
default=None,
description="Flow classes that the agent can invoke as tools. Each entry is a Flow subclass (not an instance).",
)
agent_executor: CrewAgentExecutor | AgentExecutor | None = Field(
default=None, description="An instance of the CrewAgentExecutor class."
)
@@ -347,6 +352,7 @@ class Agent(BaseAgent):
)
self.set_skills()
self._set_flow_tools()
if self.reasoning and self.planning_config is None:
warnings.warn(
@@ -459,6 +465,16 @@ class Agent(BaseAgent):
self.skills = resolved if resolved else None
def _set_flow_tools(self) -> None:
"""Convert Flow classes in ``self.flows`` to tools and merge them."""
if not self.flows:
return
flow_tools = create_flow_tools(self.flows)
if flow_tools:
if self.tools is None:
self.tools = []
self.tools.extend(flow_tools)
def _is_any_available_memory(self) -> bool:
"""Check if unified memory is available (agent or crew)."""
if getattr(self, "memory", None):
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.14.3a3"
"crewai[tools]==1.14.3"
]
[project.scripts]
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.14.3a3"
"crewai[tools]==1.14.3"
]
[project.scripts]
@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]==1.14.3a3"
"crewai[tools]==1.14.3"
]
[tool.crewai]
+82
View File
@@ -0,0 +1,82 @@
"""Wrap Flow classes as callable tools so agents can invoke them."""
from __future__ import annotations
import json
from typing import Any
from pydantic import BaseModel, Field
from crewai.tools.base_tool import BaseTool
from crewai.utilities.string_utils import sanitize_tool_name
class FlowToolInputSchema(BaseModel):
"""Default input schema for a FlowTool."""
inputs: str = Field(
default="{}",
description=(
"JSON string of key-value pairs to pass as inputs to the flow. "
"Use '{}' if the flow requires no inputs."
),
)
class FlowTool(BaseTool):
"""Wraps a Flow class as a BaseTool so an agent can invoke it.
The tool instantiates the Flow, calls ``kickoff(inputs=...)`` and returns
the result as a string.
"""
name: str = ""
description: str = ""
flow_class: Any = Field(
default=None,
description="The Flow class (not instance) to wrap.",
exclude=True,
)
args_schema: Any = FlowToolInputSchema
def _run(self, inputs: str = "{}") -> str:
"""Instantiate the Flow, run kickoff, and return the result."""
try:
parsed_inputs = json.loads(inputs) if isinstance(inputs, str) else inputs
except (json.JSONDecodeError, TypeError):
parsed_inputs = {}
if not isinstance(parsed_inputs, dict):
parsed_inputs = {}
flow_instance = self.flow_class()
result = flow_instance.kickoff(inputs=parsed_inputs if parsed_inputs else None)
return str(result)
def create_flow_tools(flows: list[type] | None) -> list[BaseTool]:
"""Convert a list of Flow classes into BaseTool wrappers.
Args:
flows: Flow classes (not instances) to wrap as tools.
Returns:
A list of FlowTool instances ready for agent use.
"""
if not flows:
return []
tools: list[BaseTool] = []
for flow_cls in flows:
name = sanitize_tool_name(flow_cls.__name__)
docstring = (flow_cls.__doc__ or "").strip()
description = docstring if docstring else f"Run the {flow_cls.__name__} flow."
tools.append(
FlowTool(
name=name,
description=description,
flow_class=flow_cls,
)
)
return tools
+185
View File
@@ -0,0 +1,185 @@
"""Tests for Flow-as-tool functionality."""
from __future__ import annotations
from unittest.mock import MagicMock
from crewai.flow.flow import Flow, start
from crewai.tools.flow_tool import FlowTool, create_flow_tools
# ---------------------------------------------------------------------------
# Test Flow classes
# ---------------------------------------------------------------------------
class SimpleFlow(Flow):
"""A simple flow that greets the user."""
@start()
def greet(self) -> str:
return "Hello from SimpleFlow!"
class MathFlow(Flow):
"""Performs basic math operations."""
@start()
def compute(self) -> str:
return "42"
class NoDocFlow(Flow):
@start()
def run_it(self) -> str:
return "no doc"
# ---------------------------------------------------------------------------
# FlowTool unit tests
# ---------------------------------------------------------------------------
class TestFlowTool:
def test_wrap_simple_flow(self) -> None:
tool = FlowTool(
name="simple_flow",
description="A simple flow that greets the user.",
flow_class=SimpleFlow,
)
assert tool.name == "simple_flow"
assert "greets the user" in tool.description
def test_run_invokes_kickoff(self) -> None:
mock_flow = MagicMock()
mock_flow.return_value = mock_flow # __init__ returns self
mock_flow.kickoff.return_value = "mocked result"
tool = FlowTool(
name="test_flow",
description="test",
flow_class=mock_flow,
)
result = tool._run(inputs="{}")
assert result == "mocked result"
mock_flow.kickoff.assert_called_once()
def test_run_with_json_inputs(self) -> None:
mock_flow = MagicMock()
mock_flow.return_value = mock_flow
mock_flow.kickoff.return_value = "result with inputs"
tool = FlowTool(
name="test_flow",
description="test",
flow_class=mock_flow,
)
result = tool._run(inputs='{"key": "value"}')
assert result == "result with inputs"
mock_flow.kickoff.assert_called_once_with(inputs={"key": "value"})
def test_run_with_invalid_json_defaults_to_empty(self) -> None:
mock_flow = MagicMock()
mock_flow.return_value = mock_flow
mock_flow.kickoff.return_value = "ok"
tool = FlowTool(
name="test_flow",
description="test",
flow_class=mock_flow,
)
result = tool._run(inputs="not valid json")
assert result == "ok"
mock_flow.kickoff.assert_called_once_with(inputs=None)
def test_run_returns_string(self) -> None:
mock_flow = MagicMock()
mock_flow.return_value = mock_flow
mock_flow.kickoff.return_value = 42
tool = FlowTool(
name="test_flow",
description="test",
flow_class=mock_flow,
)
result = tool._run()
assert result == "42"
assert isinstance(result, str)
# ---------------------------------------------------------------------------
# create_flow_tools tests
# ---------------------------------------------------------------------------
class TestCreateFlowTools:
def test_creates_tools_from_flow_classes(self) -> None:
tools = create_flow_tools([SimpleFlow, MathFlow])
assert len(tools) == 2
names = {t.name for t in tools}
assert "simple_flow" in names
assert "math_flow" in names
def test_description_from_docstring(self) -> None:
tools = create_flow_tools([SimpleFlow])
assert len(tools) == 1
assert "greets the user" in tools[0].description
def test_description_fallback_when_no_docstring(self) -> None:
tools = create_flow_tools([NoDocFlow])
assert len(tools) == 1
assert "NoDocFlow" in tools[0].description
def test_empty_list_returns_empty(self) -> None:
assert create_flow_tools([]) == []
def test_none_returns_empty(self) -> None:
assert create_flow_tools(None) == []
def test_tools_are_base_tool_instances(self) -> None:
from crewai.tools.base_tool import BaseTool
tools = create_flow_tools([SimpleFlow])
for tool in tools:
assert isinstance(tool, BaseTool)
# ---------------------------------------------------------------------------
# Agent integration tests
# ---------------------------------------------------------------------------
class TestAgentFlowIntegration:
def test_agent_with_flows_has_flow_tools(self) -> None:
from crewai.agent.core import Agent
agent = Agent(
role="Test Agent",
goal="Test flows",
backstory="I test things",
flows=[SimpleFlow, MathFlow],
)
tool_names = {t.name for t in (agent.tools or [])}
assert "simple_flow" in tool_names
assert "math_flow" in tool_names
def test_agent_without_flows_no_extra_tools(self) -> None:
from crewai.agent.core import Agent
agent = Agent(
role="Test Agent",
goal="Test",
backstory="I test things",
)
# Should not have any flow tools
flow_tool_names = {
t.name for t in (agent.tools or []) if isinstance(t, FlowTool)
}
assert len(flow_tool_names) == 0
def test_flow_tool_executes_real_flow(self) -> None:
"""Test that a FlowTool actually runs the Flow's kickoff."""
tools = create_flow_tools([SimpleFlow])
tool = tools[0]
result = tool.run(inputs="{}")
assert "Hello from SimpleFlow" in result
+1 -1
View File
@@ -1,3 +1,3 @@
"""CrewAI development tools."""
__version__ = "1.14.3a3"
__version__ = "1.14.3"
Generated
+1 -1
View File
@@ -13,7 +13,7 @@ resolution-markers = [
]
[options]
exclude-newer = "2026-04-22T16:00:00Z"
exclude-newer = "2026-04-23T07:00:00Z"
[manifest]
members = [