mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-06-08 09:48:10 +00:00
Compare commits
9 Commits
1.14.3a2
...
docs/file-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c4b6e99f | ||
|
|
f01f33de69 | ||
|
|
8e59b27c93 | ||
|
|
53eb566e5c | ||
|
|
753b48f495 | ||
|
|
1d34bed515 | ||
|
|
9ed3a3026b | ||
|
|
944fe6d435 | ||
|
|
3be2fb65dc |
103
.github/workflows/import-time.yml
vendored
Normal file
103
.github/workflows/import-time.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
name: Import Time Guard
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "lib/crewai/src/**"
|
||||
- "lib/crewai/pyproject.toml"
|
||||
- "pyproject.toml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
import-time:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.12"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
version: "0.11.3"
|
||||
enable-cache: true
|
||||
|
||||
- name: Install the project
|
||||
run: uv sync --all-extras --no-dev
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
|
||||
- name: Benchmark PR branch
|
||||
id: pr
|
||||
run: |
|
||||
result=$(uv run python scripts/benchmark_import_time.py --runs 5 --json)
|
||||
echo "result=$result" >> "$GITHUB_OUTPUT"
|
||||
echo "pr_median=$(echo $result | python3 -c 'import sys,json; print(json.load(sys.stdin)["median_s"])')" >> "$GITHUB_OUTPUT"
|
||||
echo "### PR Branch Import Time" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "$result" | python3 -c "
|
||||
import sys, json
|
||||
d = json.load(sys.stdin)
|
||||
print(f'- Median: {d[\"median_s\"]}s')
|
||||
print(f'- Mean: {d[\"mean_s\"]}s ± {d[\"stdev_s\"]}s')
|
||||
print(f'- Range: {d[\"min_s\"]}s – {d[\"max_s\"]}s')
|
||||
" >> "$GITHUB_STEP_SUMMARY"
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
|
||||
- name: Checkout base branch
|
||||
run: git checkout ${{ github.event.pull_request.base.sha }}
|
||||
|
||||
- name: Install base branch
|
||||
run: uv sync --all-extras --no-dev
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
|
||||
- name: Benchmark base branch
|
||||
id: base
|
||||
run: |
|
||||
result=$(uv run python scripts/benchmark_import_time.py --runs 5 --json 2>/dev/null || echo '{"median_s": 0}')
|
||||
echo "result=$result" >> "$GITHUB_OUTPUT"
|
||||
echo "base_median=$(echo $result | python3 -c 'import sys,json; print(json.load(sys.stdin)["median_s"])')" >> "$GITHUB_OUTPUT"
|
||||
echo "### Base Branch Import Time" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "$result" | python3 -c "
|
||||
import sys, json
|
||||
d = json.load(sys.stdin)
|
||||
if d.get('median_s', 0) > 0:
|
||||
print(f'- Median: {d[\"median_s\"]}s')
|
||||
else:
|
||||
print('- Benchmark script not present on base branch (skip comparison)')
|
||||
" >> "$GITHUB_STEP_SUMMARY"
|
||||
env:
|
||||
UV_PYTHON: ${{ matrix.python-version }}
|
||||
|
||||
- name: Compare and gate
|
||||
run: |
|
||||
pr_median=${{ steps.pr.outputs.pr_median }}
|
||||
base_median=${{ steps.base.outputs.base_median }}
|
||||
|
||||
python3 -c "
|
||||
pr = float('$pr_median')
|
||||
base = float('$base_median')
|
||||
|
||||
if base <= 0:
|
||||
print('⏭️ No base benchmark available — skipping comparison.')
|
||||
exit(0)
|
||||
|
||||
change_pct = ((pr - base) / base) * 100
|
||||
print(f'Base: {base:.3f}s')
|
||||
print(f'PR: {pr:.3f}s')
|
||||
print(f'Change: {change_pct:+.1f}%')
|
||||
print()
|
||||
|
||||
if change_pct > 5:
|
||||
print(f'❌ BLOCKED: Import time regressed by {change_pct:.1f}% (threshold: 5%)')
|
||||
exit(1)
|
||||
elif change_pct > 0:
|
||||
print(f'⚠️ Slight regression ({change_pct:.1f}%) but within 5% threshold.')
|
||||
else:
|
||||
print(f'✅ Import time improved by {abs(change_pct):.1f}%')
|
||||
"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ chromadb-*.lock
|
||||
.crewai/memory
|
||||
blogs/*
|
||||
secrets/*
|
||||
UNKNOWN.egg-info/
|
||||
|
||||
@@ -117,23 +117,35 @@ task = Task(
|
||||
|
||||
### مع التدفقات
|
||||
|
||||
مرر الملفات إلى التدفقات، والتي تنتقل تلقائيًا إلى الأطقم:
|
||||
تعمل الحقول من نوع الملف (`File`، `ImageFile`، `PDFFile`) في مخطط حالة التدفق كإشارة لواجهة المنصة. عند النشر، تُعرض هذه الحقول كمناطق سحب وإفلات لرفع الملفات. يمكن أيضًا تمرير الملفات عبر `input_files` في API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import ImageFile
|
||||
from crewai_files import File, ImageFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisFlow(Flow):
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform UI
|
||||
cover_image: ImageFile # Image-specific dropzone
|
||||
title: str = ""
|
||||
|
||||
class AnalysisFlow(Flow[MyState]):
|
||||
@start()
|
||||
def analyze(self):
|
||||
# Files are automatically populated in state
|
||||
content = self.state.document.read()
|
||||
return self.analysis_crew.kickoff()
|
||||
|
||||
flow = AnalysisFlow()
|
||||
result = flow.kickoff(
|
||||
input_files={"image": ImageFile(source="data.png")}
|
||||
input_files={"document": File(source="report.pdf")}
|
||||
)
|
||||
```
|
||||
|
||||
<Note type="info" title="تكامل منصة CrewAI">
|
||||
عند النشر على منصة CrewAI، تحصل الحقول من نوع الملف مثل `ImageFile` و `PDFFile` وغيرها في حالة التدفق تلقائيًا على واجهة رفع ملفات. يمكن للمستخدمين سحب وإفلات الملفات مباشرة في واجهة المنصة. يتم تخزين الملفات بشكل آمن وتمريرها إلى الوكلاء باستخدام تحسينات خاصة بالمزود (base64 مضمّن، أو واجهات برمجة لرفع الملفات، أو مراجع URL حسب المزود). للاطلاع على أمثلة استخدام API، راجع [مدخلات الملفات في التدفقات](/ar/concepts/flows#مدخلات-الملفات).
|
||||
</Note>
|
||||
|
||||
### مع الوكلاء المستقلين
|
||||
|
||||
مرر الملفات مباشرة إلى تشغيل الوكيل:
|
||||
|
||||
@@ -341,6 +341,90 @@ flow.kickoff()
|
||||
|
||||
من خلال توفير خيارات إدارة الحالة غير المهيكلة والمهيكلة، تمكّن تدفقات CrewAI المطورين من بناء سير عمل ذكاء اصطناعي مرن ومتين في آن واحد، ملبيةً مجموعة واسعة من متطلبات التطبيقات.
|
||||
|
||||
### مدخلات الملفات
|
||||
|
||||
عند استخدام الحالة المهيكلة، يمكنك تضمين حقول من نوع الملف باستخدام فئات من `crewai-files`. تعمل الحقول من نوع الملف في حالة التدفق كإشارة للمنصة — فهي تُعرض تلقائيًا كمناطق سحب وإفلات لرفع الملفات في واجهة علامة تبويب Run ويتم تعبئتها عند رفع الملفات عبر المنصة أو تمريرها عبر `input_files` في API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import File, ImageFile, PDFFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform
|
||||
title: str = ""
|
||||
|
||||
class MyFlow(Flow[MyState]):
|
||||
@start()
|
||||
def process(self):
|
||||
# File object is automatically populated in state
|
||||
# when uploaded via Platform UI or passed via API
|
||||
content = self.state.document.read()
|
||||
print(f"Processing {self.state.title}: {len(content)} bytes")
|
||||
return content
|
||||
```
|
||||
|
||||
عند النشر على **منصة CrewAI**، تُعرض الحقول من نوع الملف (`File`، `ImageFile`، `PDFFile` من `crewai-files`) تلقائيًا كمناطق سحب وإفلات لرفع الملفات في واجهة المستخدم. يمكن للمستخدمين سحب وإفلات الملفات، والتي تُملأ بعد ذلك في حالة التدفق الخاص بك.
|
||||
|
||||
**بدء التشغيل مع الملفات عبر API:**
|
||||
|
||||
تكتشف نقطة النهاية `/kickoff` تنسيق الطلب تلقائيًا:
|
||||
- **جسم JSON** ← بدء تشغيل عادي
|
||||
- **multipart/form-data** ← رفع ملف + بدء تشغيل
|
||||
|
||||
يمكن لمستخدمي API أيضًا تمرير سلاسل URL مباشرة إلى الحقول من نوع الملف — يقوم Pydantic بتحويلها تلقائيًا.
|
||||
|
||||
### استخدام API
|
||||
|
||||
#### الخيار 1: بدء تشغيل multipart (موصى به)
|
||||
|
||||
أرسل الملفات مباشرة مع طلب بدء التشغيل:
|
||||
|
||||
```bash
|
||||
# With files (multipart) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"company_name": "Einstein"}' \
|
||||
-F 'cover_image=@/path/to/photo.jpg'
|
||||
```
|
||||
|
||||
يتم تخزين الملفات تلقائيًا وتحويلها إلى كائنات `FileInput`. يتلقى الوكيل الملف مع تحسين خاص بالمزود (base64 مضمّن، أو API لرفع الملفات، أو مرجع URL حسب مزود LLM).
|
||||
|
||||
#### الخيار 2: بدء تشغيل JSON (بدون ملفات)
|
||||
|
||||
```bash
|
||||
# Without files (JSON) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}}'
|
||||
```
|
||||
|
||||
#### الخيار 3: رفع منفصل + بدء تشغيل
|
||||
|
||||
هذا بديل لرفع multipart عندما تحتاج إلى رفع الملفات بشكل منفصل عن طلب بدء التشغيل. ارفع الملفات أولاً، ثم أشِر إليها بواسطة URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/photo.jpg' \
|
||||
-F 'field_name=cover_image'
|
||||
# Returns: {"url": "https://...", "field_name": "cover_image"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}, "input_files": {"cover_image": "https://..."}}'
|
||||
```
|
||||
|
||||
راجع وثائق Platform API للحصول على تفاصيل كاملة حول نقطة النهاية `/files`.
|
||||
|
||||
#### على منصة CrewAI
|
||||
|
||||
عند استخدام واجهة المنصة، تُعرض الحقول من نوع الملف تلقائيًا كمناطق سحب وإفلات للرفع. لا حاجة لاستدعاءات API — فقط أفلِت الملف وانقر على تشغيل.
|
||||
|
||||
## استمرارية التدفق
|
||||
|
||||
يتيح مزخرف @persist الاستمرارية التلقائية للحالة في تدفقات CrewAI، مما يسمح لك بالحفاظ على حالة التدفق عبر عمليات إعادة التشغيل أو تنفيذات سير العمل المختلفة. يمكن تطبيق هذا المزخرف على مستوى الفئة أو مستوى الدالة، مما يوفر مرونة في كيفية إدارة استمرارية الحالة.
|
||||
|
||||
@@ -86,6 +86,60 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
|
||||
|
||||
رمز الحامل متاح في علامة تبويب Status في صفحة تفاصيل طاقمك.
|
||||
|
||||
## رفع الملفات
|
||||
|
||||
عندما يتضمن طاقمك أو تدفقك حقول حالة من نوع الملف (باستخدام `ImageFile` أو `PDFFile` أو `File` من `crewai-files`)، تُعرض هذه الحقول تلقائيًا كمناطق سحب وإفلات لرفع الملفات في واجهة علامة تبويب Run. يمكن للمستخدمين سحب وإفلات الملفات مباشرة، وتتولى المنصة التخزين والتسليم إلى وكلائك.
|
||||
|
||||
### بدء تشغيل Multipart (موصى به)
|
||||
|
||||
أرسل الملفات مباشرة مع طلب بدء التشغيل باستخدام `multipart/form-data`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"title": "Report"}' \
|
||||
-F 'document=@/path/to/file.pdf'
|
||||
```
|
||||
|
||||
يتم تخزين الملفات تلقائيًا وتحويلها إلى كائنات ملفات. يتلقى الوكيل الملف مع تحسين خاص بالمزود (base64 مضمّن، أو API لرفع الملفات، أو مرجع URL حسب مزود LLM).
|
||||
|
||||
### بدء تشغيل JSON مع عناوين URL للملفات
|
||||
|
||||
إذا كانت لديك ملفات مستضافة بالفعل على عناوين URL، مررها عبر `input_files`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"inputs": {"title": "Report"},
|
||||
"input_files": {"document": "https://example.com/file.pdf"}
|
||||
}'
|
||||
```
|
||||
|
||||
### رفع منفصل + بدء تشغيل
|
||||
|
||||
ارفع الملفات أولاً، ثم أشِر إليها بواسطة URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/file.pdf' \
|
||||
-F 'field_name=document'
|
||||
# Returns: {"url": "https://...", "field_name": "document"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"title": "Report"}, "input_files": {"document": "https://..."}}'
|
||||
```
|
||||
|
||||
<Note type="info">
|
||||
يعمل رفع الملفات بنفس الطريقة لكل من الطواقم والتدفقات. عرّف حقول من نوع الملف في مخطط حالتك، وستتولى واجهة المنصة وAPI الرفع تلقائيًا.
|
||||
</Note>
|
||||
|
||||
### التحقق من صحة الطاقم
|
||||
|
||||
قبل تنفيذ العمليات، يمكنك التحقق من أن طاقمك يعمل بشكل صحيح:
|
||||
|
||||
@@ -207,9 +207,6 @@ CrewAI AMP مُصمَّم لفرق الإنتاج. إليك ما تحصل علي
|
||||
- **Factory (استضافة ذاتية)** — على بنيتك التحتية لسيطرة كاملة على البيانات
|
||||
- **هجين** — دمج السحابة والاستضافة الذاتية حسب حساسية البيانات
|
||||
</Accordion>
|
||||
<Accordion title="كيف يعمل التسعير؟">
|
||||
سجّل في [app.crewai.com](https://app.crewai.com) لمعرفة الخطط الحالية. تسعير المؤسسات وFactory متاح عند الطلب.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Card title="استكشف CrewAI AMP →" icon="arrow-right" href="https://app.crewai.com">
|
||||
|
||||
@@ -117,23 +117,35 @@ task = Task(
|
||||
|
||||
### With Flows
|
||||
|
||||
Pass files to flows, which automatically inherit to crews:
|
||||
File-typed fields (`File`, `ImageFile`, `PDFFile`) in your flow's state schema serve as the signal to the Platform UI. When deployed, these fields render as file upload dropzones. Files can also be passed via `input_files` in the API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import ImageFile
|
||||
from crewai_files import File, ImageFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisFlow(Flow):
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform UI
|
||||
cover_image: ImageFile # Image-specific dropzone
|
||||
title: str = ""
|
||||
|
||||
class AnalysisFlow(Flow[MyState]):
|
||||
@start()
|
||||
def analyze(self):
|
||||
# Files are automatically populated in state
|
||||
content = self.state.document.read()
|
||||
return self.analysis_crew.kickoff()
|
||||
|
||||
flow = AnalysisFlow()
|
||||
result = flow.kickoff(
|
||||
input_files={"image": ImageFile(source="data.png")}
|
||||
input_files={"document": File(source="report.pdf")}
|
||||
)
|
||||
```
|
||||
|
||||
<Note type="info" title="CrewAI Platform Integration">
|
||||
When deployed on CrewAI Platform, `ImageFile`, `PDFFile`, and other file-typed fields in your flow state automatically get a file upload UI. Users can drag and drop files directly in the Platform interface. Files are stored securely and passed to agents using provider-specific optimizations (inline base64, file upload APIs, or URL references depending on the provider). For API usage examples, see [File Inputs in Flows](/concepts/flows#file-inputs).
|
||||
</Note>
|
||||
|
||||
### With Standalone Agents
|
||||
|
||||
Pass files directly to agent kickoff:
|
||||
|
||||
@@ -341,6 +341,90 @@ flow.kickoff()
|
||||
|
||||
By providing both unstructured and structured state management options, CrewAI Flows empowers developers to build AI workflows that are both flexible and robust, catering to a wide range of application requirements.
|
||||
|
||||
### File Inputs
|
||||
|
||||
When using structured state, you can include file-typed fields using classes from `crewai-files`. File-typed fields in your flow state serve as the signal to the Platform—they automatically render as file upload dropzones in the Run tab UI and get populated when files are uploaded via the Platform or passed via `input_files` in the API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import File, ImageFile, PDFFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform
|
||||
title: str = ""
|
||||
|
||||
class MyFlow(Flow[MyState]):
|
||||
@start()
|
||||
def process(self):
|
||||
# File object is automatically populated in state
|
||||
# when uploaded via Platform UI or passed via API
|
||||
content = self.state.document.read()
|
||||
print(f"Processing {self.state.title}: {len(content)} bytes")
|
||||
return content
|
||||
```
|
||||
|
||||
When deployed on **CrewAI Platform**, file-typed fields (`File`, `ImageFile`, `PDFFile` from `crewai-files`) automatically render as file upload dropzones in the UI. Users can drag and drop files, which are then populated into your flow's state.
|
||||
|
||||
**Kicking off with files via API:**
|
||||
|
||||
The `/kickoff` endpoint auto-detects the request format:
|
||||
- **JSON body** → normal kickoff
|
||||
- **multipart/form-data** → file upload + kickoff
|
||||
|
||||
API users can also pass URL strings directly to file-typed fields—Pydantic coerces them automatically.
|
||||
|
||||
### API Usage
|
||||
|
||||
#### Option 1: Multipart kickoff (recommended)
|
||||
|
||||
Send files directly with the kickoff request:
|
||||
|
||||
```bash
|
||||
# With files (multipart) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"company_name": "Einstein"}' \
|
||||
-F 'cover_image=@/path/to/photo.jpg'
|
||||
```
|
||||
|
||||
Files are automatically stored and converted to `FileInput` objects. The agent receives the file with provider-specific optimization (inline base64, file upload API, or URL reference depending on the LLM provider).
|
||||
|
||||
#### Option 2: JSON kickoff (no files)
|
||||
|
||||
```bash
|
||||
# Without files (JSON) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}}'
|
||||
```
|
||||
|
||||
#### Option 3: Separate upload + kickoff
|
||||
|
||||
This is an alternative to multipart upload when you need to upload files separately from the kickoff request. Upload files first, then reference them by URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/photo.jpg' \
|
||||
-F 'field_name=cover_image'
|
||||
# Returns: {"url": "https://...", "field_name": "cover_image"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}, "input_files": {"cover_image": "https://..."}}'
|
||||
```
|
||||
|
||||
See the Platform API documentation for full `/files` endpoint details.
|
||||
|
||||
#### On CrewAI Platform
|
||||
|
||||
When using the Platform UI, file-typed fields automatically render as drag-and-drop upload zones. No API calls needed—just drop the file and click Run.
|
||||
|
||||
## Flow Persistence
|
||||
|
||||
The @persist decorator enables automatic state persistence in CrewAI Flows, allowing you to maintain flow state across restarts or different workflow executions. This decorator can be applied at either the class level or method level, providing flexibility in how you manage state persistence.
|
||||
|
||||
@@ -86,6 +86,60 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
|
||||
|
||||
Your bearer token is available on the Status tab of your crew's detail page.
|
||||
|
||||
## File Uploads
|
||||
|
||||
When your crew or flow includes file-typed state fields (using `ImageFile`, `PDFFile`, or `File` from `crewai-files`), these fields automatically render as file upload dropzones in the Run tab UI. Users can drag and drop files directly, and the Platform handles storage and delivery to your agents.
|
||||
|
||||
### Multipart Kickoff (Recommended)
|
||||
|
||||
Send files directly with the kickoff request using `multipart/form-data`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"title": "Report"}' \
|
||||
-F 'document=@/path/to/file.pdf'
|
||||
```
|
||||
|
||||
Files are automatically stored and converted to file objects. The agent receives the file with provider-specific optimization (inline base64, file upload API, or URL reference depending on the LLM provider).
|
||||
|
||||
### JSON Kickoff with File URLs
|
||||
|
||||
If you have files already hosted at URLs, pass them via `input_files`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"inputs": {"title": "Report"},
|
||||
"input_files": {"document": "https://example.com/file.pdf"}
|
||||
}'
|
||||
```
|
||||
|
||||
### Separate Upload + Kickoff
|
||||
|
||||
Upload files first, then reference them by URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/file.pdf' \
|
||||
-F 'field_name=document'
|
||||
# Returns: {"url": "https://...", "field_name": "document"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"title": "Report"}, "input_files": {"document": "https://..."}}'
|
||||
```
|
||||
|
||||
<Note type="info">
|
||||
File uploads work the same way for both crews and flows. Define file-typed fields in your state schema, and the Platform UI and API will handle uploads automatically.
|
||||
</Note>
|
||||
|
||||
### Checking Crew Health
|
||||
|
||||
Before executing operations, you can verify that your crew is running properly:
|
||||
|
||||
@@ -207,9 +207,6 @@ CrewAI AMP is built for production teams. Here's what you get beyond deployment.
|
||||
- **Factory (self-hosted)** — run on your own infrastructure for full data control
|
||||
- **Hybrid** — mix cloud and self-hosted based on sensitivity requirements
|
||||
</Accordion>
|
||||
<Accordion title="How does pricing work?">
|
||||
Sign up at [app.crewai.com](https://app.crewai.com) to see current plans. Enterprise and Factory pricing is available on request.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Card title="Explore CrewAI AMP →" icon="arrow-right" href="https://app.crewai.com">
|
||||
|
||||
@@ -117,23 +117,35 @@ task = Task(
|
||||
|
||||
### Flow와 함께
|
||||
|
||||
flow에 파일을 전달하면 자동으로 crew에 상속됩니다:
|
||||
flow의 상태 스키마에 있는 파일 타입 필드(`File`, `ImageFile`, `PDFFile`)는 플랫폼 UI에 대한 신호 역할을 합니다. 배포 시 이러한 필드는 파일 업로드 드롭존으로 렌더링됩니다. 파일은 API에서 `input_files`를 통해서도 전달할 수 있습니다.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import ImageFile
|
||||
from crewai_files import File, ImageFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisFlow(Flow):
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform UI
|
||||
cover_image: ImageFile # Image-specific dropzone
|
||||
title: str = ""
|
||||
|
||||
class AnalysisFlow(Flow[MyState]):
|
||||
@start()
|
||||
def analyze(self):
|
||||
# Files are automatically populated in state
|
||||
content = self.state.document.read()
|
||||
return self.analysis_crew.kickoff()
|
||||
|
||||
flow = AnalysisFlow()
|
||||
result = flow.kickoff(
|
||||
input_files={"image": ImageFile(source="data.png")}
|
||||
input_files={"document": File(source="report.pdf")}
|
||||
)
|
||||
```
|
||||
|
||||
<Note type="info" title="CrewAI 플랫폼 통합">
|
||||
CrewAI 플랫폼에 배포하면 flow 상태의 `ImageFile`, `PDFFile` 및 기타 파일 타입 필드가 자동으로 파일 업로드 UI를 갖게 됩니다. 사용자는 플랫폼 인터페이스에서 직접 파일을 드래그 앤 드롭할 수 있습니다. 파일은 안전하게 저장되고 프로바이더별 최적화(인라인 base64, 파일 업로드 API 또는 프로바이더에 따른 URL 참조)를 사용하여 에이전트에 전달됩니다. API 사용 예제는 [Flows의 파일 입력](/ko/concepts/flows#파일-입력)을 참조하세요.
|
||||
</Note>
|
||||
|
||||
### 단독 에이전트와 함께
|
||||
|
||||
에이전트 킥오프에 직접 파일을 전달합니다:
|
||||
|
||||
@@ -334,6 +334,90 @@ flow.kickoff()
|
||||
|
||||
CrewAI Flows는 비구조적 및 구조적 상태 관리 옵션을 모두 제공함으로써, 개발자들이 다양한 애플리케이션 요구 사항에 맞춰 유연하면서도 견고한 AI 워크플로를 구축할 수 있도록 지원합니다.
|
||||
|
||||
### 파일 입력
|
||||
|
||||
구조화된 상태를 사용할 때, `crewai-files`의 클래스를 사용하여 파일 타입 필드를 포함할 수 있습니다. flow 상태의 파일 타입 필드는 플랫폼에 대한 신호 역할을 합니다 — Run 탭 UI에서 자동으로 파일 업로드 드롭존으로 렌더링되며, 플랫폼을 통해 파일을 업로드하거나 API에서 `input_files`를 통해 전달할 때 자동으로 채워집니다.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import File, ImageFile, PDFFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform
|
||||
title: str = ""
|
||||
|
||||
class MyFlow(Flow[MyState]):
|
||||
@start()
|
||||
def process(self):
|
||||
# File object is automatically populated in state
|
||||
# when uploaded via Platform UI or passed via API
|
||||
content = self.state.document.read()
|
||||
print(f"Processing {self.state.title}: {len(content)} bytes")
|
||||
return content
|
||||
```
|
||||
|
||||
**CrewAI 플랫폼**에 배포하면 파일 타입 필드(`crewai-files`의 `File`, `ImageFile`, `PDFFile`)가 UI에서 자동으로 파일 업로드 드롭존으로 렌더링됩니다. 사용자는 파일을 드래그 앤 드롭할 수 있으며, 해당 파일은 flow의 상태에 자동으로 채워집니다.
|
||||
|
||||
**API를 통한 파일 포함 시작:**
|
||||
|
||||
`/kickoff` 엔드포인트는 요청 형식을 자동으로 감지합니다:
|
||||
- **JSON body** → 일반 kickoff
|
||||
- **multipart/form-data** → 파일 업로드 + kickoff
|
||||
|
||||
API 사용자는 파일 타입 필드에 URL 문자열을 직접 전달할 수도 있습니다 — Pydantic이 자동으로 변환합니다.
|
||||
|
||||
### API 사용법
|
||||
|
||||
#### 옵션 1: Multipart kickoff (권장)
|
||||
|
||||
kickoff 요청과 함께 파일을 직접 전송합니다:
|
||||
|
||||
```bash
|
||||
# With files (multipart) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"company_name": "Einstein"}' \
|
||||
-F 'cover_image=@/path/to/photo.jpg'
|
||||
```
|
||||
|
||||
파일은 자동으로 저장되고 `FileInput` 객체로 변환됩니다. 에이전트는 프로바이더별 최적화(LLM 프로바이더에 따라 인라인 base64, 파일 업로드 API 또는 URL 참조)와 함께 파일을 수신합니다.
|
||||
|
||||
#### 옵션 2: JSON kickoff (파일 없음)
|
||||
|
||||
```bash
|
||||
# Without files (JSON) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}}'
|
||||
```
|
||||
|
||||
#### 옵션 3: 분리된 업로드 + kickoff
|
||||
|
||||
kickoff 요청과 별도로 파일을 업로드해야 할 때 multipart 업로드의 대안입니다. 먼저 파일을 업로드한 다음 URL로 참조합니다:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/photo.jpg' \
|
||||
-F 'field_name=cover_image'
|
||||
# Returns: {"url": "https://...", "field_name": "cover_image"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}, "input_files": {"cover_image": "https://..."}}'
|
||||
```
|
||||
|
||||
`/files` 엔드포인트에 대한 자세한 내용은 플랫폼 API 문서를 참조하세요.
|
||||
|
||||
#### CrewAI 플랫폼에서
|
||||
|
||||
플랫폼 UI를 사용할 때 파일 타입 필드는 자동으로 드래그 앤 드롭 업로드 영역으로 렌더링됩니다. API 호출이 필요 없습니다 — 파일을 드롭하고 실행을 클릭하면 됩니다.
|
||||
|
||||
## 플로우 지속성
|
||||
|
||||
@persist 데코레이터는 CrewAI 플로우에서 자동 상태 지속성을 활성화하여, 플로우 상태를 재시작이나 다른 워크플로우 실행 간에도 유지할 수 있도록 합니다. 이 데코레이터는 클래스 수준이나 메서드 수준 모두에 적용할 수 있어, 상태 지속성을 관리하는 데 유연성을 제공합니다.
|
||||
|
||||
@@ -86,6 +86,60 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
|
||||
|
||||
베어러 토큰은 crew의 상세 페이지의 Status 탭에서 확인할 수 있습니다.
|
||||
|
||||
## 파일 업로드
|
||||
|
||||
crew나 flow에 파일 타입 상태 필드(`crewai-files`의 `ImageFile`, `PDFFile`, 또는 `File` 사용)가 포함되어 있으면, 이러한 필드는 Run 탭 UI에서 자동으로 파일 업로드 드롭존으로 렌더링됩니다. 사용자는 파일을 직접 드래그 앤 드롭할 수 있으며, 플랫폼이 저장 및 에이전트 전달을 처리합니다.
|
||||
|
||||
### Multipart Kickoff (권장)
|
||||
|
||||
`multipart/form-data`를 사용하여 kickoff 요청과 함께 파일을 직접 전송합니다:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"title": "Report"}' \
|
||||
-F 'document=@/path/to/file.pdf'
|
||||
```
|
||||
|
||||
파일은 자동으로 저장되고 파일 객체로 변환됩니다. 에이전트는 프로바이더별 최적화(LLM 프로바이더에 따라 인라인 base64, 파일 업로드 API 또는 URL 참조)와 함께 파일을 수신합니다.
|
||||
|
||||
### 파일 URL을 포함한 JSON Kickoff
|
||||
|
||||
이미 URL에 호스팅된 파일이 있다면 `input_files`를 통해 전달합니다:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"inputs": {"title": "Report"},
|
||||
"input_files": {"document": "https://example.com/file.pdf"}
|
||||
}'
|
||||
```
|
||||
|
||||
### 분리된 업로드 + Kickoff
|
||||
|
||||
먼저 파일을 업로드한 다음 URL로 참조합니다:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/file.pdf' \
|
||||
-F 'field_name=document'
|
||||
# Returns: {"url": "https://...", "field_name": "document"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"title": "Report"}, "input_files": {"document": "https://..."}}'
|
||||
```
|
||||
|
||||
<Note type="info">
|
||||
파일 업로드는 crew와 flow 모두에서 동일하게 작동합니다. 상태 스키마에 파일 타입 필드를 정의하면 플랫폼 UI와 API가 자동으로 업로드를 처리합니다.
|
||||
</Note>
|
||||
|
||||
### 크루 상태 확인
|
||||
|
||||
작업을 실행하기 전에 크루가 정상적으로 실행되고 있는지 확인할 수 있습니다:
|
||||
|
||||
@@ -207,9 +207,6 @@ CrewAI AMP는 프로덕션 팀을 위해 만들어졌습니다. 배포 외에
|
||||
- **Factory(셀프 호스팅)** — 데이터 통제를 위해 자체 인프라에서 실행
|
||||
- **하이브리드** — 민감도에 따라 클라우드와 셀프 호스팅을 혼합
|
||||
</Accordion>
|
||||
<Accordion title="가격은 어떻게 되나요?">
|
||||
[app.crewai.com](https://app.crewai.com)에 가입하면 현재 요금제를 확인할 수 있습니다. 엔터프라이즈 및 Factory 가격은 문의 시 안내합니다.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Card title="CrewAI AMP 살펴보기 →" icon="arrow-right" href="https://app.crewai.com">
|
||||
|
||||
@@ -117,23 +117,35 @@ task = Task(
|
||||
|
||||
### Com Flows
|
||||
|
||||
Passe arquivos para flows, que automaticamente herdam para crews:
|
||||
Campos tipados como arquivo (`File`, `ImageFile`, `PDFFile`) no esquema de estado do seu flow servem como sinal para a interface da Plataforma. Quando implantado, esses campos são renderizados como zonas de upload de arquivos. Arquivos também podem ser passados via `input_files` na API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import ImageFile
|
||||
from crewai_files import File, ImageFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class AnalysisFlow(Flow):
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform UI
|
||||
cover_image: ImageFile # Image-specific dropzone
|
||||
title: str = ""
|
||||
|
||||
class AnalysisFlow(Flow[MyState]):
|
||||
@start()
|
||||
def analyze(self):
|
||||
# Files are automatically populated in state
|
||||
content = self.state.document.read()
|
||||
return self.analysis_crew.kickoff()
|
||||
|
||||
flow = AnalysisFlow()
|
||||
result = flow.kickoff(
|
||||
input_files={"image": ImageFile(source="data.png")}
|
||||
input_files={"document": File(source="report.pdf")}
|
||||
)
|
||||
```
|
||||
|
||||
<Note type="info" title="Integração com a Plataforma CrewAI">
|
||||
Quando implantado na Plataforma CrewAI, campos tipados como arquivo como `ImageFile`, `PDFFile` e outros no estado do seu flow recebem automaticamente uma interface de upload de arquivos. Os usuários podem arrastar e soltar arquivos diretamente na interface da Plataforma. Os arquivos são armazenados de forma segura e passados para os agentes usando otimizações específicas do provedor (base64 inline, APIs de upload de arquivo ou referências por URL dependendo do provedor). Para exemplos de uso da API, consulte [Entradas de Arquivos em Flows](/pt-BR/concepts/flows#entradas-de-arquivos).
|
||||
</Note>
|
||||
|
||||
### Com Agentes Standalone
|
||||
|
||||
Passe arquivos diretamente no kickoff do agente:
|
||||
|
||||
@@ -173,6 +173,90 @@ Cada estado nos flows do CrewAI recebe automaticamente um identificador único (
|
||||
|
||||
Ao oferecer as duas opções de gerenciamento de estado, o CrewAI Flows permite que desenvolvedores criem fluxos de IA que sejam ao mesmo tempo flexíveis e robustos, atendendo a uma ampla variedade de requisitos de aplicação.
|
||||
|
||||
### Entradas de Arquivos
|
||||
|
||||
Ao usar estado estruturado, você pode incluir campos tipados como arquivo usando classes do `crewai-files`. Campos tipados como arquivo no estado do seu flow servem como sinal para a Plataforma — eles são renderizados automaticamente como zonas de upload de arquivos na aba Run da interface e são preenchidos quando arquivos são enviados via Plataforma ou passados via `input_files` na API.
|
||||
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start
|
||||
from crewai_files import File, ImageFile, PDFFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
class MyState(BaseModel):
|
||||
document: File # Renders as file dropzone in Platform
|
||||
title: str = ""
|
||||
|
||||
class MyFlow(Flow[MyState]):
|
||||
@start()
|
||||
def process(self):
|
||||
# File object is automatically populated in state
|
||||
# when uploaded via Platform UI or passed via API
|
||||
content = self.state.document.read()
|
||||
print(f"Processing {self.state.title}: {len(content)} bytes")
|
||||
return content
|
||||
```
|
||||
|
||||
Quando implantado na **Plataforma CrewAI**, campos tipados como arquivo (`File`, `ImageFile`, `PDFFile` do `crewai-files`) são renderizados automaticamente como zonas de upload de arquivos na interface. Os usuários podem arrastar e soltar arquivos, que são então preenchidos no estado do seu flow.
|
||||
|
||||
**Iniciando com arquivos via API:**
|
||||
|
||||
O endpoint `/kickoff` detecta automaticamente o formato da requisição:
|
||||
- **Corpo JSON** → kickoff normal
|
||||
- **multipart/form-data** → upload de arquivo + kickoff
|
||||
|
||||
Usuários da API também podem passar strings de URL diretamente para campos tipados como arquivo — o Pydantic as converte automaticamente.
|
||||
|
||||
### Uso da API
|
||||
|
||||
#### Opção 1: Kickoff multipart (recomendado)
|
||||
|
||||
Envie arquivos diretamente com a requisição de kickoff:
|
||||
|
||||
```bash
|
||||
# With files (multipart) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"company_name": "Einstein"}' \
|
||||
-F 'cover_image=@/path/to/photo.jpg'
|
||||
```
|
||||
|
||||
Os arquivos são armazenados automaticamente e convertidos em objetos `FileInput`. O agente recebe o arquivo com otimização específica do provedor (base64 inline, API de upload de arquivo ou referência por URL dependendo do provedor LLM).
|
||||
|
||||
#### Opção 2: Kickoff JSON (sem arquivos)
|
||||
|
||||
```bash
|
||||
# Without files (JSON) — same endpoint
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}}'
|
||||
```
|
||||
|
||||
#### Opção 3: Upload separado + kickoff
|
||||
|
||||
Esta é uma alternativa ao upload multipart quando você precisa fazer upload dos arquivos separadamente da requisição de kickoff. Faça o upload dos arquivos primeiro e depois referencie-os por URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/photo.jpg' \
|
||||
-F 'field_name=cover_image'
|
||||
# Returns: {"url": "https://...", "field_name": "cover_image"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"company_name": "Einstein"}, "input_files": {"cover_image": "https://..."}}'
|
||||
```
|
||||
|
||||
Consulte a documentação da API da Plataforma para detalhes completos do endpoint `/files`.
|
||||
|
||||
#### Na Plataforma CrewAI
|
||||
|
||||
Ao usar a interface da Plataforma, campos tipados como arquivo são renderizados automaticamente como zonas de arrastar e soltar para upload. Nenhuma chamada de API é necessária — basta soltar o arquivo e clicar em Executar.
|
||||
|
||||
## Persistência de Flow
|
||||
|
||||
O decorador @persist permite a persistência automática do estado nos flows do CrewAI, garantindo que você mantenha o estado do flow entre reinicializações ou execuções diferentes do workflow. Esse decorador pode ser aplicado tanto ao nível de classe, quanto ao nível de método, oferecendo flexibilidade sobre como gerenciar a persistência do estado.
|
||||
|
||||
@@ -86,6 +86,60 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
|
||||
|
||||
Seu bearer token está disponível na aba Status na página de detalhes do seu crew.
|
||||
|
||||
## Upload de Arquivos
|
||||
|
||||
Quando seu crew ou flow inclui campos de estado tipados como arquivo (usando `ImageFile`, `PDFFile` ou `File` do `crewai-files`), esses campos são renderizados automaticamente como zonas de upload de arquivos na aba Run da interface. Os usuários podem arrastar e soltar arquivos diretamente, e a Plataforma gerencia o armazenamento e entrega para seus agentes.
|
||||
|
||||
### Kickoff Multipart (Recomendado)
|
||||
|
||||
Envie arquivos diretamente com a requisição de kickoff usando `multipart/form-data`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'inputs={"title": "Report"}' \
|
||||
-F 'document=@/path/to/file.pdf'
|
||||
```
|
||||
|
||||
Os arquivos são armazenados automaticamente e convertidos em objetos de arquivo. O agente recebe o arquivo com otimização específica do provedor (base64 inline, API de upload de arquivo ou referência por URL dependendo do provedor LLM).
|
||||
|
||||
### Kickoff JSON com URLs de Arquivos
|
||||
|
||||
Se você já tem arquivos hospedados em URLs, passe-os via `input_files`:
|
||||
|
||||
```bash
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{
|
||||
"inputs": {"title": "Report"},
|
||||
"input_files": {"document": "https://example.com/file.pdf"}
|
||||
}'
|
||||
```
|
||||
|
||||
### Upload Separado + Kickoff
|
||||
|
||||
Faça upload dos arquivos primeiro e depois referencie-os por URL:
|
||||
|
||||
```bash
|
||||
# Step 1: Upload
|
||||
curl -X POST https://your-deployment.crewai.com/files \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-F 'file=@/path/to/file.pdf' \
|
||||
-F 'field_name=document'
|
||||
# Returns: {"url": "https://...", "field_name": "document"}
|
||||
|
||||
# Step 2: Kickoff with URL
|
||||
curl -X POST https://your-deployment.crewai.com/kickoff \
|
||||
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"inputs": {"title": "Report"}, "input_files": {"document": "https://..."}}'
|
||||
```
|
||||
|
||||
<Note type="info">
|
||||
O upload de arquivos funciona da mesma forma tanto para crews quanto para flows. Defina campos tipados como arquivo no seu esquema de estado, e a interface da Plataforma e a API tratarão os uploads automaticamente.
|
||||
</Note>
|
||||
|
||||
### Verificando o Status do Crew
|
||||
|
||||
Antes de executar operações, você pode verificar se seu crew está funcionando corretamente:
|
||||
|
||||
@@ -207,9 +207,6 @@ O CrewAI AMP foi feito para equipes em produção. Além da implantação, você
|
||||
- **Factory (self-hosted)** — na sua infraestrutura para controle total dos dados
|
||||
- **Híbrido** — combine nuvem e self-hosted conforme a sensibilidade dos dados
|
||||
</Accordion>
|
||||
<Accordion title="Como funciona o preço?">
|
||||
Cadastre-se em [app.crewai.com](https://app.crewai.com) para ver os planos atuais. Preços enterprise e Factory sob consulta.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Card title="Conheça o CrewAI AMP →" icon="arrow-right" href="https://app.crewai.com">
|
||||
|
||||
@@ -112,7 +112,7 @@ github = [
|
||||
]
|
||||
rag = [
|
||||
"python-docx>=1.1.0",
|
||||
"lxml>=5.3.0,<5.4.0", # Pin to avoid etree import issues in 5.4.0
|
||||
"lxml>=6.1.0,<7", # 6.1.0+ required for GHSA-vfmq-68hx-4jfw (XXE in iterparse)
|
||||
]
|
||||
xml = [
|
||||
"unstructured[local-inference, all-docs]>=0.17.2"
|
||||
|
||||
@@ -78,8 +78,7 @@ from crewai.knowledge.knowledge import Knowledge
|
||||
from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
|
||||
from crewai.lite_agent_output import LiteAgentOutput
|
||||
from crewai.llms.base_llm import BaseLLM
|
||||
from crewai.mcp import MCPServerConfig
|
||||
from crewai.mcp.tool_resolver import MCPToolResolver
|
||||
from crewai.mcp.config import MCPServerConfig
|
||||
from crewai.rag.embeddings.types import EmbedderConfig
|
||||
from crewai.security.fingerprint import Fingerprint
|
||||
from crewai.skills.loader import activate_skill, discover_skills
|
||||
@@ -119,6 +118,7 @@ if TYPE_CHECKING:
|
||||
|
||||
from crewai.a2a.config import A2AClientConfig, A2AConfig, A2AServerConfig
|
||||
from crewai.agents.agent_builder.base_agent import PlatformAppOrAction
|
||||
from crewai.mcp.tool_resolver import MCPToolResolver
|
||||
from crewai.task import Task
|
||||
from crewai.tools.base_tool import BaseTool
|
||||
from crewai.tools.structured_tool import CrewStructuredTool
|
||||
@@ -1120,6 +1120,8 @@ class Agent(BaseAgent):
|
||||
Delegates to :class:`~crewai.mcp.tool_resolver.MCPToolResolver`.
|
||||
"""
|
||||
self._cleanup_mcp_clients()
|
||||
from crewai.mcp.tool_resolver import MCPToolResolver
|
||||
|
||||
self._mcp_resolver = MCPToolResolver(agent=self, logger=self._logger)
|
||||
return self._mcp_resolver.resolve(mcps)
|
||||
|
||||
|
||||
@@ -6,112 +6,20 @@ This module provides the event infrastructure that allows users to:
|
||||
- Build custom logging and analytics
|
||||
- Extend CrewAI with custom event handlers
|
||||
- Declare handler dependencies for ordered execution
|
||||
|
||||
Event type classes are lazy-loaded on first access to avoid importing
|
||||
~12 Pydantic model modules (and their transitive deps) at package init time.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from crewai.events.base_event_listener import BaseEventListener
|
||||
from crewai.events.depends import Depends
|
||||
from crewai.events.event_bus import crewai_event_bus
|
||||
from crewai.events.handler_graph import CircularDependencyError
|
||||
from crewai.events.types.crew_events import (
|
||||
CrewKickoffCompletedEvent,
|
||||
CrewKickoffFailedEvent,
|
||||
CrewKickoffStartedEvent,
|
||||
CrewTestCompletedEvent,
|
||||
CrewTestFailedEvent,
|
||||
CrewTestResultEvent,
|
||||
CrewTestStartedEvent,
|
||||
CrewTrainCompletedEvent,
|
||||
CrewTrainFailedEvent,
|
||||
CrewTrainStartedEvent,
|
||||
)
|
||||
from crewai.events.types.flow_events import (
|
||||
FlowCreatedEvent,
|
||||
FlowEvent,
|
||||
FlowFinishedEvent,
|
||||
FlowPlotEvent,
|
||||
FlowStartedEvent,
|
||||
HumanFeedbackReceivedEvent,
|
||||
HumanFeedbackRequestedEvent,
|
||||
MethodExecutionFailedEvent,
|
||||
MethodExecutionFinishedEvent,
|
||||
MethodExecutionStartedEvent,
|
||||
)
|
||||
from crewai.events.types.knowledge_events import (
|
||||
KnowledgeQueryCompletedEvent,
|
||||
KnowledgeQueryFailedEvent,
|
||||
KnowledgeQueryStartedEvent,
|
||||
KnowledgeRetrievalCompletedEvent,
|
||||
KnowledgeRetrievalStartedEvent,
|
||||
KnowledgeSearchQueryFailedEvent,
|
||||
)
|
||||
from crewai.events.types.llm_events import (
|
||||
LLMCallCompletedEvent,
|
||||
LLMCallFailedEvent,
|
||||
LLMCallStartedEvent,
|
||||
LLMStreamChunkEvent,
|
||||
)
|
||||
from crewai.events.types.llm_guardrail_events import (
|
||||
LLMGuardrailCompletedEvent,
|
||||
LLMGuardrailStartedEvent,
|
||||
)
|
||||
from crewai.events.types.logging_events import (
|
||||
AgentLogsExecutionEvent,
|
||||
AgentLogsStartedEvent,
|
||||
)
|
||||
from crewai.events.types.mcp_events import (
|
||||
MCPConfigFetchFailedEvent,
|
||||
MCPConnectionCompletedEvent,
|
||||
MCPConnectionFailedEvent,
|
||||
MCPConnectionStartedEvent,
|
||||
MCPToolExecutionCompletedEvent,
|
||||
MCPToolExecutionFailedEvent,
|
||||
MCPToolExecutionStartedEvent,
|
||||
)
|
||||
from crewai.events.types.memory_events import (
|
||||
MemoryQueryCompletedEvent,
|
||||
MemoryQueryFailedEvent,
|
||||
MemoryQueryStartedEvent,
|
||||
MemoryRetrievalCompletedEvent,
|
||||
MemoryRetrievalFailedEvent,
|
||||
MemoryRetrievalStartedEvent,
|
||||
MemorySaveCompletedEvent,
|
||||
MemorySaveFailedEvent,
|
||||
MemorySaveStartedEvent,
|
||||
)
|
||||
from crewai.events.types.reasoning_events import (
|
||||
AgentReasoningCompletedEvent,
|
||||
AgentReasoningFailedEvent,
|
||||
AgentReasoningStartedEvent,
|
||||
ReasoningEvent,
|
||||
)
|
||||
from crewai.events.types.skill_events import (
|
||||
SkillActivatedEvent,
|
||||
SkillDiscoveryCompletedEvent,
|
||||
SkillDiscoveryStartedEvent,
|
||||
SkillEvent,
|
||||
SkillLoadFailedEvent,
|
||||
SkillLoadedEvent,
|
||||
)
|
||||
from crewai.events.types.task_events import (
|
||||
TaskCompletedEvent,
|
||||
TaskEvaluationEvent,
|
||||
TaskFailedEvent,
|
||||
TaskStartedEvent,
|
||||
)
|
||||
from crewai.events.types.tool_usage_events import (
|
||||
ToolExecutionErrorEvent,
|
||||
ToolSelectionErrorEvent,
|
||||
ToolUsageErrorEvent,
|
||||
ToolUsageEvent,
|
||||
ToolUsageFinishedEvent,
|
||||
ToolUsageStartedEvent,
|
||||
ToolValidateInputErrorEvent,
|
||||
)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from crewai.events.types.agent_events import (
|
||||
@@ -125,6 +33,223 @@ if TYPE_CHECKING:
|
||||
LiteAgentExecutionErrorEvent,
|
||||
LiteAgentExecutionStartedEvent,
|
||||
)
|
||||
from crewai.events.types.crew_events import (
|
||||
CrewKickoffCompletedEvent,
|
||||
CrewKickoffFailedEvent,
|
||||
CrewKickoffStartedEvent,
|
||||
CrewTestCompletedEvent,
|
||||
CrewTestFailedEvent,
|
||||
CrewTestResultEvent,
|
||||
CrewTestStartedEvent,
|
||||
CrewTrainCompletedEvent,
|
||||
CrewTrainFailedEvent,
|
||||
CrewTrainStartedEvent,
|
||||
)
|
||||
from crewai.events.types.flow_events import (
|
||||
FlowCreatedEvent,
|
||||
FlowEvent,
|
||||
FlowFinishedEvent,
|
||||
FlowPlotEvent,
|
||||
FlowStartedEvent,
|
||||
HumanFeedbackReceivedEvent,
|
||||
HumanFeedbackRequestedEvent,
|
||||
MethodExecutionFailedEvent,
|
||||
MethodExecutionFinishedEvent,
|
||||
MethodExecutionStartedEvent,
|
||||
)
|
||||
from crewai.events.types.knowledge_events import (
|
||||
KnowledgeQueryCompletedEvent,
|
||||
KnowledgeQueryFailedEvent,
|
||||
KnowledgeQueryStartedEvent,
|
||||
KnowledgeRetrievalCompletedEvent,
|
||||
KnowledgeRetrievalStartedEvent,
|
||||
KnowledgeSearchQueryFailedEvent,
|
||||
)
|
||||
from crewai.events.types.llm_events import (
|
||||
LLMCallCompletedEvent,
|
||||
LLMCallFailedEvent,
|
||||
LLMCallStartedEvent,
|
||||
LLMStreamChunkEvent,
|
||||
)
|
||||
from crewai.events.types.llm_guardrail_events import (
|
||||
LLMGuardrailCompletedEvent,
|
||||
LLMGuardrailStartedEvent,
|
||||
)
|
||||
from crewai.events.types.logging_events import (
|
||||
AgentLogsExecutionEvent,
|
||||
AgentLogsStartedEvent,
|
||||
)
|
||||
from crewai.events.types.mcp_events import (
|
||||
MCPConfigFetchFailedEvent,
|
||||
MCPConnectionCompletedEvent,
|
||||
MCPConnectionFailedEvent,
|
||||
MCPConnectionStartedEvent,
|
||||
MCPToolExecutionCompletedEvent,
|
||||
MCPToolExecutionFailedEvent,
|
||||
MCPToolExecutionStartedEvent,
|
||||
)
|
||||
from crewai.events.types.memory_events import (
|
||||
MemoryQueryCompletedEvent,
|
||||
MemoryQueryFailedEvent,
|
||||
MemoryQueryStartedEvent,
|
||||
MemoryRetrievalCompletedEvent,
|
||||
MemoryRetrievalFailedEvent,
|
||||
MemoryRetrievalStartedEvent,
|
||||
MemorySaveCompletedEvent,
|
||||
MemorySaveFailedEvent,
|
||||
MemorySaveStartedEvent,
|
||||
)
|
||||
from crewai.events.types.reasoning_events import (
|
||||
AgentReasoningCompletedEvent,
|
||||
AgentReasoningFailedEvent,
|
||||
AgentReasoningStartedEvent,
|
||||
ReasoningEvent,
|
||||
)
|
||||
from crewai.events.types.skill_events import (
|
||||
SkillActivatedEvent,
|
||||
SkillDiscoveryCompletedEvent,
|
||||
SkillDiscoveryStartedEvent,
|
||||
SkillEvent,
|
||||
SkillLoadFailedEvent,
|
||||
SkillLoadedEvent,
|
||||
)
|
||||
from crewai.events.types.task_events import (
|
||||
TaskCompletedEvent,
|
||||
TaskEvaluationEvent,
|
||||
TaskFailedEvent,
|
||||
TaskStartedEvent,
|
||||
)
|
||||
from crewai.events.types.tool_usage_events import (
|
||||
ToolExecutionErrorEvent,
|
||||
ToolSelectionErrorEvent,
|
||||
ToolUsageErrorEvent,
|
||||
ToolUsageEvent,
|
||||
ToolUsageFinishedEvent,
|
||||
ToolUsageStartedEvent,
|
||||
ToolValidateInputErrorEvent,
|
||||
)
|
||||
|
||||
# Map every event class name → its module path for lazy loading
|
||||
_LAZY_EVENT_MAPPING: dict[str, str] = {
|
||||
# agent_events
|
||||
"AgentEvaluationCompletedEvent": "crewai.events.types.agent_events",
|
||||
"AgentEvaluationFailedEvent": "crewai.events.types.agent_events",
|
||||
"AgentEvaluationStartedEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionCompletedEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionErrorEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionStartedEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionCompletedEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionErrorEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionStartedEvent": "crewai.events.types.agent_events",
|
||||
# crew_events
|
||||
"CrewKickoffCompletedEvent": "crewai.events.types.crew_events",
|
||||
"CrewKickoffFailedEvent": "crewai.events.types.crew_events",
|
||||
"CrewKickoffStartedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTestCompletedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTestFailedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTestResultEvent": "crewai.events.types.crew_events",
|
||||
"CrewTestStartedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTrainCompletedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTrainFailedEvent": "crewai.events.types.crew_events",
|
||||
"CrewTrainStartedEvent": "crewai.events.types.crew_events",
|
||||
# flow_events
|
||||
"FlowCreatedEvent": "crewai.events.types.flow_events",
|
||||
"FlowEvent": "crewai.events.types.flow_events",
|
||||
"FlowFinishedEvent": "crewai.events.types.flow_events",
|
||||
"FlowPlotEvent": "crewai.events.types.flow_events",
|
||||
"FlowStartedEvent": "crewai.events.types.flow_events",
|
||||
"HumanFeedbackReceivedEvent": "crewai.events.types.flow_events",
|
||||
"HumanFeedbackRequestedEvent": "crewai.events.types.flow_events",
|
||||
"MethodExecutionFailedEvent": "crewai.events.types.flow_events",
|
||||
"MethodExecutionFinishedEvent": "crewai.events.types.flow_events",
|
||||
"MethodExecutionStartedEvent": "crewai.events.types.flow_events",
|
||||
# knowledge_events
|
||||
"KnowledgeQueryCompletedEvent": "crewai.events.types.knowledge_events",
|
||||
"KnowledgeQueryFailedEvent": "crewai.events.types.knowledge_events",
|
||||
"KnowledgeQueryStartedEvent": "crewai.events.types.knowledge_events",
|
||||
"KnowledgeRetrievalCompletedEvent": "crewai.events.types.knowledge_events",
|
||||
"KnowledgeRetrievalStartedEvent": "crewai.events.types.knowledge_events",
|
||||
"KnowledgeSearchQueryFailedEvent": "crewai.events.types.knowledge_events",
|
||||
# llm_events
|
||||
"LLMCallCompletedEvent": "crewai.events.types.llm_events",
|
||||
"LLMCallFailedEvent": "crewai.events.types.llm_events",
|
||||
"LLMCallStartedEvent": "crewai.events.types.llm_events",
|
||||
"LLMStreamChunkEvent": "crewai.events.types.llm_events",
|
||||
# llm_guardrail_events
|
||||
"LLMGuardrailCompletedEvent": "crewai.events.types.llm_guardrail_events",
|
||||
"LLMGuardrailStartedEvent": "crewai.events.types.llm_guardrail_events",
|
||||
# logging_events
|
||||
"AgentLogsExecutionEvent": "crewai.events.types.logging_events",
|
||||
"AgentLogsStartedEvent": "crewai.events.types.logging_events",
|
||||
# mcp_events
|
||||
"MCPConfigFetchFailedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPConnectionCompletedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPConnectionFailedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPConnectionStartedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPToolExecutionCompletedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPToolExecutionFailedEvent": "crewai.events.types.mcp_events",
|
||||
"MCPToolExecutionStartedEvent": "crewai.events.types.mcp_events",
|
||||
# memory_events
|
||||
"MemoryQueryCompletedEvent": "crewai.events.types.memory_events",
|
||||
"MemoryQueryFailedEvent": "crewai.events.types.memory_events",
|
||||
"MemoryQueryStartedEvent": "crewai.events.types.memory_events",
|
||||
"MemoryRetrievalCompletedEvent": "crewai.events.types.memory_events",
|
||||
"MemoryRetrievalFailedEvent": "crewai.events.types.memory_events",
|
||||
"MemoryRetrievalStartedEvent": "crewai.events.types.memory_events",
|
||||
"MemorySaveCompletedEvent": "crewai.events.types.memory_events",
|
||||
"MemorySaveFailedEvent": "crewai.events.types.memory_events",
|
||||
"MemorySaveStartedEvent": "crewai.events.types.memory_events",
|
||||
# reasoning_events
|
||||
"AgentReasoningCompletedEvent": "crewai.events.types.reasoning_events",
|
||||
"AgentReasoningFailedEvent": "crewai.events.types.reasoning_events",
|
||||
"AgentReasoningStartedEvent": "crewai.events.types.reasoning_events",
|
||||
"ReasoningEvent": "crewai.events.types.reasoning_events",
|
||||
# skill_events
|
||||
"SkillActivatedEvent": "crewai.events.types.skill_events",
|
||||
"SkillDiscoveryCompletedEvent": "crewai.events.types.skill_events",
|
||||
"SkillDiscoveryStartedEvent": "crewai.events.types.skill_events",
|
||||
"SkillEvent": "crewai.events.types.skill_events",
|
||||
"SkillLoadFailedEvent": "crewai.events.types.skill_events",
|
||||
"SkillLoadedEvent": "crewai.events.types.skill_events",
|
||||
# task_events
|
||||
"TaskCompletedEvent": "crewai.events.types.task_events",
|
||||
"TaskEvaluationEvent": "crewai.events.types.task_events",
|
||||
"TaskFailedEvent": "crewai.events.types.task_events",
|
||||
"TaskStartedEvent": "crewai.events.types.task_events",
|
||||
# tool_usage_events
|
||||
"ToolExecutionErrorEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolSelectionErrorEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolUsageErrorEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolUsageEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolUsageFinishedEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolUsageStartedEvent": "crewai.events.types.tool_usage_events",
|
||||
"ToolValidateInputErrorEvent": "crewai.events.types.tool_usage_events",
|
||||
}
|
||||
|
||||
_extension_exports: dict[str, Any] = {}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
"""Lazy import for event types and registered extensions."""
|
||||
if name in _LAZY_EVENT_MAPPING:
|
||||
module_path = _LAZY_EVENT_MAPPING[name]
|
||||
module = importlib.import_module(module_path)
|
||||
val = getattr(module, name)
|
||||
globals()[name] = val # cache for subsequent access
|
||||
return val
|
||||
|
||||
if name in _extension_exports:
|
||||
value = _extension_exports[name]
|
||||
if isinstance(value, str):
|
||||
module_path, _, attr_name = value.rpartition(".")
|
||||
if module_path:
|
||||
module = importlib.import_module(module_path)
|
||||
return getattr(module, attr_name)
|
||||
return importlib.import_module(value)
|
||||
return value
|
||||
|
||||
msg = f"module {__name__!r} has no attribute {name!r}"
|
||||
raise AttributeError(msg)
|
||||
|
||||
|
||||
__all__ = [
|
||||
@@ -214,42 +339,3 @@ __all__ = [
|
||||
"_extension_exports",
|
||||
"crewai_event_bus",
|
||||
]
|
||||
|
||||
_AGENT_EVENT_MAPPING = {
|
||||
"AgentEvaluationCompletedEvent": "crewai.events.types.agent_events",
|
||||
"AgentEvaluationFailedEvent": "crewai.events.types.agent_events",
|
||||
"AgentEvaluationStartedEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionCompletedEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionErrorEvent": "crewai.events.types.agent_events",
|
||||
"AgentExecutionStartedEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionCompletedEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionErrorEvent": "crewai.events.types.agent_events",
|
||||
"LiteAgentExecutionStartedEvent": "crewai.events.types.agent_events",
|
||||
}
|
||||
|
||||
_extension_exports: dict[str, Any] = {}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
"""Lazy import for agent events and registered extensions."""
|
||||
if name in _AGENT_EVENT_MAPPING:
|
||||
import importlib
|
||||
|
||||
module_path = _AGENT_EVENT_MAPPING[name]
|
||||
module = importlib.import_module(module_path)
|
||||
return getattr(module, name)
|
||||
|
||||
if name in _extension_exports:
|
||||
import importlib
|
||||
|
||||
value = _extension_exports[name]
|
||||
if isinstance(value, str):
|
||||
module_path, _, attr_name = value.rpartition(".")
|
||||
if module_path:
|
||||
module = importlib.import_module(module_path)
|
||||
return getattr(module, attr_name)
|
||||
return importlib.import_module(value)
|
||||
return value
|
||||
|
||||
msg = f"module {__name__!r} has no attribute {name!r}"
|
||||
raise AttributeError(msg)
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
|
||||
This module provides native MCP client functionality, allowing CrewAI agents
|
||||
to connect to any MCP-compliant server using various transport types.
|
||||
|
||||
Heavy imports (MCPClient, MCPToolResolver, BaseTransport, TransportType) are
|
||||
lazy-loaded on first access to avoid pulling in the ``mcp`` SDK (~400ms)
|
||||
when only lightweight config/filter types are needed.
|
||||
"""
|
||||
|
||||
from crewai.mcp.client import MCPClient
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from crewai.mcp.config import (
|
||||
MCPServerConfig,
|
||||
MCPServerHTTP,
|
||||
@@ -18,8 +26,28 @@ from crewai.mcp.filters import (
|
||||
create_dynamic_tool_filter,
|
||||
create_static_tool_filter,
|
||||
)
|
||||
from crewai.mcp.tool_resolver import MCPToolResolver
|
||||
from crewai.mcp.transports.base import BaseTransport, TransportType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from crewai.mcp.client import MCPClient
|
||||
from crewai.mcp.tool_resolver import MCPToolResolver
|
||||
from crewai.mcp.transports.base import BaseTransport, TransportType
|
||||
|
||||
_LAZY: dict[str, tuple[str, str]] = {
|
||||
"MCPClient": ("crewai.mcp.client", "MCPClient"),
|
||||
"MCPToolResolver": ("crewai.mcp.tool_resolver", "MCPToolResolver"),
|
||||
"BaseTransport": ("crewai.mcp.transports.base", "BaseTransport"),
|
||||
"TransportType": ("crewai.mcp.transports.base", "TransportType"),
|
||||
}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
if name in _LAZY:
|
||||
mod_path, attr = _LAZY[name]
|
||||
mod = importlib.import_module(mod_path)
|
||||
val = getattr(mod, attr)
|
||||
globals()[name] = val # cache for subsequent access
|
||||
return val
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -164,7 +164,7 @@ info = "Commits must follow Conventional Commits 1.0.0."
|
||||
[tool.uv]
|
||||
# Pinned to include the security patch releases (authlib 1.6.11,
|
||||
# langchain-text-splitters 1.1.2) uploaded on 2026-04-16.
|
||||
exclude-newer = "2026-04-17"
|
||||
exclude-newer = "2026-04-22"
|
||||
|
||||
# composio-core pins rich<14 but textual requires rich>=14.
|
||||
# onnxruntime 1.24+ dropped Python 3.10 wheels; cap it so qdrant[fastembed] resolves on 3.10.
|
||||
|
||||
76
scripts/benchmark_import_time.py
Executable file
76
scripts/benchmark_import_time.py
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Benchmark `import crewai` cold start time.
|
||||
|
||||
Usage:
|
||||
python scripts/benchmark_import_time.py [--runs N] [--json]
|
||||
|
||||
Spawns a fresh Python subprocess for each run to ensure cold imports.
|
||||
Prints median, mean, min, max across all runs.
|
||||
With --json, outputs machine-readable results for CI.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import statistics
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
IMPORT_SCRIPT = "import time; t0 = time.perf_counter(); import crewai; print(time.perf_counter() - t0)"
|
||||
|
||||
|
||||
def measure_import(python: str = sys.executable) -> float:
|
||||
"""Run a single cold-import measurement in a subprocess."""
|
||||
result = subprocess.run(
|
||||
[python, "-c", IMPORT_SCRIPT],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env={"PATH": "", "VIRTUAL_ENV": "", "PYTHONPATH": ""},
|
||||
timeout=30,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"Import failed: {result.stderr.strip()}")
|
||||
return float(result.stdout.strip())
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Benchmark crewai import time")
|
||||
parser.add_argument("--runs", type=int, default=5, help="Number of runs (default: 5)")
|
||||
parser.add_argument("--json", action="store_true", help="Output JSON for CI")
|
||||
parser.add_argument("--threshold", type=float, default=None,
|
||||
help="Fail if median exceeds this value (seconds)")
|
||||
args = parser.parse_args()
|
||||
|
||||
times = []
|
||||
for i in range(args.runs):
|
||||
t = measure_import()
|
||||
times.append(t)
|
||||
if not args.json:
|
||||
print(f" Run {i + 1}: {t:.3f}s")
|
||||
|
||||
median = statistics.median(times)
|
||||
mean = statistics.mean(times)
|
||||
stdev = statistics.stdev(times) if len(times) > 1 else 0.0
|
||||
|
||||
result = {
|
||||
"runs": args.runs,
|
||||
"median_s": round(median, 3),
|
||||
"mean_s": round(mean, 3),
|
||||
"stdev_s": round(stdev, 3),
|
||||
"min_s": round(min(times), 3),
|
||||
"max_s": round(max(times), 3),
|
||||
}
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(result))
|
||||
else:
|
||||
print(f"\n Median: {median:.3f}s")
|
||||
print(f" Mean: {mean:.3f}s ± {stdev:.3f}s")
|
||||
print(f" Range: {min(times):.3f}s – {max(times):.3f}s")
|
||||
|
||||
if args.threshold and median > args.threshold:
|
||||
print(f"\n ❌ FAILED: median {median:.3f}s exceeds threshold {args.threshold:.3f}s")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user