Compare commits
6 Commits
1.15.4
...
docs/cor-3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8d70afa6f | ||
|
|
db35033294 | ||
|
|
1fa3b75425 | ||
|
|
f4e4662421 | ||
|
|
cb18653c8b | ||
|
|
3f5ca89edc |
3
.github/workflows/docs-broken-links.yml
vendored
@@ -13,9 +13,6 @@ on:
|
||||
- "docs.json"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check-links:
|
||||
name: Check broken links
|
||||
|
||||
55
.github/workflows/vulnerability-scan.yml
vendored
@@ -47,20 +47,46 @@ jobs:
|
||||
|
||||
- name: Run pip-audit
|
||||
run: |
|
||||
pip_audit_args=(
|
||||
--desc
|
||||
--aliases
|
||||
--skip-editable
|
||||
--format json
|
||||
--output pip-audit-report.json
|
||||
--ignore-vuln CVE-2026-27448 # pyOpenSSL: fixes require 26.0.0, blocked by snowflake-connector-python 3.x.
|
||||
--ignore-vuln CVE-2026-27459 # pyOpenSSL: same constraint as CVE-2026-27448.
|
||||
--ignore-vuln PYSEC-2026-597 # nltk 3.9.4 (CVE-2026-12243): no fix available, transitive through crewai-tools[xml] -> unstructured.
|
||||
--ignore-vuln GHSA-rrmf-rvhw-rf47 # torch 2.12.0 (CVE-2025-3000): local-only memory corruption in torch.jit.script; no fix available.
|
||||
--ignore-vuln GHSA-f4j7-r4q5-qw2c # chromadb 1.1.1 (CVE-2026-45829): pre-auth RCE in the HTTP server; no fix available.
|
||||
--ignore-vuln GHSA-xf7x-x43h-rpqh # json-repair 0.25.3: the affected schema module is absent, and CrewAI does not pass schemas.
|
||||
)
|
||||
uv run pip-audit "${pip_audit_args[@]}"
|
||||
uv run pip-audit --desc --aliases --skip-editable --format json --output pip-audit-report.json \
|
||||
--ignore-vuln PYSEC-2024-277 \
|
||||
--ignore-vuln PYSEC-2026-89 \
|
||||
--ignore-vuln PYSEC-2026-97 \
|
||||
--ignore-vuln PYSEC-2025-148 \
|
||||
--ignore-vuln PYSEC-2025-183 \
|
||||
--ignore-vuln PYSEC-2025-189 \
|
||||
--ignore-vuln PYSEC-2025-190 \
|
||||
--ignore-vuln PYSEC-2025-191 \
|
||||
--ignore-vuln PYSEC-2025-192 \
|
||||
--ignore-vuln PYSEC-2025-193 \
|
||||
--ignore-vuln PYSEC-2025-194 \
|
||||
--ignore-vuln PYSEC-2025-195 \
|
||||
--ignore-vuln PYSEC-2025-196 \
|
||||
--ignore-vuln PYSEC-2025-197 \
|
||||
--ignore-vuln PYSEC-2025-210 \
|
||||
--ignore-vuln PYSEC-2026-139 \
|
||||
--ignore-vuln GHSA-rrmf-rvhw-rf47 \
|
||||
--ignore-vuln PYSEC-2025-211 \
|
||||
--ignore-vuln PYSEC-2025-212 \
|
||||
--ignore-vuln PYSEC-2025-213 \
|
||||
--ignore-vuln PYSEC-2025-214 \
|
||||
--ignore-vuln PYSEC-2025-215 \
|
||||
--ignore-vuln PYSEC-2025-216 \
|
||||
--ignore-vuln PYSEC-2025-217 \
|
||||
--ignore-vuln PYSEC-2025-218 \
|
||||
--ignore-vuln GHSA-f4j7-r4q5-qw2c
|
||||
# Ignored CVEs:
|
||||
# PYSEC-2024-277 - joblib 1.5.3: disputed; NumpyArrayWrapper only used with trusted caches
|
||||
# PYSEC-2026-89 - markdown 3.10.2: DoS via malformed HTML; fix 3.8.1 — already past, advisory range is stale
|
||||
# PYSEC-2026-97 - nltk 3.9.4: arbitrary file read in filestring(); no fix available
|
||||
# PYSEC-2025-148 - onnx 1.21.0: path traversal in save_external_data; no fix available
|
||||
# PYSEC-2025-183 - pyjwt 2.12.1: disputed weak-encryption claim; key length is application-chosen
|
||||
# PYSEC-2025-189..197 - torch 2.11.0: memory-corruption/DoS in functions only reachable via untrusted models; no fix available
|
||||
# PYSEC-2025-210, PYSEC-2026-139 - torch 2.11.0: profiler/deserialization issues; no fix available
|
||||
# GHSA-rrmf-rvhw-rf47 - torch 2.11.0 (CVE-2025-3000, alias of PYSEC-2025-194): memory corruption in torch.jit.script, CVSS 1.9, local-only; affected <=2.12.0, no fix available. pip-audit reports it under the GHSA id so the PYSEC ignore above does not catch it.
|
||||
# PYSEC-2025-211..218 - transformers 5.5.4: deserialization/code injection via malicious model checkpoints; no fix available
|
||||
# GHSA-f4j7-r4q5-qw2c - chromadb 1.1.1 (CVE-2026-45829): pre-auth RCE via /api/v2/tenants/{tenant}/databases/{db}/collections when trust_remote_code=true.
|
||||
# Advisory: vulnerable >=1.0.0,<=1.5.9, firstPatchedVersion=none. We only use chromadb.PersistentClient (lib/crewai/src/crewai/rag/chromadb/factory.py)
|
||||
# and chromadb.utils.embedding_functions; the chromadb HTTP server is never started, so the vulnerable route is not exposed.
|
||||
continue-on-error: true
|
||||
|
||||
- name: Display results
|
||||
@@ -106,3 +132,4 @@ jobs:
|
||||
~/.local/share/uv
|
||||
.venv
|
||||
key: uv-main-py3.11-${{ hashFiles('uv.lock') }}
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ repos:
|
||||
--ignore-vuln PYSEC-2024-277
|
||||
--ignore-vuln PYSEC-2026-89
|
||||
--ignore-vuln PYSEC-2026-97
|
||||
--ignore-vuln PYSEC-2026-597
|
||||
--ignore-vuln PYSEC-2025-148
|
||||
--ignore-vuln PYSEC-2025-183
|
||||
--ignore-vuln PYSEC-2025-189
|
||||
|
||||
158
AGENTS.md
@@ -1,26 +1,142 @@
|
||||
# Agent Instructions for CrewAI OSS
|
||||
# Docs contributor guide
|
||||
|
||||
CrewAI is a Python based framework for building AI agents and agentic systems.
|
||||
Follow these guidelines when contributing:
|
||||
The `docs/` directory is published at [docs.crewai.com](https://docs.crewai.com)
|
||||
by [Mintlify](https://www.mintlify.com/). Mintlify watches `docs/docs.json`
|
||||
and the MDX files referenced from it.
|
||||
|
||||
## Key Guidelines
|
||||
## TL;DR for editing docs
|
||||
|
||||
1. Follow Python best practices and idiomatic patterns.
|
||||
2. Maintain existing code structure and organization.
|
||||
3. Write unit tests for new functionality focusing on behaivor and not
|
||||
implementation.
|
||||
4. Document public APIs and complex logic.
|
||||
5. Suggest changes to the `docs/` folder when appropriate
|
||||
6. Follow software principles such as DRY and YAGNI.
|
||||
7. Keep diffs as minimal as possible.
|
||||
- Edit MDX under `docs/edge/<lang>/...` (e.g. `docs/edge/en/concepts/agents.mdx`).
|
||||
- Your change ships under the **Edge** version selector the moment it merges
|
||||
to `main`. Edge follows `main` and is the channel for unreleased work.
|
||||
- On release cut, the current Edge state is frozen into `docs/v<X.Y.Z>/` and
|
||||
that snapshot becomes the new default version in the selector (tag:
|
||||
`Latest`). Canonical URLs (`/<lang>/...`) auto-redirect to the new default.
|
||||
- Never modify files under `docs/v*/`. Those are frozen release snapshots
|
||||
and the `docs-snapshots` CI guard rejects writes. The only exception is a
|
||||
release-cut PR (auto-generated by `devtools release` or the manual
|
||||
`scripts/docs/freeze_current_edge.py` wrapper), which uses a
|
||||
`[docs-freeze]` title prefix to opt out.
|
||||
- Never delete or rename files under `docs/images/`. Images are append-only.
|
||||
See [Images](#images) below.
|
||||
|
||||
## Changing Docs
|
||||
## The version model
|
||||
|
||||
1. Edit MDX under `docs/edge/en/*` and reference it from `docs/docs.json` if
|
||||
needed.
|
||||
2. Do not modify files under `docs/v*/`. Those are frozen release snapshots
|
||||
managed by devtools.
|
||||
3. Do not delete or rename files under `docs/images/` as frozen snapshots
|
||||
may reference them.
|
||||
4. If you want to preview your changes locally, use `cd docs && mintlify dev`.
|
||||
To check for broken links, run `cd docs && mintlify broken-links`.
|
||||
The site has one rolling channel (Edge) plus one frozen snapshot per
|
||||
release.
|
||||
|
||||
```
|
||||
docs/
|
||||
edge/ <-- Edge sources (you edit here)
|
||||
en/...
|
||||
pt-BR/ ko/ ar/
|
||||
enterprise-api.*.yaml
|
||||
|
||||
v1.14.7/ <-- frozen snapshot of v1.14.7
|
||||
en/...
|
||||
pt-BR/ ko/ ar/
|
||||
enterprise-api.*.yaml
|
||||
v1.14.6/...
|
||||
...
|
||||
|
||||
images/ <-- shared, append-only
|
||||
docs.json <-- Mintlify config: navigation + redirects
|
||||
```
|
||||
|
||||
`docs/docs.json` lists one navigation block per version per language. Edge
|
||||
points at `docs/edge/<lang>/...`; every other version points at its own
|
||||
`docs/v<X.Y.Z>/<lang>/...` subtree. Mintlify scopes both the sidebar and the
|
||||
in-site search to whichever version the reader selects, so picking
|
||||
`v1.10.0` genuinely shows the v1.10.0 docs (and only those).
|
||||
|
||||
### URLs and canonical redirects
|
||||
|
||||
Each Mintlify version corresponds to its own URL prefix:
|
||||
|
||||
- Edge: `/edge/<lang>/<page>` (e.g. `/edge/en/concepts/agents`)
|
||||
- Frozen: `/v<X.Y.Z>/<lang>/<page>` (e.g. `/v1.14.7/en/concepts/agents`)
|
||||
|
||||
External links to the old, unversioned `/<lang>/<page>` URLs would 404 under
|
||||
this layout. To keep them working, `docs.json` ships wildcard redirects:
|
||||
|
||||
```jsonc
|
||||
{ "source": "/en/:slug*", "destination": "/v1.14.7/en/:slug*", "permanent": false }
|
||||
```
|
||||
|
||||
The release-cut step rewrites the destination on every release so canonical
|
||||
`/<lang>/...` URLs always resolve to the latest stable docs.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
1. **During development.** You add or edit pages under
|
||||
`docs/edge/<lang>/...` in normal PRs. They land in Edge as soon as the PR
|
||||
merges. Both `/edge/<lang>/<page>` and the version selector's `Edge` entry
|
||||
reflect the change immediately.
|
||||
2. **Release cut.** The release engineer runs `devtools release X.Y.Z`. As
|
||||
part of that flow the CLI opens a `[docs-freeze]` PR that copies Edge into
|
||||
`docs/v<X.Y.Z>/`, rewrites internal OpenAPI references, updates
|
||||
`docs/docs.json` to make `v<X.Y.Z>` the new default + `Latest`, and rewires
|
||||
the canonical-URL redirects to the new default. The PR must merge before
|
||||
the tag and PyPI publish run.
|
||||
3. **After release.** Edge keeps rolling. Patch fixes to the just-released
|
||||
docs go into Edge and ship with the next release. We do not back-edit
|
||||
frozen snapshots.
|
||||
|
||||
See [`RELEASING.md`](RELEASING.md) for the full release runbook.
|
||||
|
||||
## Images
|
||||
|
||||
Snapshots share a single `docs/images/` directory. If an image is deleted
|
||||
or renamed, every frozen snapshot that referenced it breaks. So the rule
|
||||
is:
|
||||
|
||||
- Adding new images is always fine.
|
||||
- Deleting or renaming an existing image fails CI unless the PR is a
|
||||
`[docs-freeze]` release-cut PR.
|
||||
- If an asset is wrong, add a new file with a new name and reference the
|
||||
new name in the Edge MDX (`docs/edge/<lang>/...`). Leave the old file
|
||||
alone.
|
||||
|
||||
## Local preview
|
||||
|
||||
Install the Mintlify CLI and run from `docs/`:
|
||||
|
||||
```bash
|
||||
npm i -g mintlify
|
||||
mintlify dev
|
||||
```
|
||||
|
||||
Use the version selector at the top of the rendered page to switch between
|
||||
Edge and frozen versions.
|
||||
|
||||
To check links across every version:
|
||||
|
||||
```bash
|
||||
mintlify broken-links
|
||||
```
|
||||
|
||||
CI runs the broken-links check on every PR that touches `docs/**` via
|
||||
[`.github/workflows/docs-broken-links.yml`](.github/workflows/docs-broken-links.yml).
|
||||
|
||||
## Scripts
|
||||
|
||||
- `scripts/docs/freeze_historical_versions.py` — one-time migration that
|
||||
reconstructed `docs/v1.10.0/` through `docs/v1.14.7/` from git tags. You
|
||||
should not need to run this again.
|
||||
- `scripts/docs/prefix_version_paths.py` — one-time migration that switched
|
||||
`docs/docs.json` to directory-based versioning, inserted Edge, and added
|
||||
the canonical-URL redirects. You should not need to run this again.
|
||||
- `scripts/docs/freeze_current_edge.py` — thin CLI wrapper around
|
||||
`crewai_devtools.docs_versioning.freeze`. `devtools release` calls the
|
||||
same module during its docs PR step; this script is the manual escape
|
||||
hatch (e.g. retroactively freezing a forgotten release).
|
||||
|
||||
## CI guards
|
||||
|
||||
- [`.github/workflows/docs-snapshots.yml`](.github/workflows/docs-snapshots.yml)
|
||||
enforces the two rules above (frozen snapshots immutable, images
|
||||
append-only). Both checks accept the `[docs-freeze]` PR-title escape
|
||||
hatch.
|
||||
- [`.github/workflows/docs-broken-links.yml`](.github/workflows/docs-broken-links.yml)
|
||||
runs `mintlify broken-links` against the whole site, so adding a new
|
||||
page or moving a snapshot file that breaks a link will fail CI.
|
||||
|
||||
80
README.md
@@ -12,8 +12,6 @@
|
||||
<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>
|
||||
@@ -55,20 +53,20 @@
|
||||
|
||||
### Fast and Flexible Multi-Agent Automation Framework
|
||||
|
||||
> 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 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 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.
|
||||
- **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
|
||||
|
||||
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 production-ready agentic automation.
|
||||
standard for enterprise-ready AI automation.
|
||||
|
||||
# CrewAI AMP Suite
|
||||
|
||||
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.
|
||||
CrewAI AMP Suite is a comprehensive bundle tailored for organizations that require secure, scalable, and easy-to-manage agent-driven automation.
|
||||
|
||||
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:
|
||||
|
||||
@@ -90,6 +88,7 @@ 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)
|
||||
@@ -97,11 +96,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)
|
||||
- [When to Use CrewAI](#when-to-use-crewai)
|
||||
- [How CrewAI Compares](#how-crewai-compares)
|
||||
- [Frequently Asked Questions (FAQ)](#frequently-asked-questions-faq)
|
||||
- [Contribution](#contribution)
|
||||
- [Telemetry](#telemetry)
|
||||
- [License](#license)
|
||||
- [Frequently Asked Questions (FAQ)](#frequently-asked-questions-faq)
|
||||
|
||||
## Build with AI
|
||||
|
||||
@@ -135,15 +134,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 speed, flexibility, and control through Crews of AI agents and event-driven Flows:
|
||||
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:
|
||||
|
||||
- **Purpose-built architecture**: Designed specifically for agent orchestration, with a lightweight Python core and clean primitives for real-world automation.
|
||||
- **Standalone Framework**: Built from scratch, independent of LangChain or any other agent framework.
|
||||
- **High Performance**: Optimized for speed and minimal resource usage, enabling faster execution.
|
||||
- **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.
|
||||
- **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.
|
||||
- **Robust Community**: Backed by a rapidly growing community of over **100,000 certified** developers offering comprehensive support and resources.
|
||||
|
||||
CrewAI empowers developers and teams to build intelligent automations that balance simplicity, flexibility, and production-grade control.
|
||||
CrewAI empowers developers and enterprises to confidently build intelligent automations, bridging the gap between simplicity, flexibility, and performance.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -434,17 +433,16 @@ In addition to the sequential process, you can use the hierarchical process, whi
|
||||
|
||||
## Key Features
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
- **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.
|
||||
- **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.
|
||||
|
||||
Choose CrewAI to build powerful, adaptable, and production-ready AI automations.
|
||||
Choose CrewAI to easily build powerful, adaptable, and production-ready AI automations.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -582,17 +580,16 @@ 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.
|
||||
|
||||
## When to Use CrewAI
|
||||
## How CrewAI Compares
|
||||
|
||||
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.
|
||||
**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.
|
||||
|
||||
CrewAI is especially useful when you want to:
|
||||
- **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.
|
||||
|
||||
- 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.
|
||||
_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.
|
||||
|
||||
## Contribution
|
||||
|
||||
@@ -701,7 +698,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)
|
||||
- [Is CrewAI a standalone framework?](#q-is-crewai-a-standalone-framework)
|
||||
- [Does CrewAI depend on LangChain?](#q-does-crewai-depend-on-langchain)
|
||||
- [Is CrewAI open-source?](#q-is-crewai-open-source)
|
||||
- [Does CrewAI collect data from users?](#q-does-crewai-collect-data-from-users)
|
||||
|
||||
@@ -710,6 +707,7 @@ 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
|
||||
@@ -725,7 +723,7 @@ CrewAI is released under the [MIT License](https://github.com/crewAIInc/crewAI/b
|
||||
|
||||
### Q: What exactly is CrewAI?
|
||||
|
||||
A: CrewAI is a lean, fast Python framework built specifically for orchestrating autonomous AI agents and production-ready agentic workflows.
|
||||
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.
|
||||
|
||||
### Q: How do I install CrewAI?
|
||||
|
||||
@@ -741,9 +739,9 @@ For additional tools, use:
|
||||
uv pip install 'crewai[tools]'
|
||||
```
|
||||
|
||||
### Q: Is CrewAI a standalone framework?
|
||||
### Q: Does CrewAI depend on LangChain?
|
||||
|
||||
A: Yes. CrewAI is a standalone Python framework with its own primitives for agents, tasks, crews, flows, tools, and orchestration.
|
||||
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.
|
||||
|
||||
### Q: Can CrewAI handle complex use cases?
|
||||
|
||||
@@ -757,6 +755,10 @@ 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.
|
||||
@@ -795,11 +797,11 @@ A: Absolutely! CrewAI agents can easily integrate with external tools, APIs, and
|
||||
|
||||
### Q: Is CrewAI suitable for production environments?
|
||||
|
||||
A: Yes, CrewAI is designed with production-grade patterns that support reliable, stable, and scalable agentic workflows.
|
||||
A: Yes, CrewAI is explicitly designed with production-grade standards, ensuring reliability, stability, and scalability for enterprise deployments.
|
||||
|
||||
### Q: How scalable is CrewAI?
|
||||
|
||||
A: CrewAI is highly scalable, supporting simple automations and large-scale workflows involving numerous agents and complex tasks simultaneously.
|
||||
A: CrewAI is highly scalable, supporting simple automations and large-scale enterprise workflows involving numerous agents and complex tasks simultaneously.
|
||||
|
||||
### Q: Does CrewAI offer debugging and monitoring tools?
|
||||
|
||||
|
||||
10667
docs/docs.json
19
docs/edge/api/v1/platform-api/introduction.mdx
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "Platform API"
|
||||
description: "Build against the supported CrewAI Platform public API."
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
# CrewAI Platform API
|
||||
|
||||
The Platform API is the supported public API for CrewAI Platform. Use it when
|
||||
you need stable HTTP contracts for automation, integrations, and agent-facing
|
||||
workflows.
|
||||
|
||||
The current public contract is `v1`. Endpoints live under `/api/v1` on the
|
||||
CrewAI Platform app host:
|
||||
|
||||
```text
|
||||
https://app.crewai.com/api/v1
|
||||
```
|
||||
13
docs/edge/api/v1/problems.mdx
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "Problems"
|
||||
description: "Error responses returned by the CrewAI Platform API."
|
||||
---
|
||||
|
||||
# Problems
|
||||
|
||||
When a request fails, the Platform API returns an `errors` array. Each item
|
||||
includes a stable `code`, an HTTP `status`, and a `detail` message with
|
||||
request-specific context.
|
||||
|
||||
Use the pages in this section to understand what each error code means and what
|
||||
to change before retrying.
|
||||
17
docs/edge/api/v1/problems/bad_request.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: bad_request
|
||||
title: Bad request
|
||||
status: 400
|
||||
---
|
||||
|
||||
# Bad request
|
||||
|
||||
The request could not be processed because it was malformed or missing required request data.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This usually means the request body, query string, headers, or required parameters are invalid before endpoint-specific validation can run.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Review the endpoint contract, required parameters, request body shape, and content type before retrying.
|
||||
17
docs/edge/api/v1/problems/internal_error.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: internal_error
|
||||
title: Internal error
|
||||
status: 500
|
||||
---
|
||||
|
||||
# Internal error
|
||||
|
||||
An unexpected server-side failure prevented the request from completing.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This means the platform encountered an unexpected condition while processing a valid request.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Retry the request after a short delay. If the problem continues, contact support with the request details and timestamp.
|
||||
17
docs/edge/api/v1/problems/not_found.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: not_found
|
||||
title: Not found
|
||||
status: 404
|
||||
---
|
||||
|
||||
# Not found
|
||||
|
||||
The requested resource does not exist or is not available at the requested path.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This can happen when the URL is incorrect, the resource identifier does not exist, or the resource is not visible through the public API.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Check the endpoint path and resource identifier, then retry with a resource that exists and is available to the request.
|
||||
17
docs/edge/api/v1/problems/validation_error.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: validation_error
|
||||
title: Validation error
|
||||
status: 422
|
||||
---
|
||||
|
||||
# Validation error
|
||||
|
||||
The request was understood, but one or more submitted values failed validation.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This usually means a submitted field is missing, malformed, out of range, duplicated, or conflicts with another value.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Inspect the `detail` message for the field-specific issue, update the submitted values, and retry the request.
|
||||
@@ -4,396 +4,6 @@ description: "تحديثات المنتج والتحسينات وإصلاحات
|
||||
icon: "clock"
|
||||
mode: "wide"
|
||||
---
|
||||
<Update label="17 يوليو 2026">
|
||||
## v1.15.4
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.4)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- ترقية مستودع المهارات من حالة تجريبية
|
||||
|
||||
### الوثائق
|
||||
- إضافة تدفقات في وثائق الاستوديو
|
||||
|
||||
## المساهمون
|
||||
|
||||
@jessemiller, @joaomdmoura, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 يوليو 2026">
|
||||
## v1.15.3
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- إضافة معلمة معرف المنظمة إلى عميل PlusAPI
|
||||
- إضافة نقاط اعتراض الخطوات وإعادة صياغة توثيق نقاط تنفيذ @on
|
||||
- توصيل نقاط اعتراض حدود التنفيذ
|
||||
- إضافة موزع اعتراض عام
|
||||
- تشغيل التدفقات التصريحية على واجهة المستخدم النصية (خيار الطرية بدون واجهة)
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- مزامنة حدث بدء التنفيذ المكتمل مع نتيجة خطاف OUTPUT
|
||||
- إصلاح سمات وكيل المستودع الفارغة
|
||||
- التأكد من أن خطافات after_llm_call لا تكسر تنفيذ الأدوات الأصلية
|
||||
- تجنب الإضافة المزدوجة لرد الدور عندما يقوم المعالج بقص التاريخ
|
||||
- جعل تخزين نتائج الأدوات اختيارياً بدلاً من أن يكون مفعلًا بشكل افتراضي
|
||||
- التوقف عن إعادة كتابة وصف الأداة المؤلف عند الإنشاء
|
||||
- كشف استخدام الرموز تحت كلا الاسمين في نتائج الوكيل والطاقم
|
||||
- الإبلاغ عن مقاييس الاستخدام لكل استدعاء في نتائج بدء التنفيذ
|
||||
- التوقف عن إعادة تشغيل نية الدور السابق عندما تعيد route_turn() قيمة غير صحيحة
|
||||
|
||||
### الوثائق
|
||||
- تحديث تجميع خطافات التنفيذ وتوثيق جميع سياقات الخطاف
|
||||
|
||||
## المساهمون
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 يوليو 2026">
|
||||
## v1.15.3a2
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a2)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح تزامن حدث انتهاء الانطلاق مع نتيجة خطاف OUTPUT
|
||||
|
||||
### الوثائق
|
||||
- تحديث لقطة الشاشة وسجل التغييرات للإصدار v1.15.3a1
|
||||
|
||||
### تحديثات التبعية
|
||||
- رفع setuptools إلى 0.83.0 لمعالجة PYSEC-2026-3447
|
||||
|
||||
## المساهمون
|
||||
|
||||
@lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 يوليو 2026">
|
||||
## v1.15.3a1
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a1)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- إضافة معلمة معرف المنظمة إلى عميل PlusAPI.
|
||||
- إضافة نقاط اعتراض الخطوات وإعادة صياغة وثائق نقاط تنفيذ `@on`.
|
||||
- توصيل نقاط اعتراض حدود التنفيذ.
|
||||
- إضافة موصل عام للاعتراضات.
|
||||
- تشغيل التدفقات التصريحية على واجهة المستخدم النصية (نسخة احتياطية من الطرفية بدون واجهة).
|
||||
- تحسين عناوين URL المخصصة لـ OpenAI.
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح سمات وكيل المستودع الفارغة.
|
||||
- إصلاح نقاط `after_llm_call` لمنع كسر تنفيذ الأدوات الأصلية.
|
||||
- إيقاف الإضافة المزدوجة لرد الدور عندما يقوم المعالج بقص التاريخ.
|
||||
- جعل تخزين نتائج الأدوات اختيارياً بدلاً من أن يكون مفعلًا بشكل افتراضي.
|
||||
- إيقاف إعادة كتابة وصف الأداة المؤلف عند الإنشاء.
|
||||
- كشف استخدام الرموز تحت كلا الاسمين في نتائج الوكيل والطاقم.
|
||||
- الإبلاغ عن مقاييس الاستخدام لكل استدعاء في نتائج البداية.
|
||||
- إيقاف إعادة تشغيل نية الدور السابق عندما تعيد `route_turn()` قيمة غير صحيحة.
|
||||
- تصريف الكتابات في الذاكرة قبل أحداث البداية وإكمال التدفق.
|
||||
|
||||
### الوثائق
|
||||
- تجميع نقاط تنفيذ الوثائق وتوثيق جميع سياقات الاعتراض.
|
||||
- تحديث الوثائق لنقاط تنفيذ الاعتراض.
|
||||
|
||||
## المساهمون
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="7 يوليو 2026">
|
||||
## v1.15.2
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- سحب أحدث نماذج LLM ديناميكيًا في معالج الطاقم.
|
||||
- دعم تعريفات المهارات المضمنة.
|
||||
- إضافة مهارة تأليف تعريف التدفق المُولد.
|
||||
- دعم مدخلات إجراءات التدفق المهيكلة.
|
||||
- إضافة مساعد نصي لمطالبات CEL للتدفق.
|
||||
- إضافة مساعد نصي لمثال مهارة التدفق.
|
||||
- تنفيذ إعداد الرسائل ومعالجة التعليقات في AgentExecutor.
|
||||
- إضافة وكلاء المستودع إلى تعريفات التدفق.
|
||||
- تعريف بروتوكول إطار البث للتدفقات.
|
||||
- نوع الأداة والتطبيق في CrewDefinition.
|
||||
- إعادة توجيه أوامر القالب إلى crewAIInc-fde org.
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- تخزين نموذج كتالوج المفتاح بواسطة مفتاح API الدقيق، تقصير TTL، وتخطي Ollama.
|
||||
- توحيد دقة مدخلات التدفق لـ `crewai run` والمطالبة من مخطط الحالة.
|
||||
- حل مشكلات pip-audit لـ onnx 1.22.0 و nltk PYSEC-2026-597.
|
||||
- التأكد من أننا نكتب الإصدار للتدفقات.
|
||||
- تضمين aiobotocore في الإضافات الأساسية.
|
||||
- رفض طرق التدفق ذات الاستماع الذاتي.
|
||||
- قطع تنقل إصدار الوثائق من Edge حتى لا يتم إسقاط الصفحات الجديدة.
|
||||
|
||||
### الوثائق
|
||||
- تحديث اللغة من القواعد إلى السياسات لتتناسب مع تغييرات لوحة المعلومات الجديدة.
|
||||
- توثيق خيارات وكيل التدفق.
|
||||
- إضافة وثائق البث إلى التنقل.
|
||||
- توثيق نوع قاعدة حد التكلفة في وحدة التحكم الخاصة بالوكيل.
|
||||
- حذف مراجع CREWAI_LOG_FORMAT من دليل Datadog.
|
||||
|
||||
## المساهمون
|
||||
|
||||
@akaKuruma, @danielfsbarreto, @github-code-quality[bot], @joaomdmoura, @lorenzejay, @lucasgomide, @manisrinivasan2k1, @renatonitta, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="1 يوليو 2026">
|
||||
## v1.15.2a2
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a2)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- إضافة aiobotocore إلى الإضافات الأساسية
|
||||
- توثيق خيارات وكيل التدفق
|
||||
- إضافة مساعد نصي إلى مثال مهارة التدفق
|
||||
- إضافة مساعد نصي لمطالب CEL الخاصة بالتدفق
|
||||
- إضافة وثائق البث إلى التنقل
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- رفض طرق التدفق ذات الاستماع الذاتي
|
||||
|
||||
### الوثائق
|
||||
- تحديث اللقطة وسجل التغييرات للإصدار v1.15.2a1
|
||||
- ضغط ملف AGENTS.md
|
||||
|
||||
## المساهمون
|
||||
|
||||
@akaKuruma, @github-code-quality[bot], @lorenzejay, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="30 يونيو 2026">
|
||||
## v1.15.2a1
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a1)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- إعادة توجيه أوامر القالب إلى منظمة crewAIInc-fde
|
||||
- دعم تعريفات المهارات المضمنة
|
||||
- تعريف بروتوكول إطار التدفق للتدفقات
|
||||
- إضافة أداة النوع والتطبيق في CrewDefinition
|
||||
- إضافة مهارة تأليف تعريف التدفق المُنشأ
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- قطع تنقل إصدار الوثائق من Edge لمنع فقدان الصفحات الجديدة
|
||||
|
||||
### الوثائق
|
||||
- توثيق نوع قاعدة حد التكلفة في وحدة التحكم الخاصة بالوكيل
|
||||
- إزالة مراجع CREWAI_LOG_FORMAT من دليل Datadog
|
||||
|
||||
## المساهمون
|
||||
|
||||
@danielfsbarreto, @joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="26 يونيو 2026">
|
||||
## v1.15.1
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- تهيئة مستودعات Git للمشاريع المولدة (#6364)
|
||||
- طلب تعريفات مشروع CrewAI بشكل صريح (#6358)
|
||||
- فتح صفحة النشر بعد نشر CLI (#6343)
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح حل رابط معرف صفحة النشر (#6365)
|
||||
- إصلاح عرض قالب الطاقم JSON (#6359)
|
||||
- إصلاح تثبيت إصدار الطاقم JSON (#6342)
|
||||
- إصلاح تجاوز إعادة التوجيه SSRF في عمليات السحب (#6331)
|
||||
|
||||
### الوثائق
|
||||
- تحسين وضع المصدر المفتوح في README (#6363)
|
||||
- تحسين دعوة العمل لإعداد وكيل البرمجة (#6344)
|
||||
- إضافة لقطة وتغيير السجل للإصدار 1.15.1a1 (#6362)
|
||||
|
||||
## المساهمون
|
||||
|
||||
@joaomdmoura, @lorenzejay, @oalami, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<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
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.0)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- تتبع استخدام تدفق المحادثات في التليمتري
|
||||
- دعم تدفقات المحادثات في واجهة سطر الأوامر TUI
|
||||
- إضافة تحميل تدفق موحد بالإعلان
|
||||
- إضافة دعم تدفق CLI بالإعلان
|
||||
- إضافة تعبير "if" اختياري إلى خطوات each.do
|
||||
- إضافة إجراء عميل فردي إلى تعريفات التدفق
|
||||
- إضافة إجراءات الطاقم إلى تعريف التدفق
|
||||
- إضافة تحميل تعريف الطاقم داخل السطر
|
||||
- إضافة إجراء مركب `each` إلى تعريف التدفق
|
||||
- تنفيذ دعم وضع DMN في إنشاء الطاقم وتنفيذه
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح تطبيق أذونات المالك فقط على ملفات الاعتماد
|
||||
- إصلاح مدخلات بدء حالة تدفق مخطط JSON
|
||||
- إصلاح تجاوز مسار الرابط الرمزي في استخراج أرشيف المهارة
|
||||
- تجميع استخدام الرموز عبر جميع مكالمات LLM
|
||||
- إزالة أداة Exa المكررة
|
||||
- حل مشاكل الطاقم JSON
|
||||
- إصلاح معالجة الطاقم JSON وتعزيز وظيفة إعادة تعيين الذاكرة
|
||||
|
||||
### الوثائق
|
||||
- تحديث وثائق التثبيت والبدء السريع لمشاريع الطاقم التي تعتمد على JSON
|
||||
- إضافة دليل تكامل Datadog مع لوحة عمليات قابلة للاستيراد
|
||||
- إضافة صفحة استوديو "بطاقة واحدة لكل خطوة"
|
||||
- إضافة لقطات وتغييرات للإصدارات السابقة التي تؤدي إلى v1.15.0
|
||||
|
||||
### الأداء
|
||||
- تحسين تجربة بدء تشغيل crewai run
|
||||
- الحفاظ على تقدم طريقة التدفق مرئيًا للطاقم المتداخل
|
||||
|
||||
### إعادة الهيكلة
|
||||
- إزالة `StateProxy` من الوصول إلى حالة التدفق
|
||||
- دمج `crewai run` و `crewai flow kickoff`
|
||||
- تمييز أنواع حالة تعريف التدفق
|
||||
- توصيل التكوين والاستمرارية من تعريف التدفق إلى وقت التشغيل
|
||||
|
||||
## المساهمون
|
||||
|
||||
@gabemilani, @github-code-quality[bot], @greysonlalonde, @iris-clawd, @jessemiller, @joaomdmoura, @lorenzejay, @lucasgomide, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="24 يونيو 2026">
|
||||
## v1.14.8a5
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a5)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- جعل المراجع التصريحية تعمل عبر التدفقات والفرق (#6326)
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح مدخلات بدء حالة تدفق مخطط JSON (#6325)
|
||||
|
||||
### الوثائق
|
||||
- وضع بطاقة واحدة لكل خطوة تحت استوديو الفريق وإزالة لافتة التوزيع (AGE-107) (#6317)
|
||||
- تحديث اللقطة وسجل التغييرات للإصدار v1.14.8a4 (#6319)
|
||||
|
||||
### إعادة الهيكلة
|
||||
- إزالة `StateProxy` من الوصول إلى حالة التدفق (#6327)
|
||||
|
||||
## المساهمون
|
||||
|
||||
@jessemiller, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="24 يونيو 2026">
|
||||
## v1.14.8a4
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a4)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- دعم تدفقات المحادثة في واجهة سطر الأوامر TUI.
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- إصلاح مسار التوجيه الرمزي في استخراج أرشيف المهارات.
|
||||
- التحقق من صحة مسارات تعريف التدفق الإعلاني.
|
||||
|
||||
### الوثائق
|
||||
- تحديث اللقطة وسجل التغييرات للإصدار v1.14.8a3.
|
||||
|
||||
## المساهمون
|
||||
|
||||
@lorenzejay, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="23 يونيو 2026">
|
||||
## v1.14.8a3
|
||||
|
||||
[عرض الإصدار على GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a3)
|
||||
|
||||
## ما الذي تغير
|
||||
|
||||
### الميزات
|
||||
- إضافة تحميل تدفق موحد إعلاني
|
||||
- تحسين تجربة بدء تشغيل crewai run
|
||||
- دمج `crewai run` و `crewai flow kickoff`
|
||||
- الحفاظ على تقدم طريقة التدفق مرئيًا للفرق المتداخلة
|
||||
- إضافة دعم واجهة سطر الأوامر الإعلانية للتدفق
|
||||
- السماح باستخدام `@router()` كطريقة بدء لتدفق
|
||||
- إضافة مخططات مخرجات مكتوبة لأدوات CrewAI
|
||||
|
||||
### إصلاحات الأخطاء
|
||||
- تثبيت opentelemetry على ~=1.42.0
|
||||
|
||||
### الوثائق
|
||||
- إضافة صفحة استوديو "بطاقة واحدة لكل خطوة"
|
||||
|
||||
## المساهمون
|
||||
|
||||
@jessemiller, @joaomdmoura, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="18 يونيو 2026">
|
||||
## v1.14.8a2
|
||||
|
||||
|
||||
@@ -24,23 +24,15 @@ mode: "wide"
|
||||
|
||||
## البداية السريعة
|
||||
|
||||
### 1. إنشاء مهارة باستخدام سطر الأوامر (CLI)
|
||||
|
||||
واجهة سطر الأوامر هي الطريقة المدعومة لإنشاء مهارة — فهي تُنشئ لك هيكل المجلد وملف `SKILL.md` صالحًا:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create code-review
|
||||
```
|
||||
|
||||
داخل مشروع طاقم (حيث يوجد `pyproject.toml`) يُنشئ هذا الأمر `./skills/code-review/`؛ وخارج المشروع يُنشئ `./code-review/` في المجلد الحالي (يمكنك فرض هذا السلوك باستخدام `--no-project`):
|
||||
### 1. إنشاء مجلد المهارة
|
||||
|
||||
```
|
||||
skills/
|
||||
└── code-review/
|
||||
├── SKILL.md # Required — instructions (pre-filled template)
|
||||
├── references/ # Optional — reference docs
|
||||
├── scripts/ # Optional — executable scripts
|
||||
└── assets/ # Optional — static files
|
||||
├── SKILL.md # مطلوب — التعليمات
|
||||
├── references/ # اختياري — مستندات مرجعية
|
||||
│ └── style-guide.md
|
||||
└── scripts/ # اختياري — سكربتات قابلة للتنفيذ
|
||||
```
|
||||
|
||||
### 2. كتابة SKILL.md الخاص بك
|
||||
@@ -172,65 +164,6 @@ agent = Agent(
|
||||
|
||||
---
|
||||
|
||||
## إنشاء المهارات ونشرها وتثبيتها
|
||||
|
||||
للمهارات دورة حياة كاملة تُدار عبر واجهة سطر الأوامر: **أنشئها باستخدام `crewai skill create`، وانشرها باستخدام `crewai skill publish`** — إنشاء المجلدات يدويًا يصلح للتجارب المحلية، لكن واجهة سطر الأوامر هي سير العمل المقصود، وهي تحافظ على صحة هيكل المهارة وبياناتها الوصفية.
|
||||
|
||||
### الإنشاء
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create my-skill
|
||||
```
|
||||
|
||||
يُنشئ هذا الأمر المجلد (داخل `./skills/` في مشروع الطاقم) مع قالب `SKILL.md`، بالإضافة إلى مجلدات فارغة `scripts/` و `references/` و `assets/`. عدّل `SKILL.md` لتعريف التعليمات.
|
||||
|
||||
### النشر
|
||||
|
||||
نفّذ الأمر من داخل مجلد المهارة (حيث يوجد `SKILL.md`):
|
||||
|
||||
```shell Terminal
|
||||
cd skills/my-skill
|
||||
crewai skill publish
|
||||
```
|
||||
|
||||
يقرأ النشر الحقول `name` و `description` و `metadata.version` من البيانات الوصفية في مقدمة `SKILL.md` ويدفع المهارة إلى سجل CrewAI. **المهارات المنشورة تكون دائمًا مقيّدة بنطاق مؤسستك** — مثل الأدوات، لا يستطيع رؤيتها وتثبيتها إلا أعضاء المؤسسة الناشرة؛ ولا توجد رؤية عامة. أعلام مفيدة:
|
||||
|
||||
| العلم | التأثير |
|
||||
| :--- | :--- |
|
||||
| `--org <slug>` | النشر تحت مؤسسة محددة (يتجاوز الإعدادات). |
|
||||
| `--force` | تخطي التحقق من حالة git (تغييرات غير مُثبتة، إلخ). |
|
||||
|
||||
### التثبيت
|
||||
|
||||
ثبّت مهارة منشورة عبر مرجعها `@org/name`:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill install @acme/code-review
|
||||
```
|
||||
|
||||
داخل مشروع الطاقم تُثبَّت المهارة في `./skills/{name}/`؛ وخارج المشروع تذهب إلى ذاكرة التخزين المؤقتة المشتركة في `~/.crewai/skills/{org}/{name}/`.
|
||||
|
||||
يمكن للوكلاء أيضًا الإشارة إلى مهارات السجل مباشرة — يتم حلّها من ذاكرة التخزين المؤقتة المحلية (أو من مجلد `skills/` في المشروع) وقت التشغيل:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
role="Senior Code Reviewer",
|
||||
goal="Review pull requests for quality and security issues",
|
||||
backstory="Staff engineer with expertise in secure coding practices.",
|
||||
skills=["@acme/code-review"], # registry ref, resolved locally
|
||||
)
|
||||
```
|
||||
|
||||
### عرض القائمة
|
||||
|
||||
```shell Terminal
|
||||
crewai skill list
|
||||
```
|
||||
|
||||
يعرض المهارات المثبّتة من مجلد المشروع `./skills/` ومن ذاكرة التخزين المؤقتة العامة معًا، مع إصداراتها ومساراتها.
|
||||
|
||||
---
|
||||
|
||||
## المهارات على مستوى الطاقم
|
||||
|
||||
يمكن تعيين المهارات على الطاقم لتُطبّق على **جميع الوكلاء**:
|
||||
|
||||
@@ -11,7 +11,7 @@ mode: "wide"
|
||||
|
||||
- [نظرة عامة](/ar/enterprise/features/agent-control-plane/overview)
|
||||
- **المراقبة** *(أنت هنا)*
|
||||
- [السياسات](/edge/ar/enterprise/features/agent-control-plane/policies)
|
||||
- [القواعد](/ar/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## نظرة عامة
|
||||
@@ -58,7 +58,7 @@ mode: "wide"
|
||||
| **Last execution** | الوقت المنقضي منذ آخر تنفيذ. |
|
||||
| **Health Status Breakdown** | شريط مكدّس بنسب `Critical` / `Warning` / `Healthy` لعمليات التنفيذ في النافذة. |
|
||||
| **Executions with Errors** | إجمالي عمليات التنفيذ الفاشلة في النافذة. |
|
||||
| **PII detection applied** | `Yes` إذا كان هناك تكوين PII لكل deployment أو [سياسة PII](/edge/ar/enterprise/features/agent-control-plane/policies) مطابِقة نشطة. |
|
||||
| **PII detection applied** | `Yes` إذا كان هناك تكوين PII لكل deployment أو [قاعدة PII](/ar/enterprise/features/agent-control-plane/rules) مطابِقة نشطة. |
|
||||
| **Executions** | إجمالي عمليات التنفيذ في النافذة. |
|
||||
| **Last updated** | متى أُعيد نشر الـ deployment آخر مرة. |
|
||||
| **Crew Version** | إصدار `crewai` الذي يُبلِّغ عنه الـ deployment. يشير أيقونة المعلومات بجانب الإصدارات الأقل من `1.13` إلى صفوف لا يمكنها المساهمة بالمقاييس. |
|
||||
@@ -96,8 +96,8 @@ mode: "wide"
|
||||
<Card title="Agent Control Plane — نظرة عامة" icon="book-open" href="/ar/enterprise/features/agent-control-plane/overview">
|
||||
ما هو ACP، المتطلبات، مستويات الخطط، و RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — السياسات" icon="shield-check" href="/edge/ar/enterprise/features/agent-control-plane/policies">
|
||||
طبّق سياسات PII Redaction على مستوى المؤسسة عبر العديد من الأتمتات.
|
||||
<Card title="Agent Control Plane — القواعد" icon="shield-check" href="/ar/enterprise/features/agent-control-plane/rules">
|
||||
طبّق قواعد PII Redaction على مستوى المؤسسة عبر العديد من الأتمتات.
|
||||
</Card>
|
||||
<Card title="Traces" icon="timeline" href="/ar/enterprise/features/traces">
|
||||
تعمّق في تنفيذ واحد لرؤية تفكير الوكيل واستدعاءات الأدوات واستخدام الرموز.
|
||||
|
||||
@@ -10,17 +10,17 @@ icon: "book-open"
|
||||
|
||||
- **نظرة عامة** *(أنت هنا)*
|
||||
- [المراقبة](/ar/enterprise/features/agent-control-plane/monitoring)
|
||||
- [السياسات](/edge/ar/enterprise/features/agent-control-plane/policies)
|
||||
- [القواعد](/ar/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
**Agent Control Plane** (ACP) هو مركز العمليات لكل ما يعمل لديك على CrewAI AMP. إنها شاشة واحدة — مقسّمة إلى تبويبَي **Automations** و **Policies** — تمنح فريقك القدرة على:
|
||||
**Agent Control Plane** (ACP) هو مركز العمليات لكل ما يعمل لديك على CrewAI AMP. إنها شاشة واحدة — مقسّمة إلى تبويبَي **Automations** و **Rules** — تمنح فريقك القدرة على:
|
||||
|
||||
- مراقبة **حالة (الصحة)** كل أتمتة حيّة (crew أو flow) بتفصيل `Critical` / `Warning` / `Healthy` وعدد عمليات التنفيذ.
|
||||
- تتبع **استهلاك LLM** — الرموز (tokens) والتكلفة — لكل أتمتة ولكل مزود ولكل نموذج، مع الفرق مقابل الفترة السابقة.
|
||||
- التعمّق في أي أتمتة منفردة أو مزود نماذج لرؤية المخططات الزمنية وتفصيل البيانات لكل مزود.
|
||||
- تطبيق **سياسات (Policies)** على مستوى المؤسسة (اليوم: PII Redaction) عبر العديد من الأتمتات دفعة واحدة بدلاً من تعديل كل deployment على حدة.
|
||||
- تطبيق **قواعد (Rules)** على مستوى المؤسسة (اليوم: PII Redaction) عبر العديد من الأتمتات دفعة واحدة بدلاً من تعديل كل deployment على حدة.
|
||||
|
||||
<Frame>
|
||||

|
||||
@@ -33,7 +33,7 @@ icon: "book-open"
|
||||
يجيب التبويبان عن سؤالَين مختلفَين:
|
||||
|
||||
- **Automations** — *"كيف يتصرف أسطولي الآن، وكم يكلّفني؟"* راجع [المراقبة](/ar/enterprise/features/agent-control-plane/monitoring).
|
||||
- **Policies** — *"كيف أفرض سياسة (مثل PII redaction) عبر العديد من عمليات النشر دون إعادة نشر كل واحدة؟"* راجع [السياسات](/edge/ar/enterprise/features/agent-control-plane/policies).
|
||||
- **Rules** — *"كيف أفرض سياسة (مثل PII redaction) عبر العديد من عمليات النشر دون إعادة نشر كل واحدة؟"* راجع [القواعد](/ar/enterprise/features/agent-control-plane/rules).
|
||||
|
||||
## المتطلبات
|
||||
|
||||
@@ -42,11 +42,11 @@ icon: "book-open"
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
يُشترط **خطة Enterprise أو Ultra** لإنشاء أو تعديل [السياسات](/edge/ar/enterprise/features/agent-control-plane/policies). يمكن للمؤسسات على الخطط الأدنى فتح تبويب Policies وعرض السياسات الموجودة، ولكن يُعرض المحرر للقراءة فقط مع شارة قفل "Enterprise" والتنبيه *"PII Redaction policies require an Enterprise plan."*. المراقبة (تبويب Automations) متاحة في جميع الخطط حيث يكون هذا الميزة مفعّلة.
|
||||
يُشترط **خطة Enterprise أو Ultra** لإنشاء أو تعديل [القواعد](/ar/enterprise/features/agent-control-plane/rules). يمكن للمؤسسات على الخطط الأدنى فتح تبويب Rules وعرض القواعد الموجودة، ولكن يُعرض المحرر للقراءة فقط مع شارة قفل "Enterprise" والتنبيه *"PII Redaction rules require an Enterprise plan."*. المراقبة (تبويب Automations) متاحة في جميع الخطط حيث يكون هذا الميزة مفعّلة.
|
||||
</Warning>
|
||||
|
||||
- يجب أن تكون ميزة **Agent Control Plane** مفعّلة لمؤسستك. إن لم ترها في الشريط الجانبي، اطلب من مالك الحساب تفعيلها.
|
||||
- داخل ACP، يحكم [RBAC](/ar/enterprise/features/rbac) الوصول: `read` للعرض في لوحة المعلومات والسياسات، و`manage` لإنشاء وتعديل وتشغيل/إيقاف وحذف السياسات.
|
||||
- داخل ACP، يحكم [RBAC](/ar/enterprise/features/rbac) الوصول: `read` للعرض في لوحة المعلومات والقواعد، و`manage` لإنشاء وتعديل وتشغيل/إيقاف وحذف القواعد.
|
||||
- يمكن ضبط نطاق جميع المخططات والجداول إلى **آخر 24 ساعة** أو **الأسبوع الماضي** أو **آخر 30 يوماً** عبر مُحدّد الوقت في أعلى اليمين. تقارن قيم الفرق (`↑ 8 vs yesterday`, `↓ $20.57 vs yesterday` وغيرها) النافذة المختارة بالنافذة السابقة بنفس الطول.
|
||||
|
||||
## ما يمكنك فعله هنا
|
||||
@@ -55,7 +55,7 @@ icon: "book-open"
|
||||
<Card title="المراقبة" icon="gauge" href="/ar/enterprise/features/agent-control-plane/monitoring">
|
||||
راقب صحة الأسطول وإنفاق LLM عبر بطاقات المقاييس و sankey التفاعلي وجداول لكل أتمتة ولوحات جانبية للتعمق في أي أتمتة أو مزود.
|
||||
</Card>
|
||||
<Card title="السياسات" icon="shield-check" href="/edge/ar/enterprise/features/agent-control-plane/policies">
|
||||
<Card title="القواعد" icon="shield-check" href="/ar/enterprise/features/agent-control-plane/rules">
|
||||
طبّق سياسات PII Redaction على مستوى المؤسسة بنطاق محدد بالأدوات والوسوم. تسري التغييرات في التنفيذ التالي — دون الحاجة لإعادة نشر.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -67,10 +67,10 @@ icon: "book-open"
|
||||
تعمّق في تنفيذ واحد لرؤية تفكير الوكيل واستدعاءات الأدوات واستخدام الرموز.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/ar/enterprise/features/rbac">
|
||||
أدِر من يمكنه قراءة Agent Control Plane ومن يمكنه تعديل السياسات.
|
||||
أدِر من يمكنه قراءة Agent Control Plane ومن يمكنه تعديل القواعد.
|
||||
</Card>
|
||||
<Card title="PII Redaction للـ Traces" icon="lock" href="/ar/enterprise/features/pii-trace-redactions">
|
||||
كتالوج الكيانات وضبط PII لكل deployment التي تستند إليها السياسات.
|
||||
كتالوج الكيانات وضبط PII لكل deployment التي تستند إليها القواعد.
|
||||
</Card>
|
||||
<Card title="النشر إلى AMP" icon="rocket" href="/ar/enterprise/guides/deploy-to-amp">
|
||||
انشر crew على إصدار crewAI يدعم Agent Control Plane.
|
||||
@@ -78,5 +78,5 @@ icon: "book-open"
|
||||
</CardGroup>
|
||||
|
||||
<Card title="تحتاج مساعدة؟" icon="headset" href="mailto:support@crewai.com">
|
||||
تواصل مع فريق الدعم للمساعدة في تفسير المقاييس أو تصميم السياسات.
|
||||
تواصل مع فريق الدعم للمساعدة في تفسير المقاييس أو تصميم القواعد.
|
||||
</Card>
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
---
|
||||
title: "إعداد السياسات"
|
||||
description: "طبّق سياسات على مستوى المؤسسة عبر العديد من الأتمتات من مكان واحد."
|
||||
sidebarTitle: "السياسات"
|
||||
icon: "shield-check"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**تنقل وثائق ACP (إصدار تجريبي)**
|
||||
|
||||
- [نظرة عامة](/ar/enterprise/features/agent-control-plane/overview)
|
||||
- [المراقبة](/ar/enterprise/features/agent-control-plane/monitoring)
|
||||
- **السياسات** *(أنت هنا)*
|
||||
</Info>
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
تتيح لك السياسات تطبيق سياسات — اليوم: **PII Redaction** — عبر العديد من الأتمتات دفعة واحدة، بدلاً من ضبط كل deployment على حدة. افتح تبويب **Policies** في [Agent Control Plane](/ar/enterprise/features/agent-control-plane/overview) لإدارتها.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
تعرض كل بطاقة سياسة الاسم والوصف و**النطاق (scope)** الذي تنطبق عليه السياسة (الأدوات والوسوم المختارة) وعدد **الأتمتات المُفعَّلة** — عمليات النشر التي تطابق النطاق حالياً. يقوم المُفتاح على اليمين بتشغيل السياسة أو إيقافها دون حذفها.
|
||||
|
||||
## المتطلبات
|
||||
|
||||
<Warning>
|
||||
يُشترط **خطة Enterprise أو Ultra** لإنشاء أو تعديل سياسات PII Redaction. يمكن للمؤسسات على الخطط الأدنى فتح تبويب Policies وعرض السياسات الموجودة، ولكن يُعرض المحرر للقراءة فقط مع شارة قفل "Enterprise" والتنبيه *"PII Redaction policies require an Enterprise plan."* — تواصل مع مالك حسابك أو المبيعات للترقية.
|
||||
</Warning>
|
||||
|
||||
- يجب أن تكون ميزة **Agent Control Plane** مفعّلة لمؤسستك. راجع [نظرة عامة — المتطلبات](/ar/enterprise/features/agent-control-plane/overview#المتطلبات).
|
||||
- تحتاج إلى صلاحية `manage` ضمن [RBAC](/ar/enterprise/features/rbac) على Agent Control Plane لإنشاء وتعديل وتشغيل/إيقاف وحذف السياسات. صلاحية `read` كافية لعرضها.
|
||||
- تُسجَّل جميع تغييرات السياسات بإصدارات للتدقيق.
|
||||
|
||||
## أنواع السياسات المتاحة
|
||||
|
||||
| النوع | ما تفعله |
|
||||
|------|---------------|
|
||||
| **PII Redaction** | تطبّق PII redaction على عمليات التنفيذ لكل أتمتة مطابِقة، باستخدام نفس كتالوج الكيانات و recognizers المخصصة الموثَّقة في [PII Redaction للـ Traces](/ar/enterprise/features/pii-trace-redactions). |
|
||||
|
||||
سيتم إضافة أنواع سياسات أخرى مع الوقت.
|
||||
|
||||
## إنشاء سياسة
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/acp-policies-new-side-panel.png" alt="لوحة تعديل سياسة جانبية بالشروط ونوع قناع PII" width="450" />
|
||||
</Frame>
|
||||
|
||||
<Steps>
|
||||
<Step title="افتح المحرر">
|
||||
انقر على **+ Create new** في أعلى يمين تبويب Policies، أو على **View Details** في بطاقة سياسة موجودة.
|
||||
</Step>
|
||||
|
||||
<Step title="سَمِّ السياسة وصِفها">
|
||||
أعطِ السياسة اسماً واضحاً (مثل *Mask PII (CC)*) ووصفاً يشرح متى تنطبق. يظهر كلاهما على بطاقة السياسة وفي مودال Engaged Automations.
|
||||
</Step>
|
||||
|
||||
<Step title="اختر النوع">
|
||||
اليوم **PII Redaction** فقط متاحة.
|
||||
</Step>
|
||||
|
||||
<Step title="حدّد الشروط">
|
||||
تحدد الشروط الأتمتات التي تنخرط معها السياسة. كلاهما اختياري ويستخدم دلالات **مساواة المجموعات (set-equality)**:
|
||||
|
||||
- **Tools** — تنخرط فقط الأتمتات التي تتطابق مجموعة أدواتها **تطابقاً تامّاً** مع الأدوات المختارة. اختر من تطبيقات Studio و MCPs والأدوات مفتوحة المصدر وأدوات سجل Tool Repository.
|
||||
- **Automations** — تنخرط فقط الأتمتات التي تتطابق مجموعة وسومها **تطابقاً تامّاً** مع الوسوم المختارة.
|
||||
|
||||
ترك مُحدِّد فارغ يعني "بدون تصفية على هذا البعد". ترك كليهما فارغَين يعني أن السياسة تنطبق على **كل** أتمتة في المؤسسة.
|
||||
</Step>
|
||||
|
||||
<Step title="اضبط جدول PII Mask Type">
|
||||
حدّد كل نوع كيان تريد تغطيته واختر **Mask** (يستبدل بتسمية الكيان مثل `<CREDIT_CARD>`) أو **Redact** (يحذف النص المطابِق بالكامل). راجع [PII Redaction للـ Traces](/ar/enterprise/features/pii-trace-redactions) للاطلاع على كتالوج الكيانات الكامل وكيفية إضافة recognizers مخصصة على مستوى المؤسسة.
|
||||
</Step>
|
||||
|
||||
<Step title="احفظ">
|
||||
تنطبق السياسة على عمليات التنفيذ **المستقبلية** لكل أتمتة مُفعَّلة بمجرد الحفظ. لا حاجة لإعادة النشر.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## الأتمتات المُفعَّلة
|
||||
|
||||
انقر على **Engaged N automations** في أي بطاقة سياسة لرؤية أي عمليات النشر تطابقها السياسة حالياً بالضبط، إلى جانب آخر تنفيذ لكل منها.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
هذه هي أسرع طريقة للتحقق من نطاق سياسة قبل تمكينها — على سبيل المثال، للتأكد من أن سياسة محدَّدة بنطاق وسم `production` لا تطابق عن طريق الخطأ deployment تجريبي.
|
||||
|
||||
## سياسات على مستوى المؤسسة مقابل إعدادات لكل deployment
|
||||
|
||||
يمكن ضبط PII Redaction في مكانين:
|
||||
|
||||
- **لكل deployment** — ضمن **Settings → PII Protection** على كل deployment على حدة ([الدليل](/ar/enterprise/features/pii-trace-redactions))
|
||||
- **على مستوى المؤسسة** — كسياسة في هذه الصفحة
|
||||
|
||||
عندما يتطابق نطاق سياسة مُفعَّلة على مستوى المؤسسة مع deployment، يُجاوز تكوين الكيانات الخاص بالسياسة **إعدادات PII المملوكة من قبل الـ deployment** لعمليات تنفيذ ذلك الـ deployment — تصبح السياسة المصدر الوحيد للحقيقة طالما هي مرتبطة. عطّل السياسة أو فُكَّ ارتباطها (أو غيِّر نطاقها بحيث لا تتطابق بعد الآن) ويعود الـ deployment إلى إعدادات PII Protection الخاصة به.
|
||||
|
||||
فضّل السياسات على مستوى المؤسسة عندما تريد فرض سياسة متسقة عبر العديد من عمليات النشر؛ احتفظ بالضبط لكل deployment للاستثناءات الفردية.
|
||||
|
||||
## ذو صلة
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agent Control Plane — نظرة عامة" icon="book-open" href="/ar/enterprise/features/agent-control-plane/overview">
|
||||
ما هو ACP، المتطلبات، مستويات الخطط، و RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — المراقبة" icon="gauge" href="/ar/enterprise/features/agent-control-plane/monitoring">
|
||||
راقب الأتمتات واستهلاك LLM عبر أسطولك.
|
||||
</Card>
|
||||
<Card title="PII Redaction للـ Traces" icon="lock" href="/ar/enterprise/features/pii-trace-redactions">
|
||||
كتالوج الكيانات، recognizers المخصصة، والضبط لكل deployment.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/ar/enterprise/features/rbac">
|
||||
أدِر من يمكنه إنشاء أو تعديل السياسات.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Card title="تحتاج مساعدة؟" icon="headset" href="mailto:support@crewai.com">
|
||||
تواصل مع فريق الدعم للمساعدة في تصميم سياسات لمؤسستك.
|
||||
</Card>
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**الإطلاق يوم الأربعاء 24 يونيو.** تنتقل لوحة Studio إلى بطاقة واحدة لكل خطوة بدلاً من عُقد منفصلة للمهمة والوكيل، وذلك لتبسيط اللوحة مع إضافتنا لوظائف جديدة قريبًا. تستمر أتمتتك الحالية في العمل دون أي تغييرات مطلوبة — تبقى جميع إعدادات المهمة والوكيل متاحة، ولكن منظّمة في بطاقة واحدة.
|
||||
</Note>
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
على لوحة Studio، تُمثَّل كل خطوة عمل بـ **بطاقة واحدة**. تجمع البطاقة بين عنصرين كانا في السابق في عُقد منفصلة:
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
---
|
||||
title: التدفقات في الاستوديو
|
||||
description: "أنشئ سير عمل يعتمد على الأحداث يجمع بين التحكم الحتمي خطوة بخطوة والذكاء الوكيلي — دون كتابة أي كود."
|
||||
icon: "diagram-project"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**الطرح جارٍ حاليًا**: يجري طرح التدفقات في الاستوديو تدريجيًا خلال أسبوع 20 يوليو 2026. إذا لم يظهر لك خيار Flows في الاستوديو بعد، فهذا يعني أن الميزة لم تصل إلى مؤسستك بعد — عاود التحقق قريبًا.
|
||||
</Info>
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
يدعم الاستوديو الآن إنشاء **التدفقات (Flows)** إلى جانب فرق Crew. التدفقات هي سير عمل يعتمد على الأحداث تتحكم فيه بدقة في الخطوات التي تُنفَّذ وترتيبها وشروط تنفيذها — بينما تُفوِّض العمل الذكي داخل كل خطوة إلى وكلاء الذكاء الاصطناعي.
|
||||
|
||||
لإنشاء تدفق، افتح الاستوديو وصف الأتمتة التي تريدها، ثم اختر **Flows** من المحدد بجوار مربع الإدخال.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
## لماذا التدفقات؟
|
||||
|
||||
فرق Crew ممتازة عندما تريد أن يتعاون فريق من الوكلاء بشكل مستقل نحو هدف. لكن كثيرًا من الأتمتة الواقعية يحتاج إلى قدر أكبر من القابلية للتنبؤ: اجلب هذه البيانات أولًا، ثم لخصها، ثم انشر النتيجة — في كل مرة وبنفس الترتيب.
|
||||
|
||||
تمنحك التدفقات الأمرين معًا:
|
||||
|
||||
- **الحتمية حيث تهم**: تُنفَّذ الخطوات وفق تسلسل محدد وتفرعات صريحة، فتكون عمليات التشغيل قابلة للتنبؤ والتكرار وسهلة التصحيح.
|
||||
- **الذكاء حيث تحتاجه**: كل خطوة يشغّلها وكيل (أو فريق Crew كامل)، لذا يستفيد العمل داخل الخطوة — التلخيص والتقييم والصياغة واتخاذ القرار — من قدرات الاستدلال الكاملة للنموذج اللغوي.
|
||||
|
||||
هذا المزيج هو ما يجعل التدفقات مناسبة للأتمتة في بيئات الإنتاج: البنية مضمونة، والاستقلالية محصورة في الخطوات التي تحتاجها.
|
||||
|
||||
## إنشاء تدفق
|
||||
|
||||
صف ما تريده بلغة طبيعية وسيصمم مساعد الاستوديو (Studio Assistant) التدفق لك — بإنشاء الخطوات وربطها ببعضها وتهيئة الوكلاء وتكاملات التطبيقات التي تحتاجها كل خطوة. تعرض اللوحة (Canvas) على اليمين سير العمل الناتج كعُقد متصلة، ويمكنك مواصلة التحسين عبر المحادثة أو تعديل أي عقدة مباشرة.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
عندما تكون جاهزًا، استخدم **Run** لاختبار التدفق من البداية إلى النهاية، وافحص النتائج في تبويبي **Output** و**Traces**، ثم نفّذ **Deploy** عندما يستقر. يمكنك أيضًا مشاركة المشروع عبر **Share** أو تنزيل الكود المصدري عبر **Download**.
|
||||
|
||||
## أنواع العُقد
|
||||
|
||||
تتكون التدفقات من ثلاثة أنواع أساسية من العُقد. كل عقدة هي خطوة في سير العمل، ويمكنك المزج بينها بحرية.
|
||||
|
||||
### الوكيل المنفرد (Single Agent)
|
||||
|
||||
تُشغِّل عقدة Single Agent وكيلًا واحدًا لمهمة واحدة مركزة — وهي مثالية للخطوات محددة النطاق مثل جلب البيانات من تكامل، أو تحويل المحتوى، أو نشر رسالة.
|
||||
|
||||
عند النقر على عقدة الوكيل تُفتح تهيئتها الكاملة:
|
||||
|
||||
- **Task**: ما ينبغي أن تنجزه هذه الخطوة والمخرجات التي يجب أن تنتجها
|
||||
- **Profile**: دور الوكيل وهدفه وخلفيته
|
||||
- **Model**: النموذج اللغوي الذي يشغّل الوكيل
|
||||
- **Apps**: التكاملات التي يمكن للوكيل استخدامها (مثل Linear وSlack وHubSpot)
|
||||
- **Runtime Controls**: خيارات التخطيط قبل التنفيذ والتفويض والذاكرة
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
### فرق Crew
|
||||
|
||||
تُضمِّن عقدة Crew فريقًا كاملًا — عدة وكلاء يتعاونون عبر عدة مهام — كخطوة واحدة في تدفقك. استخدمها عندما تكون الخطوة أكبر من أن يتولاها وكيل واحد، مثل تجميع البيانات وتلخيصها حسب الفريق ثم تنسيق النتيجة للتسليم.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
يكشف فتح عقدة Crew عن بنيتها الداخلية: المهام التي تؤديها، والوكلاء المعيّنين لكل مهمة، والتطبيقات التي يستخدمونها. يعمل الفريق بشكل مستقل داخل الخطوة، ثم يسلّم مخرجاته إلى العقدة التالية في التدفق.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
هذا هو نمط الحتمية مع الذكاء الوكيلي عمليًا: يضمن التدفق *متى* يعمل الفريق، بينما يضيف الفريق ذكاءً تعاونيًا إلى *كيفية* إنجاز العمل.
|
||||
|
||||
### الموجِّه (Router)
|
||||
|
||||
تُفرِّع عقدة Router التدفق بناءً على شروط، بحيث تسلك النتائج المختلفة مسارات مختلفة. على سبيل المثال، يمكن لتدفق توجيه العملاء المحتملين تقييم العملاء الواردين ثم توجيه ذوي الجودة العالية إلى خطوة إسناد المبيعات، مع تسجيل البقية للمتابعة والرعاية لاحقًا.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
الموجِّهات هي ما يجعل التدفقات معتمدة على الأحداث فعليًا: يتعامل سير العمل نفسه مع كل الحالات، لكن كل عملية تشغيل تتبع فقط الفرع الذي تستدعيه بياناتها — بلا خطوات مهدرة ولا غموض حول ما سيحدث تاليًا.
|
||||
|
||||
## المزامنة مع مستودع الوكلاء
|
||||
|
||||
لا يلزم أن يبقى الوكلاء الذين تنشئهم في التدفقات حبيسي مشروع واحد. تتضمن كل عقدة وكيل زر **Publish to Agent Repository** الذي يحفظ الوكيل — بدوره وهدفه وخلفيته ونموذجه وتهيئته — في [مستودع الوكلاء](/ar/enterprise/features/agent-repositories) الخاص بمؤسستك.
|
||||
|
||||
يعمل هذا في الاتجاهين:
|
||||
|
||||
- **النشر**: رقِّ وكيلًا حسّنته داخل تدفق إلى المستودع ليتمكن باقي الفرق والمشاريع من إعادة استخدامه.
|
||||
- **السحب**: أدخِل وكيلًا موجودًا من المستودع إلى تدفق جديد بدلًا من إعادة بنائه من الصفر.
|
||||
|
||||
ولأن وكلاء المستودع متزامنون عبر مؤسستك كلها، فإن أي تحسين على وكيل مشترك يعود بالنفع على كل تدفق يستخدمه — مما يحافظ على سلوك وكلاء متسق وخاضع للحوكمة وخالٍ من ازدواجية الجهد.
|
||||
|
||||
## أفضل الممارسات
|
||||
|
||||
- **اختر التدفق** عندما يكون للأتمتة تسلسل واضح أو منطق تفرّع؛ واختر Crew عندما يكون الطريق إلى الهدف مفتوحًا.
|
||||
- **أبقِ مهام الوكلاء مركزة** — عقدة Single Agent بوصف مهمة محكم أكثر موثوقية من وكيل مطلوب منه ثلاثة أشياء.
|
||||
- **استخدم الموجّهات لمعالجة كل حالة صراحةً**، بما في ذلك مسار "عدم فعل شيء" (مثل تسجيل العملاء المتجاوزين)، حتى تكون كل عمليات التشغيل محسوبة بالكامل.
|
||||
- **انشر الوكلاء المستقرين في مستودع الوكلاء** لتبني مؤسستك مكتبة مشتركة بدلًا من نسخ متوازية لمرة واحدة.
|
||||
- **اختبر عبر Run وافحص Traces** قبل النشر لاكتشاف مشكلات التكامل أو الموجِّهات النصية مبكرًا.
|
||||
|
||||
## ذات صلة
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="استوديو الطاقم" href="/ar/enterprise/features/crew-studio" icon="pencil">
|
||||
أنشئ فرق Crew في الاستوديو.
|
||||
</Card>
|
||||
<Card title="مستودعات الوكلاء" href="/ar/enterprise/features/agent-repositories" icon="people-group">
|
||||
شارك الوكلاء وأعد استخدامهم عبر مؤسستك.
|
||||
</Card>
|
||||
<Card title="مفاهيم التدفقات" href="/ar/concepts/flows" icon="diagram-project">
|
||||
تعرّف على كيفية عمل التدفقات في إطار عمل CrewAI.
|
||||
</Card>
|
||||
<Card title="الأدوات والتكاملات" href="/ar/enterprise/features/tools-and-integrations" icon="plug">
|
||||
اربط التطبيقات التي يستخدمها وكلاؤك.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -21,11 +21,12 @@ CrewAI supports two log-ingestion paths to Datadog — both are first-class and
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Datadog Agent">
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. Each log event ships as a single billable line with structured attributes — see the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. With `CREWAI_LOG_FORMAT=json` set, each log event ships as a single billable line with structured attributes.
|
||||
|
||||
**Setup:**
|
||||
1. Run the Datadog Agent next to your CrewAI containers — see [Datadog's deployment docs](https://docs.datadoghq.com/agent/) for Kubernetes, ECS, or VM setup. Enable log collection (`logs_enabled: true`) and container log collection (`logs_config.container_collect_all: true`).
|
||||
2. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
2. Set `CREWAI_LOG_FORMAT=json` as an **automation environment variable** in CrewAI AMP (open your automation → **Settings → Environment Variables**) so each log event is a single line instead of a multi-line traceback. AMP propagates the value to every container in the deployment (API + workers) — don't set it on the container or host directly. See [Enabling JSON output](#enabling-json-output) below for the AMP UI walkthrough and the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
3. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
|
||||
**Pick this path if** you already operate Datadog Agents (e.g. for infrastructure metrics), or your log volume makes per-event ingestion cost a real concern — collapsing tracebacks into single events keeps Agent ingestion cheap at scale.
|
||||
</Tab>
|
||||
@@ -56,10 +57,10 @@ Either path lands the same structured facets in Datadog (`@automation_id`, `@kic
|
||||
## Log schema reference
|
||||
|
||||
<Info>
|
||||
This schema applies to the **Datadog Agent path** — structured stdout JSON logs emitted by every CrewAI worker container. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
This schema applies to the **Datadog Agent path** — stdout JSON logs produced when `CREWAI_LOG_FORMAT=json` is set. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
</Info>
|
||||
|
||||
Every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
When `CREWAI_LOG_FORMAT=json` is set, every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
|
||||
### Why JSON output
|
||||
|
||||
@@ -78,6 +79,20 @@ Every log event is emitted as a **single JSON object per line** to stdout, with
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Enabling JSON output
|
||||
|
||||
`CREWAI_LOG_FORMAT=json` must be set as an **automation environment variable** in CrewAI AMP — it is **not** a container, host, or Docker setting. Open your automation in AMP, click the **Settings** icon, and add the variable under the **Environment Variables** section. AMP applies the value to every container in the deployment (API + workers) on the next restart. See [Update Your Crew](./update-crew) for the full UI walkthrough with screenshots.
|
||||
|
||||
```shell
|
||||
CREWAI_LOG_FORMAT=json
|
||||
```
|
||||
|
||||
Restart the deployment to pick up the change. Every log line on stdout from that point on is a single JSON object.
|
||||
|
||||
<Note>
|
||||
The default value is `text`, which preserves the legacy human-readable line format byte-for-byte. Setting any value other than `json` falls back to text mode. There is no migration step — the variable is read at process start and the format switches immediately.
|
||||
</Note>
|
||||
|
||||
### Example events
|
||||
|
||||
A single info-level log inside an active automation kickoff:
|
||||
@@ -120,7 +135,7 @@ An error with a Python exception is collapsed into a single event with the trace
|
||||
}
|
||||
```
|
||||
|
||||
Without JSON output, that same error would produce ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
The same error in legacy text mode would have produced ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
|
||||
### Schema v1 fields
|
||||
|
||||
@@ -222,7 +237,7 @@ Open [Logs Explorer](https://app.datadoghq.com/logs) and run a query that matche
|
||||
<Tab title="Datadog Agent">
|
||||
Search `service:crewai* @schema:v1`. You should see structured logs with the JSON fields parsed into Datadog facets. Pick a recent event and verify it has `@automation_id`, `@kickoff_id`, `@execution_id`, `@crewai_version`, and (when running inside a span) `@trace_id` / `@span_id` populated.
|
||||
|
||||
If nothing appears, confirm the Datadog Agent is tailing container stdout and that the deployment is running a recent enough CrewAI Enterprise build.
|
||||
If nothing appears, confirm `CREWAI_LOG_FORMAT=json` is set under your automation's **Environment Variables** in AMP, the deployment was restarted after the change, and the Datadog Agent is tailing container stdout.
|
||||
</Tab>
|
||||
<Tab title="Datadog OTLP intake">
|
||||
Search `source:otlp service:crewai*`. OTLP attributes land with their OpenTelemetry names (`automation_id`, `crewai.kickoff.id`, etc.) rather than the stdout JSON keys, but they map to the same dashboard facets after [facet promotion](#prerequisite-promote-facets).
|
||||
@@ -265,7 +280,7 @@ The `$service` template variable defaults to `*` and will catch every CrewAI dep
|
||||
| All widgets show "No data" | Facets aren't promoted | Re-do the [Promote facets](#prerequisite-promote-facets) step. Datadog won't query against an un-promoted field. |
|
||||
| Error Rate widget shows `NaN` | No executions in the time window | Either no traffic, or `@execution_id` isn't faceted. Expand the time range and re-check facets. |
|
||||
| Throughput chart is flat at the same value | Logs aren't reaching Datadog | Search `service:crewai*` in Logs Explorer. If nothing shows, verify the Datadog Agent is running (Agent path) or the OTel collector endpoint is correct (OTLP path). |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments (pre-structured-logs AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments running text mode (or older AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| Template variables don't filter widgets | The widget's filter line doesn't reference the template variable | Edit the widget and confirm the search includes `$automation $version $service`. |
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -11,7 +11,7 @@ mode: "wide"
|
||||
|
||||
## كيف يعمل بث التدفق
|
||||
|
||||
عند تفعيل البث في تدفق، يلتقط CrewAI ويبث المخرجات من أي أطقم أو استدعاءات LLM أو أدوات أو أحداث دورة حياة داخل التدفق. يقدم البث عناصر `StreamFrame` مرتبة تحتوي على محتوى قابل للطباعة وبيانات حدث مهيكلة مع تقدم التنفيذ.
|
||||
عند تفعيل البث في تدفق، يلتقط CrewAI ويبث المخرجات من أي أطقم أو استدعاءات LLM داخل التدفق. يقدم البث أجزاء منظمة تحتوي على المحتوى وسياق المهمة ومعلومات الوكيل مع تقدم التنفيذ.
|
||||
|
||||
## تفعيل البث
|
||||
|
||||
@@ -52,7 +52,7 @@ class ResearchFlow(Flow):
|
||||
|
||||
## البث المتزامن
|
||||
|
||||
عند استدعاء `kickoff()` على تدفق مع تفعيل البث، يُرجع جلسة stream تنتج عناصر `StreamFrame` مرتبة:
|
||||
عند استدعاء `kickoff()` على تدفق مع تفعيل البث، يُرجع كائن `FlowStreamingOutput` يمكنك التكرار عليه:
|
||||
|
||||
```python Code
|
||||
flow = ResearchFlow()
|
||||
@@ -60,43 +60,44 @@ flow = ResearchFlow()
|
||||
# Start streaming execution
|
||||
streaming = flow.kickoff()
|
||||
|
||||
# Iterate over stream items as they arrive
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Iterate over chunks as they arrive
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Access the final result after streaming completes
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal output: {result}")
|
||||
```
|
||||
|
||||
### معلومات عنصر البث
|
||||
### معلومات جزء البث
|
||||
|
||||
يوفر كل عنصر محتوى قابلاً للطباعة وبيانات حدث مهيكلة:
|
||||
يوفر كل جزء سياقاً حول مصدره في التدفق:
|
||||
|
||||
```python Code
|
||||
streaming = flow.kickoff()
|
||||
|
||||
for item in streaming:
|
||||
print(f"Channel: {item.channel}")
|
||||
print(f"Type: {item.type}")
|
||||
print(f"Content: {item.content}")
|
||||
print(f"Event payload: {item.event}")
|
||||
for chunk in streaming:
|
||||
print(f"Agent: {chunk.agent_role}")
|
||||
print(f"Task: {chunk.task_name}")
|
||||
print(f"Content: {chunk.content}")
|
||||
print(f"Type: {chunk.chunk_type}") # TEXT or TOOL_CALL
|
||||
```
|
||||
|
||||
### الوصول إلى خصائص البث
|
||||
|
||||
توفر جلسة stream خصائص وطرق مفيدة:
|
||||
يوفر كائن `FlowStreamingOutput` خصائص وطرق مفيدة:
|
||||
|
||||
```python Code
|
||||
streaming = flow.kickoff()
|
||||
|
||||
# Iterate and collect items
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Iterate and collect chunks
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# After iteration completes
|
||||
print(f"\nCompleted: {streaming.is_completed}")
|
||||
print(f"Total frames: {len(streaming.frames)}")
|
||||
print(f"Full text: {streaming.get_full_text()}")
|
||||
print(f"Total chunks: {len(streaming.chunks)}")
|
||||
print(f"Final result: {streaming.result}")
|
||||
```
|
||||
|
||||
@@ -113,9 +114,9 @@ async def stream_flow():
|
||||
# Start async streaming
|
||||
streaming = await flow.kickoff_async()
|
||||
|
||||
# Async iteration over stream items
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Async iteration over chunks
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Access final result
|
||||
result = streaming.result
|
||||
@@ -180,14 +181,13 @@ flow = MultiStepFlow()
|
||||
streaming = flow.kickoff()
|
||||
|
||||
current_step = ""
|
||||
for item in streaming:
|
||||
for chunk in streaming:
|
||||
# Track which flow step is executing
|
||||
step_name = item.event.get("method_name") or item.event.get("task_name")
|
||||
if step_name and step_name != current_step:
|
||||
current_step = step_name
|
||||
print(f"\n\n=== {step_name} ===\n")
|
||||
if chunk.task_name != current_step:
|
||||
current_step = chunk.task_name
|
||||
print(f"\n\n=== {chunk.task_name} ===\n")
|
||||
|
||||
print(item.content, end="", flush=True)
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal analysis: {result}")
|
||||
@@ -201,6 +201,7 @@ print(f"\n\nFinal analysis: {result}")
|
||||
import asyncio
|
||||
from crewai.flow.flow import Flow, listen, start
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai.types.streaming import StreamChunkType
|
||||
|
||||
class ResearchPipeline(Flow):
|
||||
stream = True
|
||||
@@ -253,35 +254,33 @@ async def run_with_dashboard():
|
||||
|
||||
current_agent = ""
|
||||
current_task = ""
|
||||
frame_count = 0
|
||||
chunk_count = 0
|
||||
|
||||
async for item in streaming:
|
||||
frame_count += 1
|
||||
async for chunk in streaming:
|
||||
chunk_count += 1
|
||||
|
||||
# Display phase transitions
|
||||
task_name = item.event.get("task_name", "")
|
||||
agent_role = item.event.get("agent_role", "")
|
||||
if task_name and task_name != current_task:
|
||||
current_task = task_name
|
||||
current_agent = agent_role
|
||||
if chunk.task_name != current_task:
|
||||
current_task = chunk.task_name
|
||||
current_agent = chunk.agent_role
|
||||
print(f"\n\n📋 Phase: {current_task}")
|
||||
print(f"👤 Agent: {current_agent}")
|
||||
print("-" * 60)
|
||||
|
||||
# Display text output
|
||||
if item.content:
|
||||
print(item.content, end="", flush=True)
|
||||
if chunk.chunk_type == StreamChunkType.TEXT:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Display tool usage
|
||||
elif item.channel == "tools":
|
||||
print(f"\n🔧 Tool event: {item.type}")
|
||||
elif chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
|
||||
print(f"\n🔧 Tool: {chunk.tool_call.tool_name}")
|
||||
|
||||
# Show completion summary
|
||||
result = streaming.result
|
||||
print(f"\n\n{'='*60}")
|
||||
print("PIPELINE COMPLETE")
|
||||
print(f"{'='*60}")
|
||||
print(f"Total frames: {frame_count}")
|
||||
print(f"Total chunks: {chunk_count}")
|
||||
print(f"Final output length: {len(str(result))} characters")
|
||||
|
||||
asyncio.run(run_with_dashboard())
|
||||
@@ -354,8 +353,8 @@ class StatefulStreamingFlow(Flow[AnalysisState]):
|
||||
flow = StatefulStreamingFlow()
|
||||
streaming = flow.kickoff(inputs={"topic": "quantum computing"})
|
||||
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal state:")
|
||||
@@ -375,29 +374,29 @@ print(f"Insights length: {len(flow.state.insights)}")
|
||||
- **تتبع التقدم**: إظهار المرحلة الحالية من سير العمل للمستخدمين
|
||||
- **لوحات المعلومات الحية**: إنشاء واجهات مراقبة لتدفقات الإنتاج
|
||||
|
||||
## قنوات إطارات البث
|
||||
## أنواع أجزاء البث
|
||||
|
||||
ينتج بث التدفق عناصر `StreamFrame` عبر عدة قنوات:
|
||||
مثل بث الطاقم، يمكن أن تكون أجزاء التدفق من أنواع مختلفة:
|
||||
|
||||
### إطارات LLM
|
||||
### أجزاء TEXT
|
||||
|
||||
محتوى نصي قياسي من استجابات LLM:
|
||||
|
||||
```python Code
|
||||
for item in streaming:
|
||||
if item.channel == "llm" and item.content:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
if chunk.chunk_type == StreamChunkType.TEXT:
|
||||
print(chunk.content, end="", flush=True)
|
||||
```
|
||||
|
||||
### إطارات الأدوات
|
||||
### أجزاء TOOL_CALL
|
||||
|
||||
معلومات حول استدعاءات الأدوات داخل التدفق:
|
||||
|
||||
```python Code
|
||||
for item in streaming:
|
||||
if item.channel == "tools":
|
||||
print(f"\nTool event: {item.type}")
|
||||
print(f"Payload: {item.event}")
|
||||
for chunk in streaming:
|
||||
if chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
|
||||
print(f"\nTool: {chunk.tool_call.tool_name}")
|
||||
print(f"Args: {chunk.tool_call.arguments}")
|
||||
```
|
||||
|
||||
## معالجة الأخطاء
|
||||
@@ -409,8 +408,8 @@ flow = ResearchFlow()
|
||||
streaming = flow.kickoff()
|
||||
|
||||
try:
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\nSuccess! Result: {result}")
|
||||
@@ -423,7 +422,7 @@ except Exception as e:
|
||||
|
||||
## الإلغاء وتنظيف الموارد
|
||||
|
||||
تدعم جلسة stream الإلغاء السلس بحيث يتوقف العمل الجاري فوراً عند انقطاع اتصال المستهلك.
|
||||
يدعم `FlowStreamingOutput` الإلغاء السلس بحيث يتوقف العمل الجاري فوراً عند انقطاع اتصال المستهلك.
|
||||
|
||||
### مدير السياق غير المتزامن
|
||||
|
||||
@@ -431,8 +430,8 @@ except Exception as e:
|
||||
streaming = await flow.kickoff_async()
|
||||
|
||||
async with streaming:
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
```
|
||||
|
||||
### الإلغاء الصريح
|
||||
@@ -440,8 +439,8 @@ async with streaming:
|
||||
```python Code
|
||||
streaming = await flow.kickoff_async()
|
||||
try:
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
finally:
|
||||
await streaming.aclose() # غير متزامن
|
||||
# streaming.close() # المكافئ المتزامن
|
||||
@@ -452,10 +451,10 @@ finally:
|
||||
## ملاحظات مهمة
|
||||
|
||||
- يفعّل البث تلقائياً بث LLM لأي أطقم مستخدمة داخل التدفق
|
||||
- يجب التكرار عبر جميع عناصر stream قبل الوصول إلى خاصية `.result`
|
||||
- يجب التكرار عبر جميع الأجزاء قبل الوصول إلى خاصية `.result`
|
||||
- يعمل البث مع كل من حالة التدفق المنظمة وغير المنظمة
|
||||
- يلتقط بث التدفق المخرجات من جميع الأطقم واستدعاءات LLM في التدفق
|
||||
- يتضمن كل إطار سياق حدث مهيكلاً مثل القناة والنوع والنطاق والحمولة
|
||||
- يتضمن كل جزء سياقاً حول الوكيل والمهمة التي ولدته
|
||||
- يضيف البث حملاً ضئيلاً لتنفيذ التدفق
|
||||
|
||||
## الدمج مع تصور التدفق
|
||||
@@ -469,8 +468,8 @@ flow.plot("research_flow") # Creates HTML visualization
|
||||
|
||||
# Run with streaming
|
||||
streaming = flow.kickoff()
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\nFlow complete! View structure at: research_flow.html")
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
title: عقد بث وقت التشغيل
|
||||
description: بث إطارات وقت تشغيل مرتبة من التدفقات واستدعاءات LLM المباشرة ودورات المحادثة.
|
||||
icon: tower-broadcast
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
يوفر CrewAI عقد بث قائمًا على الإطارات للأنظمة التي تحتاج إلى أكثر من أجزاء نصية بسيطة. يصدر العقد كائنات `StreamFrame` مرتبة لأحداث دورة حياة Flow، وتوكنات LLM المباشرة، ونشاط الأدوات، ورسائل المحادثة، والأحداث المخصصة.
|
||||
|
||||
استخدم هذه الواجهة عندما تبني واجهة مستخدم، أو جسر خدمة، أو تطبيق طرفية، أو وقت تشغيل نشر يحتاج إلى تدفق ثابت من الأحداث المهيكلة أثناء تشغيل Flow أو دورة محادثة أو استدعاء LLM مباشر.
|
||||
|
||||
## StreamFrame
|
||||
|
||||
لكل إطار نفس الغلاف:
|
||||
|
||||
```python
|
||||
from crewai.types.streaming import StreamFrame
|
||||
|
||||
frame.id # معرف إطار فريد
|
||||
frame.seq # ترتيب محلي للتنفيذ، عند توفره
|
||||
frame.type # نوع الحدث المصدر، مثل "flow_started"
|
||||
frame.channel # "llm", "flow", "tools", "messages", "lifecycle", or "custom"
|
||||
frame.namespace # نطاق المصدر/وقت التشغيل
|
||||
frame.timestamp # طابع وقت الحدث
|
||||
frame.parent_id # معرف الحدث الأب، عند توفره
|
||||
frame.previous_id # معرف الحدث السابق، عند توفره
|
||||
frame.data # حمولة الحدث
|
||||
frame.event # اسم بديل لـ frame.data
|
||||
frame.content # نص قابل للطباعة لإطارات التوكن، وإلا ""
|
||||
```
|
||||
|
||||
حقل `channel` هو أسرع طريقة لتوجيه الإطارات في المستهلكين:
|
||||
|
||||
| القناة | تحتوي على |
|
||||
|--------|-----------|
|
||||
| `llm` | توكنات وأجزاء التفكير من أحداث بث LLM |
|
||||
| `flow` | دورة حياة Flow، وتنفيذ الدوال، والتوجيه، وأحداث الإيقاف/الاستئناف |
|
||||
| `tools` | أحداث استخدام الأدوات |
|
||||
| `messages` | أحداث سجل المحادثة |
|
||||
| `lifecycle` | أحداث دورة حياة وقت التشغيل التي لا تخص قناة أخرى |
|
||||
| `custom` | أحداث لا تُطابق قناة مدمجة |
|
||||
|
||||
يحافظ `frame.type` على نوع الحدث المصدر، حتى يتمكن المستهلكون من التعامل مع أحداث محددة داخل القناة.
|
||||
|
||||
## بث Flow
|
||||
|
||||
عيّن `stream=True` على Flow لجعل `kickoff()` يعيد جلسة stream:
|
||||
|
||||
```python
|
||||
from crewai.flow import Flow, start
|
||||
|
||||
|
||||
class ReportFlow(Flow):
|
||||
@start()
|
||||
def generate(self):
|
||||
return "done"
|
||||
|
||||
|
||||
flow = ReportFlow(stream=True)
|
||||
stream = flow.kickoff()
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
if chunk.type == "tool_usage_started":
|
||||
print(chunk.event["tool_name"])
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
يجب استهلاك stream قبل قراءة `stream.result`. يؤدي الوصول إلى النتيجة مبكرًا إلى رفع `RuntimeError` حتى لا يتعامل المستهلكون بالخطأ مع تشغيل جزئي على أنه مكتمل.
|
||||
|
||||
يمكنك أيضًا استدعاء `flow.stream_events(...)` مباشرة عندما تريد البث لاستدعاء واحد بدون تعيين `stream=True` على مثيل Flow.
|
||||
|
||||
## التصفية حسب القناة
|
||||
|
||||
يوفر `StreamSession` إسقاطات حسب القناة تحافظ على ترتيب الإطارات العالمي داخل القناة المحددة:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
الإسقاطات المتاحة هي:
|
||||
|
||||
| الإسقاط | الإطارات |
|
||||
|---------|----------|
|
||||
| `stream.events` | كل الإطارات |
|
||||
| `stream.llm` | إطارات LLM |
|
||||
| `stream.messages` | إطارات رسائل المحادثة |
|
||||
| `stream.flow` | إطارات Flow |
|
||||
| `stream.tools` | إطارات الأدوات |
|
||||
| `stream.interleave([...])` | مجموعة مختارة من القنوات |
|
||||
|
||||
استخدم `stream.interleave(["flow", "llm", "messages"])` عندما يريد المستهلك بعض القنوات فقط لكنه ما زال يحتاج إلى ترتيبها النسبي.
|
||||
|
||||
## البث غير المتزامن
|
||||
|
||||
استخدم `astream()` للمستهلكين غير المتزامنين:
|
||||
|
||||
```python
|
||||
flow = ReportFlow()
|
||||
stream = flow.astream()
|
||||
|
||||
async with stream:
|
||||
async for chunk in stream.events:
|
||||
print(chunk.channel, chunk.type, chunk.content)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
تملك الجلسة غير المتزامنة نفس إسقاطات الجلسة المتزامنة.
|
||||
|
||||
## بث استدعاء LLM مباشر
|
||||
|
||||
ما زال `llm.call(...)` يعيد النتيجة النهائية المجمعة. استخدم `llm.stream_events(...)` عندما تريد التكرار على الأجزاء فور وصولها مع الحفاظ على حمولة الحدث المهيكلة:
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
stream = llm.stream_events(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Explain CrewAI streaming in two short sentences.",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
يفعل `llm.stream_events(...)` البث مؤقتًا للاستدعاء المغلف ثم يستعيد إعداد `stream` السابق في LLM بعد ذلك. تستمر تكاملات المزودين في إصدار أحداث بث LLM الأساسية؛ يوفر هذا المساعد واجهة مكرر مشتركة فوق تلك الأحداث لكل مزودي LLM.
|
||||
|
||||
## دورات المحادثة
|
||||
|
||||
يمكن للتدفقات المحادثية بث دورة مستخدم واحدة باستخدام `stream_turn()`:
|
||||
|
||||
```python
|
||||
from crewai import Flow
|
||||
from crewai.experimental.conversational import ConversationConfig, ConversationState
|
||||
|
||||
|
||||
@ConversationConfig(llm="gpt-4o-mini", defer_trace_finalization=True)
|
||||
class ChatFlow(Flow[ConversationState]):
|
||||
conversational = True
|
||||
|
||||
|
||||
flow = ChatFlow()
|
||||
stream = flow.stream_turn("What can you help me with?", session_id="session-1")
|
||||
|
||||
with stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.type == "llm_stream_chunk":
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
reply = stream.result
|
||||
```
|
||||
|
||||
أثناء `stream_turn()`، يفعّل مسار الإجابة المحادثية المدمج بث توكنات LLM لذلك الدور ثم يستعيد إعداد `stream` السابق في LLM بعد ذلك. يجب على معالجات المسارات المخصصة التي تنشئ Agents أو مثيلات LLM خاصة بها تهيئة تلك النماذج للبث إذا احتاجت إلى إخراج على مستوى التوكن.
|
||||
|
||||
## التنظيف
|
||||
|
||||
استخدم الجلسة كمدير سياق عندما يكون ذلك ممكنًا. إذا انقطع اتصال العميل قبل استهلاك stream بالكامل، فأغلق الجلسة صراحة:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
try:
|
||||
for frame in stream.events:
|
||||
print(frame.type)
|
||||
finally:
|
||||
if not stream.is_exhausted:
|
||||
stream.close()
|
||||
```
|
||||
|
||||
للتدفقات غير المتزامنة، استخدم `await stream.aclose()`.
|
||||
|
||||
## بث الأجزاء القديم
|
||||
|
||||
ما زال بث Crew مع `stream=True` يعيد واجهة `CrewStreamingOutput` المعتمدة على الأجزاء والموضحة في [بث تنفيذ Crew](/ar/learn/streaming-crew-execution). وما زالت استدعاءات `llm.call(...)` المباشرة تعيد نتيجة LLM النهائية. عقد الإطارات مخصص لأوقات التشغيل التي تحتاج إلى غلاف حدث ثابت عبر Flows، واستدعاءات LLM المباشرة، ودورات المحادثة، والأدوات، والرسائل.
|
||||
@@ -4,396 +4,6 @@ description: "Product updates, improvements, and bug fixes for CrewAI"
|
||||
icon: "clock"
|
||||
mode: "wide"
|
||||
---
|
||||
<Update label="Jul 17, 2026">
|
||||
## v1.15.4
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.4)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Promote Skills Repository out of experimental status
|
||||
|
||||
### Documentation
|
||||
- Add Flows in Studio documentation
|
||||
|
||||
## Contributors
|
||||
|
||||
@jessemiller, @joaomdmoura, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jul 16, 2026">
|
||||
## v1.15.3
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Add organization ID parameter to PlusAPI client
|
||||
- Add step interception points and rework execution hooks documentation around @on
|
||||
- Wire execution-boundary interception points
|
||||
- Add generic interception-hook dispatcher
|
||||
- Run declarative flows on the TUI (headless terminal fallback)
|
||||
|
||||
### Bug Fixes
|
||||
- Sync kickoff-completed event with OUTPUT hook result
|
||||
- Fix null repository agent attributes
|
||||
- Ensure after_llm_call hooks do not break native tool execution
|
||||
- Avoid double-append of the turn reply when a handler trims history
|
||||
- Make tool-result caching opt-in instead of on by default
|
||||
- Stop rewriting the authored tool description at construction
|
||||
- Expose token usage under both names on agent and crew results
|
||||
- Report per-call usage metrics on kickoff results
|
||||
- Stop replaying previous turn's intent when route_turn() returns falsy
|
||||
|
||||
### Documentation
|
||||
- Update execution hooks grouping and document all hook contexts
|
||||
|
||||
## Contributors
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jul 16, 2026">
|
||||
## v1.15.3a2
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a2)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Bug Fixes
|
||||
- Fix synchronization of kickoff-completed event with OUTPUT hook result
|
||||
|
||||
### Documentation
|
||||
- Update snapshot and changelog for v1.15.3a1
|
||||
|
||||
### Dependency Updates
|
||||
- Bump setuptools to 0.83.0 to address PYSEC-2026-3447
|
||||
|
||||
## Contributors
|
||||
|
||||
@lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jul 16, 2026">
|
||||
## v1.15.3a1
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a1)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Add organization ID parameter to PlusAPI client.
|
||||
- Add step interception points and rework execution hooks documentation around `@on`.
|
||||
- Wire execution-boundary interception points.
|
||||
- Add generic interception-hook dispatcher.
|
||||
- Run declarative flows on the TUI (headless terminal fallback).
|
||||
- Improve custom OpenAI URLs.
|
||||
|
||||
### Bug Fixes
|
||||
- Fix null repository agent attributes.
|
||||
- Fix `after_llm_call` hooks to prevent breaking native tool execution.
|
||||
- Stop double-appending the turn reply when a handler trims history.
|
||||
- Make tool-result caching opt-in instead of on by default.
|
||||
- Stop rewriting the authored tool description at construction.
|
||||
- Expose token usage under both names on agent and crew results.
|
||||
- Report per-call usage metrics on kickoff results.
|
||||
- Stop replaying the previous turn's intent when `route_turn()` returns falsy.
|
||||
- Drain memory writes before kickoff and flow completion events.
|
||||
|
||||
### Documentation
|
||||
- Group execution hooks and document all hook contexts.
|
||||
- Update documentation for execution hooks.
|
||||
|
||||
## Contributors
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jul 07, 2026">
|
||||
## v1.15.2
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Pull latest LLM models dynamically in the crew wizard.
|
||||
- Support inline skill definitions.
|
||||
- Add generated Flow Definition authoring skill.
|
||||
- Support templated Flow action inputs.
|
||||
- Add text helper for flow CEL prompts.
|
||||
- Add text helper to flow skill example.
|
||||
- Implement message setup and feedback handling in AgentExecutor.
|
||||
- Add repository agents to flow definitions.
|
||||
- Define stream frame protocol for flows.
|
||||
- Type tool and app in CrewDefinition.
|
||||
- Repoint template commands to crewAIInc-fde org.
|
||||
|
||||
### Bug Fixes
|
||||
- Key model-catalog cache by exact API key, shorten TTL, and skip Ollama.
|
||||
- Unify `crewai run` flow input resolution and prompt from the state schema.
|
||||
- Resolve pip-audit failures for onnx 1.22.0 and nltk PYSEC-2026-597.
|
||||
- Ensure we are writing version for flows.
|
||||
- Include aiobotocore in the bedrock extra.
|
||||
- Reject self-listening flow methods.
|
||||
- Cut docs version nav from Edge so new pages aren't dropped.
|
||||
|
||||
### Documentation
|
||||
- Update language from Rules to Policies to match new dashboard changes.
|
||||
- Document flow agent options.
|
||||
- Add streaming docs to the navigation.
|
||||
- Document Cost Limit rule type in Agent Control Plane.
|
||||
- Drop CREWAI_LOG_FORMAT references from Datadog guide.
|
||||
|
||||
## Contributors
|
||||
|
||||
@akaKuruma, @danielfsbarreto, @github-code-quality[bot], @joaomdmoura, @lorenzejay, @lucasgomide, @manisrinivasan2k1, @renatonitta, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jul 01, 2026">
|
||||
## v1.15.2a2
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a2)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Add aiobotocore to the bedrock extra
|
||||
- Document flow agent options
|
||||
- Add text helper to flow skill example
|
||||
- Add text helper for flow CEL prompts
|
||||
- Add streaming docs to the navigation
|
||||
|
||||
### Bug Fixes
|
||||
- Reject self-listening flow methods
|
||||
|
||||
### Documentation
|
||||
- Update snapshot and changelog for v1.15.2a1
|
||||
- Squeeze AGENTS.md file
|
||||
|
||||
## Contributors
|
||||
|
||||
@akaKuruma, @github-code-quality[bot], @lorenzejay, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 30, 2026">
|
||||
## v1.15.2a1
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a1)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Repoint template commands to crewAIInc-fde org
|
||||
- Support inline skill definitions
|
||||
- Define stream frame protocol for flows
|
||||
- Add type tool and app in CrewDefinition
|
||||
- Add generated Flow Definition authoring skill
|
||||
|
||||
### Bug Fixes
|
||||
- Cut docs version navigation from Edge to prevent new pages from being dropped
|
||||
|
||||
### Documentation
|
||||
- Document Cost Limit rule type in Agent Control Plane
|
||||
- Drop CREWAI_LOG_FORMAT references from Datadog guide
|
||||
|
||||
## Contributors
|
||||
|
||||
@danielfsbarreto, @joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 26, 2026">
|
||||
## v1.15.1
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Initialize Git repositories for generated projects (#6364)
|
||||
- Require explicit CrewAI project definitions (#6358)
|
||||
- Open deployment page after CLI deploy (#6343)
|
||||
|
||||
### Bug Fixes
|
||||
- Fix deployment page link ID resolution (#6365)
|
||||
- Fix JSON crew template rendering (#6359)
|
||||
- Fix JSON crew version pin (#6342)
|
||||
- Fix SSRF redirect bypass in scraping fetches (#6331)
|
||||
|
||||
### Documentation
|
||||
- Improve open source positioning in README (#6363)
|
||||
- Improve coding agent setup call-to-action (#6344)
|
||||
- Add snapshot and changelog for version 1.15.1a1 (#6362)
|
||||
|
||||
## Contributors
|
||||
|
||||
@joaomdmoura, @lorenzejay, @oalami, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<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 release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.0)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Track conversational flow turn usage in telemetry
|
||||
- Support conversational flows in the CLI TUI
|
||||
- Add unified declarative flow loading
|
||||
- Add declarative Flow CLI support
|
||||
- Add optional if expression to each.do steps
|
||||
- Add single agent action to Flow definitions
|
||||
- Add crew actions to FlowDefinition
|
||||
- Add inline crew definition loading
|
||||
- Add `each` composite action to FlowDefinition
|
||||
- Implement DMN mode support in crew creation and execution
|
||||
|
||||
### Bug Fixes
|
||||
- Fix owner-only permissions enforcement on credential files
|
||||
- Fix JSON schema flow state kickoff inputs
|
||||
- Fix symlink path traversal in skill archive extraction
|
||||
- Aggregate token usage across all LLM calls
|
||||
- Remove duplicated Exa tool
|
||||
- Resolve JSON crew issues
|
||||
- Fix JSON crew handling and enhance memory reset functionality
|
||||
|
||||
### Documentation
|
||||
- Update installation and quickstart documentation for JSON-first crew projects
|
||||
- Add Datadog integration guide with importable operations dashboard
|
||||
- Add "One Card per Step" Studio page
|
||||
- Add snapshots and changelogs for previous versions leading to v1.15.0
|
||||
|
||||
### Performance
|
||||
- Improve crewai run startup UX
|
||||
- Keep flow method progress visible for nested crews
|
||||
|
||||
### Refactoring
|
||||
- Remove `StateProxy` from flow state access
|
||||
- Consolidate `crewai run` and `crewai flow kickoff`
|
||||
- Discriminate FlowDefinition state types
|
||||
- Wire config and persistence from FlowDefinition into the runtime
|
||||
|
||||
## Contributors
|
||||
|
||||
@gabemilani, @github-code-quality[bot], @greysonlalonde, @iris-clawd, @jessemiller, @joaomdmoura, @lorenzejay, @lucasgomide, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 24, 2026">
|
||||
## v1.14.8a5
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a5)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Make declarative refs work across flows and crews (#6326)
|
||||
|
||||
### Bug Fixes
|
||||
- Fix JSON schema flow state kickoff inputs (#6325)
|
||||
|
||||
### Documentation
|
||||
- Nest One Card per Step under Crew Studio and drop rollout banner (AGE-107) (#6317)
|
||||
- Update snapshot and changelog for v1.14.8a4 (#6319)
|
||||
|
||||
### Refactoring
|
||||
- Remove `StateProxy` from flow state access (#6327)
|
||||
|
||||
## Contributors
|
||||
|
||||
@jessemiller, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 24, 2026">
|
||||
## v1.14.8a4
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a4)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Support conversational flows in the CLI TUI.
|
||||
|
||||
### Bug Fixes
|
||||
- Fix symlink path traversal in skill archive extraction.
|
||||
- Validate declarative flow definition paths.
|
||||
|
||||
### Documentation
|
||||
- Update snapshot and changelog for v1.14.8a3.
|
||||
|
||||
## Contributors
|
||||
|
||||
@lorenzejay, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 23, 2026">
|
||||
## v1.14.8a3
|
||||
|
||||
[View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a3)
|
||||
|
||||
## What's Changed
|
||||
|
||||
### Features
|
||||
- Add unified declarative flow loading
|
||||
- Improve crewai run startup UX
|
||||
- Consolidate `crewai run` and `crewai flow kickoff`
|
||||
- Keep flow method progress visible for nested crews
|
||||
- Add declarative Flow CLI support
|
||||
- Allow `@router()` as start method of a flow
|
||||
- Add typed output schemas for CrewAI tools
|
||||
|
||||
### Bug Fixes
|
||||
- Pin opentelemetry to ~=1.42.0
|
||||
|
||||
### Documentation
|
||||
- Add "One Card per Step" Studio page
|
||||
|
||||
## Contributors
|
||||
|
||||
@jessemiller, @joaomdmoura, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="Jun 18, 2026">
|
||||
## v1.14.8a2
|
||||
|
||||
|
||||
@@ -144,18 +144,6 @@ In this section, you'll find detailed examples that help you select, configure,
|
||||
)
|
||||
```
|
||||
|
||||
**Custom OpenAI-Compatible Endpoint:**
|
||||
```python Code
|
||||
from crewai import LLM
|
||||
|
||||
llm = LLM(
|
||||
model="anthropic/claude-sonnet-4-6",
|
||||
custom_openai=True,
|
||||
base_url="https://your-gateway.example.com/v1",
|
||||
api_key="your-gateway-api-key",
|
||||
)
|
||||
```
|
||||
|
||||
**Advanced Configuration:**
|
||||
```python Code
|
||||
from crewai import LLM
|
||||
|
||||
@@ -24,23 +24,15 @@ You often need **both**: skills for expertise, tools for action. They are config
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create a Skill with the CLI
|
||||
|
||||
The CLI is the supported way to create a skill — it scaffolds the directory layout and a valid `SKILL.md` for you:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create code-review
|
||||
```
|
||||
|
||||
Inside a crew project (where `pyproject.toml` lives) this creates `./skills/code-review/`; outside a project it creates `./code-review/` in the current directory (you can force that behavior with `--no-project`):
|
||||
### 1. Create a Skill Directory
|
||||
|
||||
```
|
||||
skills/
|
||||
└── code-review/
|
||||
├── SKILL.md # Required — instructions (pre-filled template)
|
||||
├── SKILL.md # Required — instructions
|
||||
├── references/ # Optional — reference docs
|
||||
├── scripts/ # Optional — executable scripts
|
||||
└── assets/ # Optional — static files
|
||||
│ └── style-guide.md
|
||||
└── scripts/ # Optional — executable scripts
|
||||
```
|
||||
|
||||
### 2. Write Your SKILL.md
|
||||
@@ -172,65 +164,6 @@ agent = Agent(
|
||||
|
||||
---
|
||||
|
||||
## Creating, Publishing, and Installing Skills
|
||||
|
||||
Skills have a full lifecycle managed by the CLI: **create them with `crewai skill create`, publish them with `crewai skill publish`** — hand-rolling directories works for local experiments, but the CLI is the intended workflow and keeps your skill layout and frontmatter valid.
|
||||
|
||||
### Create
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create my-skill
|
||||
```
|
||||
|
||||
Scaffolds the directory (into `./skills/` inside a crew project) with a template `SKILL.md`, plus empty `scripts/`, `references/`, and `assets/` directories. Edit `SKILL.md` to define the instructions.
|
||||
|
||||
### Publish
|
||||
|
||||
Run from inside the skill directory (where `SKILL.md` is):
|
||||
|
||||
```shell Terminal
|
||||
cd skills/my-skill
|
||||
crewai skill publish
|
||||
```
|
||||
|
||||
Publishing reads `name`, `description`, and `metadata.version` from the `SKILL.md` frontmatter and pushes the skill to the CrewAI registry. **Published skills are always scoped to your organization** — like tools, only members of the publishing org can see and install them; there is no public visibility. Useful flags:
|
||||
|
||||
| Flag | Effect |
|
||||
| :--- | :--- |
|
||||
| `--org <slug>` | Publish under a specific organization (overrides settings). |
|
||||
| `--force` | Skip git-state validation (uncommitted changes, etc.). |
|
||||
|
||||
### Install
|
||||
|
||||
Install a published skill by its `@org/name` reference:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill install @acme/code-review
|
||||
```
|
||||
|
||||
Inside a crew project the skill lands in `./skills/{name}/`; outside a project it goes to the shared cache at `~/.crewai/skills/{org}/{name}/`.
|
||||
|
||||
Agents can also reference registry skills directly — they resolve from the local cache (or project `skills/` directory) at runtime:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
role="Senior Code Reviewer",
|
||||
goal="Review pull requests for quality and security issues",
|
||||
backstory="Staff engineer with expertise in secure coding practices.",
|
||||
skills=["@acme/code-review"], # registry ref, resolved locally
|
||||
)
|
||||
```
|
||||
|
||||
### List
|
||||
|
||||
```shell Terminal
|
||||
crewai skill list
|
||||
```
|
||||
|
||||
Shows installed skills from both the project `./skills/` directory and the global cache, with their versions and paths.
|
||||
|
||||
---
|
||||
|
||||
## Crew-Level Skills
|
||||
|
||||
Skills can be set on a crew to apply to **all agents**:
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
---
|
||||
title: Streaming
|
||||
description: Understand CrewAI's streaming model for Flows, direct LLM calls, tools, and conversational turns.
|
||||
icon: radio
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Streaming lets your application receive execution updates while work is still running. Instead of waiting for the final result, you can render LLM tokens, tool activity, Flow lifecycle events, and conversation messages as they happen.
|
||||
|
||||
CrewAI has two streaming surfaces:
|
||||
|
||||
| Surface | Used by | Output |
|
||||
|---------|---------|--------|
|
||||
| Frame streaming | Flows, direct LLM calls, conversational turns | Ordered `StreamFrame` objects |
|
||||
| Crew chunk streaming | Crews with `stream=True` | `CrewStreamingOutput` chunks |
|
||||
|
||||
For new runtime integrations, UIs, terminal apps, service bridges, and conversational surfaces, use frame streaming. It provides one stable event envelope across the runtime.
|
||||
|
||||
## StreamFrame
|
||||
|
||||
A `StreamFrame` is the common object emitted by streamable runtimes:
|
||||
|
||||
```python
|
||||
frame.id # unique frame id
|
||||
frame.seq # execution-local order, when available
|
||||
frame.type # source event type, such as "llm_stream_chunk"
|
||||
frame.channel # "llm", "flow", "tools", "messages", "lifecycle", or "custom"
|
||||
frame.namespace # source/runtime namespace
|
||||
frame.timestamp # event timestamp
|
||||
frame.parent_id # parent event id, when available
|
||||
frame.previous_id # previous event id, when available
|
||||
frame.data # structured event payload
|
||||
frame.event # alias for frame.data
|
||||
frame.content # printable text for token-like frames, otherwise ""
|
||||
```
|
||||
|
||||
The important fields for most consumers are:
|
||||
|
||||
| Field | Use it for |
|
||||
|-------|------------|
|
||||
| `channel` | Routing frames to the right UI region |
|
||||
| `type` | Handling a specific event inside a channel |
|
||||
| `content` | Printing token-like text |
|
||||
| `event` | Reading structured metadata, such as tool names or message roles |
|
||||
| `seq` | Preserving execution order |
|
||||
|
||||
## Channels
|
||||
|
||||
Frames are grouped into high-level channels:
|
||||
|
||||
| Channel | Contains |
|
||||
|---------|----------|
|
||||
| `llm` | LLM call lifecycle, text chunks, and thinking chunks |
|
||||
| `flow` | Flow lifecycle, method execution, routing, pause, and resume events |
|
||||
| `tools` | Tool usage start, finish, and error events |
|
||||
| `messages` | Conversation transcript events |
|
||||
| `lifecycle` | Runtime lifecycle events that do not belong to another channel |
|
||||
| `custom` | Events that do not map to a built-in channel |
|
||||
|
||||
The stream itself remains one ordered timeline. Channel projections let consumers focus on only part of that timeline.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["flow<br/>flow_started"] --> B["llm<br/>llm_call_started"]
|
||||
B --> C["llm<br/>llm_stream_chunk"]
|
||||
C --> D["tools<br/>tool_usage_started"]
|
||||
D --> E["tools<br/>tool_usage_finished"]
|
||||
E --> F["llm<br/>llm_stream_chunk"]
|
||||
F --> G["flow<br/>flow_finished"]
|
||||
```
|
||||
|
||||
## Stream Sessions
|
||||
|
||||
Frame streaming returns a stream session:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events(inputs={"topic": "AI agents"})
|
||||
```
|
||||
|
||||
The session is both an iterator and the holder for the final result:
|
||||
|
||||
```python
|
||||
with stream:
|
||||
for frame in stream:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Consume the stream before reading `stream.result`. Reading the result too early raises an error because the runtime may still be producing frames.
|
||||
|
||||
## Channel Projections
|
||||
|
||||
Use channel projections when you only need one kind of frame:
|
||||
|
||||
```python
|
||||
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Available projections:
|
||||
|
||||
| Projection | Frames |
|
||||
|------------|--------|
|
||||
| `stream.events` | All frames |
|
||||
| `stream.llm` | LLM frames |
|
||||
| `stream.flow` | Flow frames |
|
||||
| `stream.tools` | Tool frames |
|
||||
| `stream.messages` | Conversation message frames |
|
||||
| `stream.interleave([...])` | Selected channels in relative order |
|
||||
|
||||
## Entrypoints
|
||||
|
||||
Use the entrypoint that matches the runtime you are streaming:
|
||||
|
||||
| Runtime | Streaming entrypoint |
|
||||
|---------|----------------------|
|
||||
| Flow | `flow.stream_events(...)` |
|
||||
| Flow with `stream=True` | `flow.kickoff(...)` returns a stream session |
|
||||
| Async Flow | `flow.astream(...)` or `await flow.kickoff_async(...)` when `stream=True` |
|
||||
| Direct LLM call | `llm.stream_events(...)` |
|
||||
| Conversational Flow turn | `flow.stream_turn(...)` |
|
||||
| Crew | `Crew(..., stream=True).kickoff(...)` returns `CrewStreamingOutput` |
|
||||
|
||||
Direct `llm.call(...)` still returns the final assembled LLM result. Use `llm.stream_events(...)` when you want to iterate over LLM chunks as they arrive.
|
||||
|
||||
## Related Guides
|
||||
|
||||
- [Consuming Streams](/edge/en/learn/consuming-streams)
|
||||
- [Streaming Runtime Contract](/edge/en/learn/streaming-runtime-contract)
|
||||
- [Streaming Flow Execution](/edge/en/learn/streaming-flow-execution)
|
||||
- [Streaming Crew Execution](/edge/en/learn/streaming-crew-execution)
|
||||
@@ -11,7 +11,7 @@ mode: "wide"
|
||||
|
||||
- [Overview](/en/enterprise/features/agent-control-plane/overview)
|
||||
- **Monitoring** *(you are here)*
|
||||
- [Policies](/edge/en/enterprise/features/agent-control-plane/policies)
|
||||
- [Rules](/en/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
@@ -58,7 +58,7 @@ The **Automations** sub-tab is the per-deployment breakdown of fleet health. Eac
|
||||
| **Last execution** | Time since the most recent run. |
|
||||
| **Health Status Breakdown** | Stacked bar of `Critical` / `Warning` / `Healthy` percentages for executions in the window. |
|
||||
| **Executions with Errors** | Total failed executions in the window. |
|
||||
| **PII detection applied** | `Yes` if a per-deployment PII config or a matching [PII policy](/edge/en/enterprise/features/agent-control-plane/policies) is active. |
|
||||
| **PII detection applied** | `Yes` if a per-deployment PII config or a matching [PII rule](/en/enterprise/features/agent-control-plane/rules) is active. |
|
||||
| **Executions** | Total executions in the window. |
|
||||
| **Last updated** | When the deployment was last re-deployed. |
|
||||
| **Crew Version** | The `crewai` version reported by the deployment. An info icon next to versions below `1.13` flags rows that can't contribute metrics. |
|
||||
@@ -96,8 +96,8 @@ Filter by **LLM provider** and sort by `Cost`, `Executions`, or `Last run`.
|
||||
<Card title="Agent Control Plane — Overview" icon="book-open" href="/en/enterprise/features/agent-control-plane/overview">
|
||||
What ACP is, requirements, plan tiers, and RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — Policies" icon="shield-check" href="/edge/en/enterprise/features/agent-control-plane/policies">
|
||||
Apply organization-wide PII Redaction policies across many automations.
|
||||
<Card title="Agent Control Plane — Rules" icon="shield-check" href="/en/enterprise/features/agent-control-plane/rules">
|
||||
Apply organization-wide PII Redaction rules across many automations.
|
||||
</Card>
|
||||
<Card title="Traces" icon="timeline" href="/en/enterprise/features/traces">
|
||||
Drill into a single execution to see agent reasoning, tool calls, and token usage.
|
||||
|
||||
@@ -10,17 +10,17 @@ icon: "book-open"
|
||||
|
||||
- **Overview** *(you are here)*
|
||||
- [Monitoring](/en/enterprise/features/agent-control-plane/monitoring)
|
||||
- [Policies](/edge/en/enterprise/features/agent-control-plane/policies)
|
||||
- [Rules](/en/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
|
||||
The **Agent Control Plane** (ACP) is the operations hub for everything you have running on CrewAI AMP. It is a single screen — split into **Automations** and **Policies** tabs — that lets your team:
|
||||
The **Agent Control Plane** (ACP) is the operations hub for everything you have running on CrewAI AMP. It is a single screen — split into **Automations** and **Rules** tabs — that lets your team:
|
||||
|
||||
- Monitor the **health** of every live automation (crew or flow), with `Critical` / `Warning` / `Healthy` breakdowns and execution counts.
|
||||
- Track **LLM consumption** — tokens and cost — per automation, per provider, and per model, with a delta vs the previous period.
|
||||
- Drill into any single automation or model provider for time-series charts and per-provider breakdowns.
|
||||
- Apply organization-wide **Policies** (today: PII Redaction and Cost Limit) across many automations at once instead of editing each deployment individually.
|
||||
- Apply organization-wide **Rules** (today: PII Redaction) across many automations at once instead of editing each deployment individually.
|
||||
|
||||
<Frame>
|
||||

|
||||
@@ -33,7 +33,7 @@ The **Agent Control Plane** (ACP) is the operations hub for everything you have
|
||||
The two tabs answer two different questions:
|
||||
|
||||
- **Automations** — *"How is my fleet behaving right now, and what is it costing me?"* See [Monitoring](/en/enterprise/features/agent-control-plane/monitoring).
|
||||
- **Policies** — *"How do I enforce a policy (e.g. PII redaction or a spend budget) across many deployments without re-deploying each one?"* See [Policies](/edge/en/enterprise/features/agent-control-plane/policies).
|
||||
- **Rules** — *"How do I enforce a policy (e.g. PII redaction) across many deployments without re-deploying each one?"* See [Rules](/en/enterprise/features/agent-control-plane/rules).
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -42,11 +42,11 @@ The two tabs answer two different questions:
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
**Enterprise Plan or Ultra Plan** is required to create or edit **PII Redaction** [Policies](/edge/en/enterprise/features/agent-control-plane/policies). Lower-tier organizations can open the Policies tab and view existing policies, but the PII editor renders read-only with an "Enterprise" lock pill and the alert *"PII Redaction policies require an Enterprise plan."* **Cost Limit** policies and Monitoring (the Automations tab) are available on all plans where the feature is enabled.
|
||||
**Enterprise Plan or Ultra Plan** is required to create or edit [Rules](/en/enterprise/features/agent-control-plane/rules). Lower-tier organizations can open the Rules tab and view existing rules, but the editor renders read-only with an "Enterprise" lock pill and the alert *"PII Redaction rules require an Enterprise plan."* Monitoring (the Automations tab) is available on all plans where the feature is enabled.
|
||||
</Warning>
|
||||
|
||||
- The **Agent Control Plane** feature must be enabled for your organization. If you don't see it in the sidebar, ask your account owner to request enablement.
|
||||
- Inside ACP, [RBAC](/en/enterprise/features/rbac) governs access: `read` to view the dashboard and policies, `manage` to create, edit, toggle, or delete policies.
|
||||
- Inside ACP, [RBAC](/en/enterprise/features/rbac) governs access: `read` to view the dashboard and rules, `manage` to create, edit, toggle, or delete rules.
|
||||
- All charts and tables can be scoped to the **Last 24 hours**, **Last Week**, or **Last 30 days** using the time selector at the top right. Deltas (`↑ 8 vs yesterday`, `↓ $20.57 vs yesterday`, etc.) compare the selected window against the previous one of the same length.
|
||||
|
||||
## What you can do here
|
||||
@@ -55,8 +55,8 @@ The two tabs answer two different questions:
|
||||
<Card title="Monitoring" icon="gauge" href="/en/enterprise/features/agent-control-plane/monitoring">
|
||||
Watch fleet health and LLM spend with metric cards, an interactive sankey, per-automation tables, and drill-down side panels for any automation or provider.
|
||||
</Card>
|
||||
<Card title="Policies" icon="shield-check" href="/edge/en/enterprise/features/agent-control-plane/policies">
|
||||
Apply organization-wide PII Redaction and Cost Limit policies scoped by tools and tags. Changes take effect on the next execution — no re-deploy required.
|
||||
<Card title="Rules" icon="shield-check" href="/en/enterprise/features/agent-control-plane/rules">
|
||||
Apply organization-wide PII Redaction policies scoped by tools and tags. Changes take effect on the next execution — no re-deploy required.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -67,10 +67,10 @@ The two tabs answer two different questions:
|
||||
Drill into a single execution to see agent reasoning, tool calls, and token usage.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/en/enterprise/features/rbac">
|
||||
Manage who can read the Agent Control Plane and who can edit policies.
|
||||
Manage who can read the Agent Control Plane and who can edit rules.
|
||||
</Card>
|
||||
<Card title="PII Redaction for Traces" icon="lock" href="/en/enterprise/features/pii-trace-redactions">
|
||||
Entity catalog and per-deployment PII configuration referenced by Policies.
|
||||
Entity catalog and per-deployment PII configuration referenced by Rules.
|
||||
</Card>
|
||||
<Card title="Deploy to AMP" icon="rocket" href="/en/enterprise/guides/deploy-to-amp">
|
||||
Deploy a crew on a crewAI version that supports the Agent Control Plane.
|
||||
@@ -78,5 +78,5 @@ The two tabs answer two different questions:
|
||||
</CardGroup>
|
||||
|
||||
<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
|
||||
Contact our support team for help interpreting metrics or designing policies.
|
||||
Contact our support team for help interpreting metrics or designing rules.
|
||||
</Card>
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
---
|
||||
title: "Set up the Policies"
|
||||
description: "Apply organization-wide policies across many automations from a single place."
|
||||
sidebarTitle: "Policies"
|
||||
icon: "shield-check"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**ACP (Beta) Docs Navigation**
|
||||
|
||||
- [Overview](/en/enterprise/features/agent-control-plane/overview)
|
||||
- [Monitoring](/en/enterprise/features/agent-control-plane/monitoring)
|
||||
- **Policies** *(you are here)*
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
|
||||
Policies let you enforce organization-wide controls — today **PII Redaction** and **Cost Limit** — across many automations at once, instead of configuring each deployment individually. Open the **Policies** tab in the [Agent Control Plane](/en/enterprise/features/agent-control-plane/overview) to manage them.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Each policy card shows the name, description, the **scope** the policy applies to (selected tools and tags), and a count of **engaged automations** — deployments that currently match the scope. The toggle on the right enables or disables the policy without deleting it.
|
||||
|
||||
## Requirements
|
||||
|
||||
<Warning>
|
||||
**Enterprise Plan or Ultra Plan** is required to create or edit **PII Redaction** policies. Lower-tier organizations can still open the Policies tab and view existing policies, but the PII editor renders read-only with an "Enterprise" lock pill and the alert *"PII Redaction policies require an Enterprise plan."* — contact your account owner or sales to upgrade. **Cost Limit** policies are **not** plan-gated and can be created on any plan where the Agent Control Plane is enabled.
|
||||
</Warning>
|
||||
|
||||
- The **Agent Control Plane** feature must be enabled for your organization. See [Overview — Requirements](/en/enterprise/features/agent-control-plane/overview#requirements).
|
||||
- The `manage` [RBAC permission](/en/enterprise/features/rbac) on Agent Control Plane is required to create, edit, toggle, or delete policies. The `read` permission is enough to view them.
|
||||
- All policy changes are versioned for auditing.
|
||||
|
||||
## Policy types
|
||||
|
||||
Every policy is one of the types below. Open the tab for the policy you want to enforce.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="PII Redaction">
|
||||
Applies PII redaction to executions of every matching automation, using the same entity catalog and custom recognizers documented in [PII Redaction for Traces](/en/enterprise/features/pii-trace-redactions).
|
||||
|
||||
<Warning>
|
||||
Creating or editing PII Redaction policies requires an **Enterprise** or **Ultra** plan. On lower tiers the PII editor renders read-only with an "Enterprise" lock pill.
|
||||
</Warning>
|
||||
|
||||
**Configuration** — in the **PII Mask Type** table, check each entity type you want covered and choose how to handle it:
|
||||
|
||||
- **Mask** — replaces the match with the entity label (e.g. `<CREDIT_CARD>`).
|
||||
- **Redact** — removes the matched text entirely.
|
||||
|
||||
See [PII Redaction for Traces](/en/enterprise/features/pii-trace-redactions) for the full entity catalog and how to add organization-level custom recognizers.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Cost Limit">
|
||||
Emails the recipients you choose when a matching automation's LLM spend exceeds a budget threshold in the selected period. Available on **all plans** where the Agent Control Plane is enabled — it is not Enterprise-gated.
|
||||
|
||||
<Warning>
|
||||
Cost Limit policies are **notify-only**. They never pause, throttle, or stop a run — they only send an email so a human can decide what to do. Adjust the budget or remove the policy if you no longer want the alert.
|
||||
</Warning>
|
||||
|
||||
**Configuration**
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| **Budget period** | The window spend is measured over: **Daily**, **Weekly**, or **Monthly** (default *Monthly*). Spend resets at the start of each calendar period. |
|
||||
| **Threshold (USD)** | The dollar amount that triggers an alert. Must be greater than `0`. The alert fires once the automation's spend for the current period exceeds this value. |
|
||||
| **Recipient emails** | Up to 50 email addresses. Type an address and press **Enter** or comma to add it as a chip; **Backspace** removes the last chip. These do not need to be CrewAI users. |
|
||||
| **Notify roles** | Optionally select organization [roles](/en/enterprise/features/rbac); the alert is sent to every member of the chosen roles. Roles with no members can't be selected. You must provide at least one recipient — an email or a role. |
|
||||
| **Re-alert frequency** | How often the alert can re-fire while an automation stays over budget: **Once per period**, **Every hour while over**, **Every 4h while over**, or **Daily while over**. Re-alerts are capped at 24 per period. |
|
||||
|
||||
**How spend is measured and matched**
|
||||
|
||||
- The threshold is evaluated **per automation**, not summed across the whole scope. Each engaged automation has its own running total for the period.
|
||||
- A policy can match many automations via its conditions (tools/tags), and a single automation can be covered by **multiple** Cost Limit policies at once. Each policy tracks its own budget and alert state independently — they don't merge.
|
||||
- A background check compares each engaged automation's period-to-date spend against the threshold and sends the email when it's exceeded. Because the check runs periodically, expect a short delay between crossing the threshold and the email arriving.
|
||||
|
||||
**The alert email**
|
||||
|
||||
When an automation goes over budget, recipients get an email summarizing the overage — the automation name, the **current spend**, the **budget threshold**, and how far over it is in both dollars and percent (e.g. `$0.38` current vs a `$0.10` budget = `+277%`). The email reiterates that the run was **not** paused.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
More policy types will be added over time.
|
||||
|
||||
## Creating a policy
|
||||
|
||||
<Tabs>
|
||||
<Tab title="PII Redaction">
|
||||
<Frame>
|
||||
<img src="/images/enterprise/acp-policies-new-side-panel.png" alt="New Policy side panel configured for PII Redaction with the PII mask type table" width="450" />
|
||||
</Frame>
|
||||
</Tab>
|
||||
<Tab title="Cost Limit">
|
||||
<Frame>
|
||||
<img src="/images/enterprise/acp-policies-edit-cost-limit.png" alt="New Policy side panel configured for Cost Limit with budget period, threshold, and recipient emails" width="450" />
|
||||
</Frame>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Steps>
|
||||
<Step title="Open the editor">
|
||||
Click **+ Create new** at the top-right of the Policies tab, or **View Details** on an existing policy card.
|
||||
</Step>
|
||||
|
||||
<Step title="Name and describe the policy">
|
||||
Give the policy a clear name (e.g. *Mask PII (CC)* or *Monthly $100 budget*) and a description explaining when it applies. Both show up on the policy card and in the Engaged Automations modal.
|
||||
</Step>
|
||||
|
||||
<Step title="Pick the type">
|
||||
Choose **PII Redaction** or **Cost Limit**. The type determines which configuration section appears below the conditions. The type is fixed once the policy is created — to switch, create a new policy.
|
||||
</Step>
|
||||
|
||||
<Step title="Set the conditions">
|
||||
Conditions decide which automations the policy engages with. Both are optional and use **set-equality** semantics:
|
||||
|
||||
- **Tools** — only automations whose tool set **exactly matches** the selected tools will engage. Picks from Studio apps, MCPs, OSS tools, and Tool Repository registry tools.
|
||||
- **Automations** — only automations whose tag set **exactly matches** the selected tags will engage.
|
||||
|
||||
Leaving a picker empty means "no filter on this dimension". Leaving both empty means the policy applies to **every** automation in the organization.
|
||||
</Step>
|
||||
|
||||
<Step title="Configure the type-specific section">
|
||||
The editor shows the configuration for the type you picked — the **PII Mask Type** table for PII Redaction, or the budget fields for Cost Limit. See [Policy types](#policy-types) for what each field does.
|
||||
</Step>
|
||||
|
||||
<Step title="Save">
|
||||
The policy applies to **future** executions of every engaged automation as soon as you save. No re-deploy is needed.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Engaged automations
|
||||
|
||||
Click **Engaged N automations** on any policy card to see exactly which deployments the policy is currently matching, along with each one's last execution.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
This is the fastest way to sanity-check a policy's scope before enabling it — for example, to confirm that a policy scoped to the `production` tag isn't accidentally matching a staging deployment.
|
||||
|
||||
## Org-wide policies vs per-deployment settings
|
||||
|
||||
Both PII Redaction and Cost Limit can be configured in two places: org-wide as a Policy on this page, or per-deployment under that deployment's **Settings**. When an enabled org-wide policy's scope matches a deployment, the policy takes precedence over the deployment-owned setting while it's attached.
|
||||
|
||||
| Policy | Per-deployment setting | What an attached org-wide policy does |
|
||||
|--------|------------------------|-------------------------------------|
|
||||
| **PII Redaction** | **Settings → PII Protection** ([guide](/en/enterprise/features/pii-trace-redactions)) | The policy's entity configuration **overrides** the deployment's PII settings for that deployment's executions. |
|
||||
| **Cost Limit** | **Settings → Cost Alerts** | The deployment's manual cost alert is **paused** and the attached cost policy(s) fire instead. The per-deployment form stays editable as a fallback. |
|
||||
|
||||
Disable or detach the policy (or change its scope so it no longer matches) and the deployment falls back to its own per-deployment settings.
|
||||
|
||||
Prefer org-wide policies when you want to enforce a consistent policy across many deployments; reserve per-deployment configuration for one-off exceptions.
|
||||
|
||||
## Related
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agent Control Plane — Overview" icon="book-open" href="/en/enterprise/features/agent-control-plane/overview">
|
||||
What ACP is, requirements, plan tiers, and RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — Monitoring" icon="gauge" href="/en/enterprise/features/agent-control-plane/monitoring">
|
||||
Monitor automations and LLM consumption across your fleet.
|
||||
</Card>
|
||||
<Card title="PII Redaction for Traces" icon="lock" href="/en/enterprise/features/pii-trace-redactions">
|
||||
Entity catalog, custom recognizers, and per-deployment configuration.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/en/enterprise/features/rbac">
|
||||
Manage who can create or edit policies.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
|
||||
Contact our support team for help designing policies for your organization.
|
||||
</Card>
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**Rolling out Wednesday, June 24th.** The Studio canvas is moving to one card per step instead of separate task and agent nodes, to streamline the canvas as we add new functionality soon. Your existing automations keep working with no changes needed — every task and agent setting is still available, just organized onto a single card.
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
On the Studio canvas, each step of work is represented by a **single card**. The card combines two things that used to live in separate nodes:
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
---
|
||||
title: Flows in Studio
|
||||
description: "Build event-driven workflows that combine deterministic, step-by-step control with agentic intelligence — no code required."
|
||||
icon: "diagram-project"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**Rolling out now**: Flows in Studio is being rolled out gradually during the week of July 20th, 2026. If you don't see the Flows option in Studio yet, it hasn't reached your organization — check back soon.
|
||||
</Info>
|
||||
|
||||
## Overview
|
||||
|
||||
Studio now supports building **Flows** in addition to Crews. Flows are event-driven workflows where you control exactly which steps run, in what order, and under what conditions — while still delegating the intelligent work within each step to AI agents.
|
||||
|
||||
To build a Flow, open Studio, describe your automation, and select **Flows** from the selector next to the prompt box.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
## Why Flows?
|
||||
|
||||
Crews are great when you want a team of agents to collaborate autonomously toward a goal. But many real-world automations need more predictability: fetch this data first, then summarize it, then post the result — every time, in that order.
|
||||
|
||||
Flows give you both:
|
||||
|
||||
- **Determinism where it matters**: steps execute in a defined sequence with explicit branching, so runs are predictable, repeatable, and easy to debug.
|
||||
- **Intelligence where you need it**: each step is powered by an agent (or an entire crew), so the work inside a step — summarizing, scoring, drafting, deciding — benefits from full LLM reasoning.
|
||||
|
||||
This mix is what makes Flows well suited for production automations: the structure is guaranteed, and the agency is scoped to the steps that need it.
|
||||
|
||||
## Building a Flow
|
||||
|
||||
Describe what you want in natural language and the Studio Assistant designs the Flow for you — creating the steps, wiring them together, and configuring the agents and app integrations each step needs. The canvas on the right shows the resulting workflow as connected nodes, and you can keep iterating conversationally or edit any node directly.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
When you're ready, use **Run** to test the Flow end-to-end, inspect results in the **Output** and **Traces** tabs, and **Deploy** when it's stable. You can also **Share** the project or **Download** the source code.
|
||||
|
||||
## Node Types
|
||||
|
||||
Flows are composed from three core node types. Each node is a step in the workflow, and you can mix them freely.
|
||||
|
||||
### Single Agent
|
||||
|
||||
A Single Agent node runs one agent against one focused task — ideal for well-scoped steps like fetching data from an integration, transforming content, or posting a message.
|
||||
|
||||
Clicking into an agent node opens its full configuration:
|
||||
|
||||
- **Task**: what this step should accomplish and what output it should produce
|
||||
- **Profile**: the agent's role, goal, and backstory
|
||||
- **Model**: which LLM powers the agent
|
||||
- **Apps**: the integrations the agent can use (e.g. Linear, Slack, HubSpot)
|
||||
- **Runtime Controls**: toggles for planning before executing, delegation, and memory
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
### Crews
|
||||
|
||||
A Crew node embeds an entire crew — multiple agents collaborating across multiple tasks — as a single step in your Flow. Use it when a step is too rich for one agent, like grouping and summarizing data by team and then formatting the result for delivery.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Opening a Crew node reveals its internal structure: the tasks it performs, the agents assigned to each, and the apps they use. The crew runs autonomously within the step, then hands its output to the next node in the Flow.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
This is the deterministic-plus-agentic pattern in action: the Flow guarantees *when* the crew runs, and the crew brings collaborative intelligence to *how* the work gets done.
|
||||
|
||||
### Router
|
||||
|
||||
A Router node branches the Flow based on conditions, so different outcomes take different paths. For example, a lead-routing Flow can score incoming leads and then route high-quality leads to a sales-assignment step while logging the rest for future nurturing.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Routers are what make Flows genuinely event-driven: the same workflow handles every case, but each run follows only the branch its data warrants — no wasted steps, no ambiguity about what happens next.
|
||||
|
||||
## Agent Repository Sync
|
||||
|
||||
Agents you build in Flows don't have to stay locked inside a single project. Every agent node includes a **Publish to Agent Repository** button that saves the agent — its role, goal, backstory, model, and configuration — to your organization's [Agent Repository](/en/enterprise/features/agent-repositories).
|
||||
|
||||
This works in both directions:
|
||||
|
||||
- **Publish**: promote an agent you've refined in a Flow to the repository so other teams and projects can reuse it.
|
||||
- **Pull**: bring an existing repository agent into a new Flow instead of rebuilding it from scratch.
|
||||
|
||||
Because repository agents are synced across your organization, an improvement made to a shared agent benefits every Flow that uses it — keeping agent behavior consistent, governed, and free of duplicated effort.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Reach for a Flow** when the automation has a clear sequence or branching logic; reach for a Crew when the path to the goal is open-ended.
|
||||
- **Keep agent tasks focused** — a Single Agent node with a tight task description is more reliable than one asked to do three things.
|
||||
- **Use Routers to handle every case explicitly**, including the "do nothing" path (e.g. logging skipped leads), so runs are fully accounted for.
|
||||
- **Publish stable agents to the Agent Repository** so your organization builds a shared library instead of parallel one-offs.
|
||||
- **Test with Run and inspect Traces** before deploying to catch integration or prompt issues early.
|
||||
|
||||
## Related
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="Crew Studio" href="/en/enterprise/features/crew-studio" icon="pencil">
|
||||
Build Crews in Studio.
|
||||
</Card>
|
||||
<Card title="Agent Repositories" href="/en/enterprise/features/agent-repositories" icon="people-group">
|
||||
Share and reuse agents across your organization.
|
||||
</Card>
|
||||
<Card title="Flows Concepts" href="/en/concepts/flows" icon="diagram-project">
|
||||
Learn how Flows work in the CrewAI framework.
|
||||
</Card>
|
||||
<Card title="Tools & Integrations" href="/en/enterprise/features/tools-and-integrations" icon="plug">
|
||||
Connect the apps your agents use.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -17,11 +17,12 @@ CrewAI supports two log-ingestion paths to Datadog — both are first-class and
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Datadog Agent">
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. Each log event ships as a single billable line with structured attributes — see the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. With `CREWAI_LOG_FORMAT=json` set, each log event ships as a single billable line with structured attributes.
|
||||
|
||||
**Setup:**
|
||||
1. Run the Datadog Agent next to your CrewAI containers — see [Datadog's deployment docs](https://docs.datadoghq.com/agent/) for Kubernetes, ECS, or VM setup. Enable log collection (`logs_enabled: true`) and container log collection (`logs_config.container_collect_all: true`).
|
||||
2. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
2. Set `CREWAI_LOG_FORMAT=json` as an **automation environment variable** in CrewAI AMP (open your automation → **Settings → Environment Variables**) so each log event is a single line instead of a multi-line traceback. AMP propagates the value to every container in the deployment (API + workers) — don't set it on the container or host directly. See [Enabling JSON output](#enabling-json-output) below for the AMP UI walkthrough and the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
3. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
|
||||
**Pick this path if** you already operate Datadog Agents (e.g. for infrastructure metrics), or your log volume makes per-event ingestion cost a real concern — collapsing tracebacks into single events keeps Agent ingestion cheap at scale.
|
||||
</Tab>
|
||||
@@ -52,10 +53,10 @@ Either path lands the same structured facets in Datadog (`@automation_id`, `@kic
|
||||
## Log schema reference
|
||||
|
||||
<Info>
|
||||
This schema applies to the **Datadog Agent path** — structured stdout JSON logs emitted by every CrewAI worker container. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
This schema applies to the **Datadog Agent path** — stdout JSON logs produced when `CREWAI_LOG_FORMAT=json` is set. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
</Info>
|
||||
|
||||
Every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
When `CREWAI_LOG_FORMAT=json` is set, every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
|
||||
### Why JSON output
|
||||
|
||||
@@ -74,6 +75,20 @@ Every log event is emitted as a **single JSON object per line** to stdout, with
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Enabling JSON output
|
||||
|
||||
`CREWAI_LOG_FORMAT=json` must be set as an **automation environment variable** in CrewAI AMP — it is **not** a container, host, or Docker setting. Open your automation in AMP, click the **Settings** icon, and add the variable under the **Environment Variables** section. AMP applies the value to every container in the deployment (API + workers) on the next restart. See [Update Your Crew](./update-crew) for the full UI walkthrough with screenshots.
|
||||
|
||||
```shell
|
||||
CREWAI_LOG_FORMAT=json
|
||||
```
|
||||
|
||||
Restart the deployment to pick up the change. Every log line on stdout from that point on is a single JSON object.
|
||||
|
||||
<Note>
|
||||
The default value is `text`, which preserves the legacy human-readable line format byte-for-byte. Setting any value other than `json` falls back to text mode. There is no migration step — the variable is read at process start and the format switches immediately.
|
||||
</Note>
|
||||
|
||||
### Example events
|
||||
|
||||
A single info-level log inside an active automation kickoff:
|
||||
@@ -116,7 +131,7 @@ An error with a Python exception is collapsed into a single event with the trace
|
||||
}
|
||||
```
|
||||
|
||||
Without JSON output, that same error would produce ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
The same error in legacy text mode would have produced ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
|
||||
### Schema v1 fields
|
||||
|
||||
@@ -218,7 +233,7 @@ Open [Logs Explorer](https://app.datadoghq.com/logs) and run a query that matche
|
||||
<Tab title="Datadog Agent">
|
||||
Search `service:crewai* @schema:v1`. You should see structured logs with the JSON fields parsed into Datadog facets. Pick a recent event and verify it has `@automation_id`, `@kickoff_id`, `@execution_id`, `@crewai_version`, and (when running inside a span) `@trace_id` / `@span_id` populated.
|
||||
|
||||
If nothing appears, confirm the Datadog Agent is tailing container stdout and that the deployment is running a recent enough CrewAI Enterprise build.
|
||||
If nothing appears, confirm `CREWAI_LOG_FORMAT=json` is set under your automation's **Environment Variables** in AMP, the deployment was restarted after the change, and the Datadog Agent is tailing container stdout.
|
||||
</Tab>
|
||||
<Tab title="Datadog OTLP intake">
|
||||
Search `source:otlp service:crewai*`. OTLP attributes land with their OpenTelemetry names (`automation_id`, `crewai.kickoff.id`, etc.) rather than the stdout JSON keys, but they map to the same dashboard facets after [facet promotion](#prerequisite-promote-facets).
|
||||
@@ -261,7 +276,7 @@ The `$service` template variable defaults to `*` and will catch every CrewAI dep
|
||||
| All widgets show "No data" | Facets aren't promoted | Re-do the [Promote facets](#prerequisite-promote-facets) step. Datadog won't query against an un-promoted field. |
|
||||
| Error Rate widget shows `NaN` | No executions in the time window | Either no traffic, or `@execution_id` isn't faceted. Expand the time range and re-check facets. |
|
||||
| Throughput chart is flat at the same value | Logs aren't reaching Datadog | Search `service:crewai*` in Logs Explorer. If nothing shows, verify the Datadog Agent is running (Agent path) or the OTel collector endpoint is correct (OTLP path). |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments (pre-structured-logs AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments running text mode (or older AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| Template variables don't filter widgets | The widget's filter line doesn't reference the template variable | Edit the widget and confirm the search includes `$automation $version $service`. |
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -25,7 +25,6 @@ Use **`flow.handle_turn(message, session_id=...)`** for every user message from
|
||||
| API | Use for |
|
||||
|-----|---------|
|
||||
| `handle_turn(message, session_id=...)` | Ergonomic one-turn wrapper for conversational `Flow` |
|
||||
| `stream_turn(message, session_id=...)` | Stream one conversational turn as ordered runtime frames |
|
||||
| `chat()` | Local terminal REPL for conversational `Flow` |
|
||||
| `kickoff(inputs={...})` | Advanced flow execution without conversational turn handling |
|
||||
| `ask()` | Blocking prompt **inside** one step (wizard, clarification) |
|
||||
@@ -86,23 +85,6 @@ finally:
|
||||
flow.finalize_session_traces() # one trace link for the whole chat
|
||||
```
|
||||
|
||||
## Streaming a turn
|
||||
|
||||
Use `stream_turn()` when a UI or runtime needs structured events for one chat turn. It returns a stream session with ordered frames for Flow routing, LLM chunks, tool activity, and conversation messages.
|
||||
|
||||
```python
|
||||
stream = flow.stream_turn("Where is my order?", session_id=session_id)
|
||||
|
||||
with stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.type == "llm_stream_chunk":
|
||||
print(frame.data.get("chunk", ""), end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
For the full frame contract, channel list, and async API, see [Streaming Runtime Contract](/edge/en/learn/streaming-runtime-contract).
|
||||
|
||||
## Turn lifecycle
|
||||
|
||||
Each `handle_turn` runs this pipeline:
|
||||
|
||||
@@ -5,49 +5,15 @@ icon: wrench
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 18,
|
||||
padding: "24px",
|
||||
marginBottom: 32,
|
||||
borderRadius: 12,
|
||||
border: "1px solid rgba(235,102,88,0.28)",
|
||||
background: "linear-gradient(180deg, rgba(235,102,88,0.14) 0%, rgba(235,102,88,0.06) 100%)"
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<p style={{ margin: 0, color: "#EB6658", fontSize: 13, fontWeight: 700, textTransform: "uppercase" }}>
|
||||
Coding agent setup
|
||||
</p>
|
||||
<h2 style={{ margin: "6px 0 8px" }}>Set up CrewAI in your coding agent</h2>
|
||||
<p style={{ margin: 0, color: "var(--mint-text-2)", maxWidth: 760 }}>
|
||||
Copy a ready-to-paste setup prompt for Claude Code, Codex, Cursor, or any coding agent. It installs the official CrewAI skills, checks the CLI, and points the agent at the right docs before it edits code.
|
||||
</p>
|
||||
</div>
|
||||
### Watch: Building CrewAI Agents & Flows with Coding Agent Skills
|
||||
|
||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 12, alignItems: "center" }}>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid #EB6658",
|
||||
background: "#EB6658",
|
||||
color: "#FFFFFF",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
cursor: "pointer",
|
||||
boxShadow: "0 10px 24px rgba(235,102,88,0.22)"
|
||||
}}
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
Install our coding agent skills (Claude Code, Codex, ...) to quickly get your coding agents up and running with CrewAI.
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="button button-primary"
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
|
||||
First install the official CrewAI coding-agent skills if this environment supports npx:
|
||||
|
||||
@@ -82,49 +48,21 @@ Setup steps:
|
||||
Do not hardcode API keys. Use .env.
|
||||
Do not invent CLI flags. Validate with crewai --help or crewai create --help.
|
||||
If a command fails, show the exact command and error, explain the likely cause, fix what you can safely fix, and retry once.`;
|
||||
const button = event.currentTarget;
|
||||
const resetTimeout = button.dataset.resetTimeout;
|
||||
if (resetTimeout) {
|
||||
window.clearTimeout(Number(resetTimeout));
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
button.dataset.resetTimeout = String(window.setTimeout(() => {
|
||||
button.textContent = "Copy agent setup prompt";
|
||||
delete button.dataset.resetTimeout;
|
||||
}, 1600));
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy agent setup prompt
|
||||
</button>
|
||||
<a
|
||||
href="/en/guides/coding-tools/build-with-ai"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.36)",
|
||||
color: "#EB6658",
|
||||
fontSize: 15,
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
View coding-agent guide
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### Watch: Building CrewAI Agents & Flows with Coding Agent Skills
|
||||
const button = event.currentTarget;
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
window.setTimeout(() => {
|
||||
button.textContent = "Copy instructions for coding agents";
|
||||
}, 1600);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy instructions for coding agents
|
||||
</button>
|
||||
|
||||
<iframe src="https://www.loom.com/embed/befb9f68b81f42ad8112bfdd95a780af" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style={{width: "100%", height: "400px"}}></iframe>
|
||||
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
---
|
||||
title: Consuming Streams
|
||||
description: Print LLM chunks, observe tool events, and read final results from CrewAI streams.
|
||||
icon: square-terminal
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Use this guide when you want to subscribe to a CrewAI stream and print or route frames as they arrive.
|
||||
|
||||
The basic pattern is:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events(inputs={"topic": "AI agents"})
|
||||
|
||||
with stream:
|
||||
for frame in stream:
|
||||
...
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Always consume the stream before reading `stream.result`.
|
||||
|
||||
## Print LLM Output
|
||||
|
||||
If you only care about text generated by LLM calls, subscribe to the `llm` projection and print `frame.content`:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events(inputs={"topic": "AI agents"})
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
print()
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`frame.content` is an empty string for frames that do not carry printable text, so this is also safe:
|
||||
|
||||
```python
|
||||
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.content:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
## Print Tool Activity
|
||||
|
||||
Tool events arrive on the `tools` channel. Use `frame.type` to distinguish starts, finishes, and errors.
|
||||
|
||||
```python
|
||||
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.content:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
if frame.channel == "tools" and frame.type == "tool_usage_started":
|
||||
print(f"\nTool started: {frame.event.get('tool_name')}")
|
||||
|
||||
if frame.channel == "tools" and frame.type == "tool_usage_finished":
|
||||
print(f"\nTool finished: {frame.event.get('tool_name')}")
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`frame.event` is the structured payload for the source event. Use it for metadata such as tool names, arguments, message roles, and runtime identifiers.
|
||||
|
||||
## Watch Flow Progress
|
||||
|
||||
Flow lifecycle and method execution frames arrive on the `flow` channel:
|
||||
|
||||
```python
|
||||
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
|
||||
for frame in stream.flow:
|
||||
print(frame.type, frame.namespace)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Use this when you want a progress log instead of token-level output.
|
||||
|
||||
## Interleave Selected Channels
|
||||
|
||||
Use `interleave()` when you want a subset of channels while preserving their relative order:
|
||||
|
||||
```python
|
||||
with flow.stream_events(inputs={"topic": "AI agents"}) as stream:
|
||||
for frame in stream.interleave(["llm", "tools"]):
|
||||
if frame.channel == "llm":
|
||||
print(frame.content, end="", flush=True)
|
||||
elif frame.type == "tool_usage_started":
|
||||
print(f"\nTool: {frame.event.get('tool_name')}")
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
## Stream a Direct LLM Call
|
||||
|
||||
Direct `llm.call(...)` returns the final assembled result. To stream a direct LLM call, use `llm.stream_events(...)`:
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
stream = llm.stream_events("Explain streaming in one sentence.")
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
print()
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
## Stream a Conversational Turn
|
||||
|
||||
Conversational Flows expose `stream_turn()` for one user message:
|
||||
|
||||
```python
|
||||
stream = flow.stream_turn(
|
||||
"What can you help me with?",
|
||||
session_id="session-1",
|
||||
)
|
||||
|
||||
with stream:
|
||||
for frame in stream.interleave(["llm", "messages"]):
|
||||
if frame.channel == "llm":
|
||||
print(frame.content, end="", flush=True)
|
||||
elif frame.channel == "messages":
|
||||
print(f"\n{frame.event.get('role')}: {frame.event.get('content')}")
|
||||
|
||||
reply = stream.result
|
||||
```
|
||||
|
||||
## Async Consumers
|
||||
|
||||
Async streams use the same channel projections:
|
||||
|
||||
```python
|
||||
stream = flow.astream(inputs={"topic": "AI agents"})
|
||||
|
||||
async with stream:
|
||||
async for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
## Cleanup
|
||||
|
||||
Use the stream as a context manager when possible. If a client disconnects or you stop consuming early, close the stream:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events(inputs={"topic": "AI agents"})
|
||||
|
||||
try:
|
||||
for frame in stream.events:
|
||||
print(frame.content, end="", flush=True)
|
||||
finally:
|
||||
if not stream.is_exhausted:
|
||||
stream.close()
|
||||
```
|
||||
|
||||
For async streams, call `await stream.aclose()`.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Streaming](/edge/en/concepts/streaming)
|
||||
- [Streaming Runtime Contract](/edge/en/learn/streaming-runtime-contract)
|
||||
- [Streaming Flow Execution](/edge/en/learn/streaming-flow-execution)
|
||||
- [Streaming Crew Execution](/edge/en/learn/streaming-crew-execution)
|
||||
@@ -1,163 +0,0 @@
|
||||
---
|
||||
title: Execution Boundary Hooks
|
||||
description: Intercept the start, inputs, output, and end of crew and flow executions with the @on decorator
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Execution boundary hooks intercept the outermost edges of a run — before any
|
||||
work starts, when inputs are resolved, when the final result is ready, and when
|
||||
the execution finishes. They fire for both crews and flows and are the right
|
||||
place for run-level policy checks, input rewriting, and output sanitization.
|
||||
|
||||
## Overview
|
||||
|
||||
Four interception points cover the boundaries:
|
||||
|
||||
| Point | When | `ctx.payload` |
|
||||
|-------|------|---------------|
|
||||
| `EXECUTION_START` | A crew or flow is about to begin | inputs `dict` |
|
||||
| `INPUT` | Resolved inputs for the execution | inputs `dict` |
|
||||
| `OUTPUT` | The final result is ready | the output object |
|
||||
| `EXECUTION_END` | The execution has finished | the output object |
|
||||
|
||||
For a crew, the output payload is a `CrewOutput`. For a flow, it is the final
|
||||
flow-method result.
|
||||
|
||||
## Hook Signature
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint
|
||||
|
||||
@on(InterceptionPoint.EXECUTION_START)
|
||||
def boundary_hook(ctx) -> Any | None:
|
||||
# Mutate ctx.payload in place, or
|
||||
# return a non-None value to replace it, or
|
||||
# raise HookAborted(reason, source) to stop the run
|
||||
return None
|
||||
```
|
||||
|
||||
Boundary hooks follow the standard contract: proceed (`return None`), mutate in
|
||||
place, replace by returning, or abort by raising
|
||||
[`HookAborted`](/edge/en/learn/execution-hooks#aborting-an-operation). An abort at any
|
||||
boundary propagates out of `kickoff()` with its reason.
|
||||
|
||||
## Context Schema
|
||||
|
||||
Each point receives a typed context. All contexts share the base fields:
|
||||
|
||||
```python
|
||||
class InterceptionContext:
|
||||
payload: Any # The interceptable value (see table above)
|
||||
agent: Any = None # Not populated at execution boundaries
|
||||
agent_role: str | None # Not populated at execution boundaries
|
||||
task: Any = None # Not populated at execution boundaries
|
||||
crew: Any = None # The Crew instance (crew runs only)
|
||||
flow: Any = None # The Flow instance (flow runs only)
|
||||
```
|
||||
|
||||
The per-point contexts add a named alias for the payload:
|
||||
|
||||
```python
|
||||
class ExecutionStartContext(InterceptionContext):
|
||||
inputs: dict # Same dict as payload
|
||||
|
||||
class InputContext(InterceptionContext):
|
||||
inputs: dict # Same dict as payload
|
||||
|
||||
class OutputContext(InterceptionContext):
|
||||
output: Any # The output object
|
||||
|
||||
class ExecutionEndContext(InterceptionContext):
|
||||
output: Any # The output object
|
||||
```
|
||||
|
||||
<Note>
|
||||
`ctx.inputs` aliases the **original** inputs dict, so in-place edits through
|
||||
either name are equivalent. If an earlier hook *replaced* the payload by
|
||||
returning a new dict, only `ctx.payload` is rebound — always read and write
|
||||
`ctx.payload` when hooks might chain.
|
||||
</Note>
|
||||
|
||||
## Crew Runs vs. Flow Runs
|
||||
|
||||
Boundary hooks fire on both runtimes, and crew execution internally rides on a
|
||||
flow runtime. During a `crew.kickoff()`, a global boundary hook therefore fires
|
||||
for the crew boundary (`ctx.crew` set, `ctx.flow` `None`) **and** for the
|
||||
internal flow (`ctx.flow` set, `ctx.crew` `None`). Discriminate by runtime:
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.OUTPUT)
|
||||
def crew_output_only(ctx):
|
||||
if ctx.crew is None:
|
||||
return None # Skip the internal flow (or a bare flow)
|
||||
ctx.payload.raw = ctx.payload.raw.strip()
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Policy Check at Start
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.EXECUTION_START)
|
||||
def enforce_policy(ctx):
|
||||
if ctx.crew is not None and not ctx.payload.get("authorized"):
|
||||
raise HookAborted(reason="unauthorized execution", source="access-control")
|
||||
```
|
||||
|
||||
### Input Rewriting
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.INPUT)
|
||||
def add_defaults(ctx):
|
||||
if ctx.crew is None:
|
||||
return None
|
||||
ctx.payload.setdefault("locale", "en-US")
|
||||
ctx.payload["topic"] = ctx.payload["topic"].strip().lower()
|
||||
```
|
||||
|
||||
Rewritten inputs flow into task interpolation, so the run behaves as if it was
|
||||
kicked off with the modified dict.
|
||||
|
||||
### Output Sanitization
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
@on(InterceptionPoint.OUTPUT)
|
||||
def redact_emails(ctx):
|
||||
if ctx.crew is None:
|
||||
return None
|
||||
ctx.payload.raw = re.sub(
|
||||
r"\b[\w.+-]+@[\w-]+\.[\w.]+\b", "[EMAIL-REDACTED]", ctx.payload.raw
|
||||
)
|
||||
```
|
||||
|
||||
`OUTPUT` runs before `EXECUTION_END`, and both see the (possibly replaced)
|
||||
payload from earlier hooks; the final rewritten value is what `kickoff()`
|
||||
returns.
|
||||
|
||||
## Ordering
|
||||
|
||||
For a crew run the boundary order is:
|
||||
|
||||
```
|
||||
EXECUTION_START → before_kickoff callbacks → INPUT → tasks execute → OUTPUT → EXECUTION_END
|
||||
```
|
||||
|
||||
Hooks at the same point run in registration order, global hooks first, then
|
||||
crew-scoped hooks. Telemetry (`HookDispatchedEvent`) is emitted per dispatch.
|
||||
|
||||
## Managing Hooks in Tests
|
||||
|
||||
```python
|
||||
from crewai.hooks import clear_all_hooks
|
||||
|
||||
clear_all_hooks() # Clears every point, including boundaries
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Execution Hooks Overview →](/edge/en/learn/execution-hooks)
|
||||
- [Step Hooks →](/edge/en/learn/step-hooks)
|
||||
- [LLM Call Hooks →](/edge/en/learn/llm-hooks)
|
||||
- [Tool Call Hooks →](/edge/en/learn/tool-hooks)
|
||||
@@ -1,281 +1,525 @@
|
||||
---
|
||||
title: Execution Hooks
|
||||
description: Intercept, modify, and control CrewAI's runtime with the @on decorator - one contract covering every interception point
|
||||
title: Execution Hooks Overview
|
||||
description: Understanding and using execution hooks in CrewAI for fine-grained control over agent operations
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Execution hooks provide fine-grained control over the runtime behavior of your
|
||||
CrewAI agents. Unlike kickoff hooks that run before and after crew execution,
|
||||
execution hooks intercept specific operations during execution — from the moment
|
||||
a run starts, through every model call, tool call, and task or flow-method step,
|
||||
down to the final output.
|
||||
Execution Hooks provide fine-grained control over the runtime behavior of your CrewAI agents. Unlike kickoff hooks that run before and after crew execution, execution hooks intercept specific operations during agent execution, allowing you to modify behavior, implement safety checks, and add comprehensive monitoring.
|
||||
|
||||
Hooks are written with the `@on` decorator: one registration API and one
|
||||
contract cover every interception point in the framework.
|
||||
## Types of Execution Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint
|
||||
CrewAI provides two main categories of execution hooks:
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["delete_file"])
|
||||
def guard_deletes(ctx):
|
||||
raise HookAborted(reason="file deletion is not allowed", source="policy")
|
||||
```
|
||||
### 1. [LLM Call Hooks](/learn/llm-hooks)
|
||||
|
||||
<Note>
|
||||
The point-specific decorators (`@before_llm_call`, `@after_tool_call`, ...) keep
|
||||
working unchanged — they are adapters over the same engine. See
|
||||
[Point-specific decorators (legacy)](#point-specific-decorators-legacy) at the
|
||||
end of this page.
|
||||
</Note>
|
||||
Control and monitor language model interactions:
|
||||
- **Before LLM Call**: Modify prompts, validate inputs, implement approval gates
|
||||
- **After LLM Call**: Transform responses, sanitize outputs, update conversation history
|
||||
|
||||
## The contract
|
||||
**Use Cases:**
|
||||
- Iteration limiting
|
||||
- Cost tracking and token usage monitoring
|
||||
- Response sanitization and content filtering
|
||||
- Human-in-the-loop approval for LLM calls
|
||||
- Adding safety guidelines or context
|
||||
- Debug logging and request/response inspection
|
||||
|
||||
Every hook is a **synchronous** callable that receives a single typed context:
|
||||
[View LLM Hooks Documentation →](/learn/llm-hooks)
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint
|
||||
### 2. [Tool Call Hooks](/learn/tool-hooks)
|
||||
|
||||
@on(InterceptionPoint.INPUT)
|
||||
def add_defaults(ctx):
|
||||
# 1. Observe: read anything off the context.
|
||||
# 2. Mutate in place: change ctx.payload or nested fields directly.
|
||||
ctx.payload.setdefault("locale", "en-US")
|
||||
# 3. Or replace: return a new value to swap ctx.payload.
|
||||
# 4. Or abort: raise HookAborted(reason, source) to stop the operation.
|
||||
return None
|
||||
```
|
||||
Control and monitor tool execution:
|
||||
- **Before Tool Call**: Modify inputs, validate parameters, block dangerous operations
|
||||
- **After Tool Call**: Transform results, sanitize outputs, log execution details
|
||||
|
||||
A hook may do any of four things:
|
||||
**Use Cases:**
|
||||
- Safety guardrails for destructive operations
|
||||
- Human approval for sensitive actions
|
||||
- Input validation and sanitization
|
||||
- Result caching and rate limiting
|
||||
- Tool usage analytics
|
||||
- Debug logging and monitoring
|
||||
|
||||
| Action | How | Effect |
|
||||
|--------|-----|--------|
|
||||
| **Proceed** | `return None` (or nothing) | Operation continues unchanged |
|
||||
| **Mutate** | Change `ctx.payload` / fields in place | Change is visible downstream |
|
||||
| **Replace** | `return new_payload` | A non-`None` return replaces `ctx.payload` |
|
||||
| **Abort** | `raise HookAborted(reason, source)` | Operation is stopped; the reason propagates |
|
||||
[View Tool Hooks Documentation →](/learn/tool-hooks)
|
||||
|
||||
## Registering hooks
|
||||
## Hook Registration Methods
|
||||
|
||||
Use `@on` for global hooks. It accepts `agents=` / `tools=` filters to scope a
|
||||
hook to specific agent roles or tool names:
|
||||
### 1. Decorator-Based Hooks (Recommended)
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, InterceptionPoint
|
||||
|
||||
@on(InterceptionPoint.POST_TOOL_CALL, agents=["researcher"], tools=["web_search"])
|
||||
def log_search_results(ctx):
|
||||
print(f"search returned: {(ctx.tool_result or '')[:80]}")
|
||||
```
|
||||
|
||||
Applied to a method inside a `@CrewBase` class, `@on` registers a
|
||||
**crew-scoped** hook, active only while that crew runs:
|
||||
|
||||
```python
|
||||
from crewai import CrewBase
|
||||
from crewai.hooks import on, InterceptionPoint
|
||||
|
||||
@CrewBase
|
||||
class MyProjCrew:
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def validate_inputs(self, ctx):
|
||||
# Only applies to this crew
|
||||
return None
|
||||
```
|
||||
|
||||
## Interception point catalog
|
||||
|
||||
Each family has a detailed guide covering its context schema, payload
|
||||
semantics, and examples.
|
||||
|
||||
### [Execution boundaries](/edge/en/learn/execution-boundary-hooks)
|
||||
|
||||
| Point | When | `ctx.payload` |
|
||||
|-------|------|---------------|
|
||||
| `EXECUTION_START` | A crew or flow is about to begin | inputs `dict` |
|
||||
| `INPUT` | Resolved inputs for the execution | inputs `dict` |
|
||||
| `OUTPUT` | Final result is ready | the output object |
|
||||
| `EXECUTION_END` | A crew or flow has finished | the output object |
|
||||
|
||||
### [Model boundaries](/edge/en/learn/llm-hooks) & [tool boundaries](/edge/en/learn/tool-hooks)
|
||||
|
||||
| Point | When | Hook receives |
|
||||
|-------|------|---------------|
|
||||
| `PRE_MODEL_CALL` | Before an LLM call | `LLMCallHookContext` |
|
||||
| `POST_MODEL_CALL` | After an LLM call | `LLMCallHookContext` (with `response` set) |
|
||||
| `PRE_TOOL_CALL` | Before a tool runs | `ToolCallHookContext` |
|
||||
| `POST_TOOL_CALL` | After a tool runs | `ToolCallHookContext` (with results set) |
|
||||
|
||||
At these four points the hook receives the rich legacy context **directly** as
|
||||
its argument — there is no separate `ctx.payload`. Mutate `ctx.messages` /
|
||||
`ctx.tool_input` in place, and return a string from a post hook to replace the
|
||||
response / tool result.
|
||||
|
||||
### [Step points](/edge/en/learn/step-hooks)
|
||||
|
||||
| Point | When | `ctx.payload` |
|
||||
|-------|------|---------------|
|
||||
| `PRE_STEP` | Before a task or flow-method step | step input |
|
||||
| `POST_STEP` | After a task or flow-method step | step output |
|
||||
|
||||
`PRE_STEP` / `POST_STEP` carry `ctx.kind` (`"task"` or `"flow_method"`) and
|
||||
`ctx.step_name`.
|
||||
|
||||
## Aborting an operation
|
||||
|
||||
`HookAborted` carries a `reason` and an optional `source`. The `source` defaults
|
||||
to the aborting hook when omitted, which is useful for telemetry and failure
|
||||
messages:
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.EXECUTION_START)
|
||||
def enforce_policy(ctx):
|
||||
if not ctx.payload.get("authorized"):
|
||||
raise HookAborted(reason="unauthorized execution", source="access-control")
|
||||
```
|
||||
|
||||
## Composition, ordering, and fail-open
|
||||
|
||||
- Multiple hooks on the same point run in **registration order**, global hooks
|
||||
first, then execution-scoped hooks. Legacy hooks registered for the same point
|
||||
participate in the same chain.
|
||||
- The (possibly mutated) payload flows from one hook to the next.
|
||||
- `HookAborted` **propagates by design** and stops the chain.
|
||||
- Any *other* exception raised by a hook is **swallowed** (fail-open) so a single
|
||||
buggy hook can't crash a run.
|
||||
- When no hook is registered for a point, dispatch is a single dict lookup
|
||||
(no-op fast path), so unused points cost effectively nothing.
|
||||
|
||||
## Common patterns
|
||||
|
||||
### Safety guardrails
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def block_dangerous_tools(ctx):
|
||||
dangerous = {"delete_file", "drop_table", "system_shutdown"}
|
||||
if ctx.tool_name in dangerous:
|
||||
raise HookAborted(reason=f"{ctx.tool_name} is blocked", source="safety-policy")
|
||||
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def iteration_limit(ctx):
|
||||
if ctx.iterations > 15:
|
||||
raise HookAborted(reason="maximum iterations exceeded", source="loop-guard")
|
||||
```
|
||||
|
||||
### Human-in-the-loop approval
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["send_email", "make_payment"])
|
||||
def require_approval(ctx):
|
||||
response = ctx.request_human_input(
|
||||
prompt=f"Approve {ctx.tool_name}?",
|
||||
default_message="Type 'yes' to approve:",
|
||||
)
|
||||
if response.lower() != "yes":
|
||||
raise HookAborted(reason="rejected by operator", source="approval-gate")
|
||||
```
|
||||
|
||||
### Sanitizing outputs
|
||||
|
||||
A non-`None` return value replaces the interceptable value, so transformations
|
||||
are plain return statements:
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
@on(InterceptionPoint.POST_MODEL_CALL)
|
||||
def redact_keys(ctx):
|
||||
return re.sub(
|
||||
r'(api[_-]?key)["\']?\s*[:=]\s*["\']?[\w-]+',
|
||||
r"\1: [REDACTED]",
|
||||
ctx.response,
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
```
|
||||
|
||||
### Observing steps
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.POST_STEP)
|
||||
def trace_steps(ctx):
|
||||
print(f"{ctx.kind} '{ctx.step_name}' finished")
|
||||
```
|
||||
|
||||
## Telemetry
|
||||
|
||||
Whenever a point actually dispatches to at least one hook, CrewAI emits a
|
||||
`HookDispatchedEvent` on the event bus with the point, the outcome
|
||||
(`proceeded` / `modified` / `aborted`), the hook count, the duration, and — for
|
||||
aborts — the reason and source. The no-op fast path emits nothing.
|
||||
|
||||
## Managing hooks in tests
|
||||
|
||||
Global hooks persist for the lifetime of the process. Reset them between tests:
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from crewai.hooks import clear_all_hooks
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_hooks():
|
||||
clear_all_hooks()
|
||||
yield
|
||||
clear_all_hooks()
|
||||
```
|
||||
|
||||
## Best practices
|
||||
|
||||
1. **Keep hooks focused** — one clear responsibility per hook; register several
|
||||
small hooks rather than one that does everything.
|
||||
2. **Keep hooks fast** — hooks run on every dispatch of their point; avoid heavy
|
||||
computation and lazy-import heavy dependencies.
|
||||
3. **Prefer scoping** — use `agents=` / `tools=` filters and crew-scoped
|
||||
registration instead of unconditional global hooks.
|
||||
4. **Abort loudly** — raise `HookAborted` with a meaningful `reason` and
|
||||
`source`; that context surfaces in error messages and telemetry. Remember
|
||||
that any other exception is swallowed (fail-open), so don't rely on raising
|
||||
`ValueError` to stop a run.
|
||||
|
||||
## Point-specific decorators (legacy)
|
||||
|
||||
Before `@on`, LLM and tool calls were hooked with dedicated decorator pairs.
|
||||
These keep working unchanged — they are adapters over the same dispatcher, so
|
||||
they compose with `@on` hooks in the same registration-order chain:
|
||||
The cleanest and most Pythonic way to register hooks:
|
||||
|
||||
```python
|
||||
from crewai.hooks import before_llm_call, after_llm_call, before_tool_call, after_tool_call
|
||||
|
||||
@before_llm_call
|
||||
def limit_iterations(context):
|
||||
"""Prevent infinite loops by limiting iterations."""
|
||||
if context.iterations > 10:
|
||||
return False # Block execution
|
||||
return None
|
||||
|
||||
@after_llm_call
|
||||
def sanitize_response(context):
|
||||
"""Remove sensitive data from LLM responses."""
|
||||
if "API_KEY" in context.response:
|
||||
return context.response.replace("API_KEY", "[REDACTED]")
|
||||
return None
|
||||
|
||||
@before_tool_call
|
||||
def block_dangerous_tools(context):
|
||||
"""Block destructive operations."""
|
||||
if context.tool_name == "delete_database":
|
||||
return False # Block execution
|
||||
return None
|
||||
|
||||
@after_tool_call
|
||||
def log_tool_result(context):
|
||||
"""Log tool execution."""
|
||||
print(f"Tool {context.tool_name} completed")
|
||||
return None
|
||||
```
|
||||
|
||||
Differences from `@on`:
|
||||
### 2. Crew-Scoped Hooks
|
||||
|
||||
- They cover **only** the four model/tool points — no execution boundaries, no
|
||||
steps.
|
||||
- Blocking is `return False`, with no abort reason or source attached.
|
||||
- They receive the same rich contexts — `LLMCallHookContext` (with full
|
||||
executor access) and `ToolCallHookContext` — that `@on` hooks receive at the
|
||||
model/tool points.
|
||||
- Crew-scoping works the same way: apply the decorator to a method inside a
|
||||
`@CrewBase` class.
|
||||
- They support the same `agents=` / `tools=` filters.
|
||||
Apply hooks only to specific crew instances:
|
||||
|
||||
You might still prefer them for existing codebases that already use
|
||||
`return False` semantics, or when you want the point-specific typed signatures.
|
||||
For the detailed guides — context attributes, patterns, and management APIs
|
||||
(`register_*` / `unregister_*` / `clear_*`) — see:
|
||||
```python
|
||||
from crewai import CrewBase
|
||||
from crewai.project import crew
|
||||
from crewai.hooks import before_llm_call_crew, after_tool_call_crew
|
||||
|
||||
- [LLM Call Hooks →](/edge/en/learn/llm-hooks)
|
||||
- [Tool Call Hooks →](/edge/en/learn/tool-hooks)
|
||||
@CrewBase
|
||||
class MyProjCrew:
|
||||
@before_llm_call_crew
|
||||
def validate_inputs(self, context):
|
||||
# Only applies to this crew
|
||||
print(f"LLM call in {self.__class__.__name__}")
|
||||
return None
|
||||
|
||||
## Related documentation
|
||||
@after_tool_call_crew
|
||||
def log_results(self, context):
|
||||
# Crew-specific logging
|
||||
print(f"Tool result: {context.tool_result[:50]}...")
|
||||
return None
|
||||
|
||||
- [Before and After Kickoff Hooks →](/edge/en/learn/before-and-after-kickoff-hooks)
|
||||
- [Human-in-the-Loop →](/edge/en/learn/human-in-the-loop)
|
||||
@crew
|
||||
def crew(self) -> Crew:
|
||||
return Crew(
|
||||
agents=self.agents,
|
||||
tasks=self.tasks,
|
||||
process=Process.sequential
|
||||
)
|
||||
```
|
||||
|
||||
## Hook Execution Flow
|
||||
|
||||
### LLM Call Flow
|
||||
|
||||
```
|
||||
Agent needs to call LLM
|
||||
↓
|
||||
[Before LLM Call Hooks Execute]
|
||||
├→ Hook 1: Validate iteration count
|
||||
├→ Hook 2: Add safety context
|
||||
└→ Hook 3: Log request
|
||||
↓
|
||||
If any hook returns False:
|
||||
├→ Block LLM call
|
||||
└→ Raise ValueError
|
||||
↓
|
||||
If all hooks return True/None:
|
||||
├→ LLM call proceeds
|
||||
└→ Response generated
|
||||
↓
|
||||
[After LLM Call Hooks Execute]
|
||||
├→ Hook 1: Sanitize response
|
||||
├→ Hook 2: Log response
|
||||
└→ Hook 3: Update metrics
|
||||
↓
|
||||
Final response returned
|
||||
```
|
||||
|
||||
### Tool Call Flow
|
||||
|
||||
```
|
||||
Agent needs to execute tool
|
||||
↓
|
||||
[Before Tool Call Hooks Execute]
|
||||
├→ Hook 1: Check if tool is allowed
|
||||
├→ Hook 2: Validate inputs
|
||||
└→ Hook 3: Request approval if needed
|
||||
↓
|
||||
If any hook returns False:
|
||||
├→ Block tool execution
|
||||
└→ Return error message
|
||||
↓
|
||||
If all hooks return True/None:
|
||||
├→ Tool execution proceeds
|
||||
└→ Result generated
|
||||
↓
|
||||
[After Tool Call Hooks Execute]
|
||||
├→ Hook 1: Sanitize result
|
||||
├→ Hook 2: Cache result
|
||||
└→ Hook 3: Log metrics
|
||||
↓
|
||||
Final result returned
|
||||
```
|
||||
|
||||
## Hook Context Objects
|
||||
|
||||
### LLMCallHookContext
|
||||
|
||||
Provides access to LLM execution state:
|
||||
|
||||
```python
|
||||
class LLMCallHookContext:
|
||||
executor: CrewAgentExecutor # Full executor access
|
||||
messages: list # Mutable message list
|
||||
agent: Agent # Current agent
|
||||
task: Task # Current task
|
||||
crew: Crew # Crew instance
|
||||
llm: BaseLLM # LLM instance
|
||||
iterations: int # Current iteration
|
||||
response: str | None # LLM response (after hooks)
|
||||
```
|
||||
|
||||
### ToolCallHookContext
|
||||
|
||||
Provides access to tool execution state:
|
||||
|
||||
```python
|
||||
class ToolCallHookContext:
|
||||
tool_name: str # Tool being called
|
||||
tool_input: dict # Mutable input parameters
|
||||
tool: CrewStructuredTool # Tool instance
|
||||
agent: Agent | None # Agent executing
|
||||
task: Task | None # Current task
|
||||
crew: Crew | None # Crew instance
|
||||
tool_result: str | None # Agent-facing result string (after hooks)
|
||||
raw_tool_result: Any | None # Raw Python result (after hooks)
|
||||
```
|
||||
|
||||
For typed tool outputs, `tool_result` is the string the agent sees. By default, this is JSON. If the tool uses custom formatting, it can be Markdown or another string. `raw_tool_result` is the original Python value returned by the tool.
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Safety and Validation
|
||||
|
||||
```python
|
||||
@before_tool_call
|
||||
def safety_check(context):
|
||||
"""Block destructive operations."""
|
||||
dangerous = ['delete_file', 'drop_table', 'system_shutdown']
|
||||
if context.tool_name in dangerous:
|
||||
print(f"🛑 Blocked: {context.tool_name}")
|
||||
return False
|
||||
return None
|
||||
|
||||
@before_llm_call
|
||||
def iteration_limit(context):
|
||||
"""Prevent infinite loops."""
|
||||
if context.iterations > 15:
|
||||
print("⛔ Maximum iterations exceeded")
|
||||
return False
|
||||
return None
|
||||
```
|
||||
|
||||
### Human-in-the-Loop
|
||||
|
||||
```python
|
||||
@before_tool_call
|
||||
def require_approval(context):
|
||||
"""Require approval for sensitive operations."""
|
||||
sensitive = ['send_email', 'make_payment', 'post_message']
|
||||
|
||||
if context.tool_name in sensitive:
|
||||
response = context.request_human_input(
|
||||
prompt=f"Approve {context.tool_name}?",
|
||||
default_message="Type 'yes' to approve:"
|
||||
)
|
||||
|
||||
if response.lower() != 'yes':
|
||||
return False
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### Monitoring and Analytics
|
||||
|
||||
```python
|
||||
from collections import defaultdict
|
||||
import time
|
||||
|
||||
metrics = defaultdict(lambda: {'count': 0, 'total_time': 0})
|
||||
|
||||
@before_tool_call
|
||||
def start_timer(context):
|
||||
context.tool_input['_start'] = time.time()
|
||||
return None
|
||||
|
||||
@after_tool_call
|
||||
def track_metrics(context):
|
||||
start = context.tool_input.get('_start', time.time())
|
||||
duration = time.time() - start
|
||||
|
||||
metrics[context.tool_name]['count'] += 1
|
||||
metrics[context.tool_name]['total_time'] += duration
|
||||
|
||||
return None
|
||||
|
||||
# View metrics
|
||||
def print_metrics():
|
||||
for tool, data in metrics.items():
|
||||
avg = data['total_time'] / data['count']
|
||||
print(f"{tool}: {data['count']} calls, {avg:.2f}s avg")
|
||||
```
|
||||
|
||||
### Response Sanitization
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
@after_llm_call
|
||||
def sanitize_llm_response(context):
|
||||
"""Remove sensitive data from LLM responses."""
|
||||
if not context.response:
|
||||
return None
|
||||
|
||||
result = context.response
|
||||
result = re.sub(r'(api[_-]?key)["\']?\s*[:=]\s*["\']?[\w-]+',
|
||||
r'\1: [REDACTED]', result, flags=re.IGNORECASE)
|
||||
return result
|
||||
|
||||
@after_tool_call
|
||||
def sanitize_tool_result(context):
|
||||
"""Remove sensitive data from tool results."""
|
||||
if not context.tool_result:
|
||||
return None
|
||||
|
||||
result = context.tool_result
|
||||
result = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
|
||||
'[EMAIL-REDACTED]', result)
|
||||
return result
|
||||
```
|
||||
|
||||
## Hook Management
|
||||
|
||||
### Clearing All Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import clear_all_global_hooks
|
||||
|
||||
# Clear all hooks at once
|
||||
result = clear_all_global_hooks()
|
||||
print(f"Cleared {result['total']} hooks")
|
||||
# Output: {'llm_hooks': (2, 1), 'tool_hooks': (1, 2), 'total': (3, 3)}
|
||||
```
|
||||
|
||||
### Clearing Specific Hook Types
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
clear_before_llm_call_hooks,
|
||||
clear_after_llm_call_hooks,
|
||||
clear_before_tool_call_hooks,
|
||||
clear_after_tool_call_hooks
|
||||
)
|
||||
|
||||
# Clear specific types
|
||||
llm_before_count = clear_before_llm_call_hooks()
|
||||
tool_after_count = clear_after_tool_call_hooks()
|
||||
```
|
||||
|
||||
### Unregistering Individual Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
unregister_before_llm_call_hook,
|
||||
unregister_after_tool_call_hook
|
||||
)
|
||||
|
||||
def my_hook(context):
|
||||
...
|
||||
|
||||
# Register
|
||||
register_before_llm_call_hook(my_hook)
|
||||
|
||||
# Later, unregister
|
||||
success = unregister_before_llm_call_hook(my_hook)
|
||||
print(f"Unregistered: {success}")
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Keep Hooks Focused
|
||||
Each hook should have a single, clear responsibility:
|
||||
|
||||
```python
|
||||
# ✅ Good - focused responsibility
|
||||
@before_tool_call
|
||||
def validate_file_path(context):
|
||||
if context.tool_name == 'read_file':
|
||||
if '..' in context.tool_input.get('path', ''):
|
||||
return False
|
||||
return None
|
||||
|
||||
# ❌ Bad - too many responsibilities
|
||||
@before_tool_call
|
||||
def do_everything(context):
|
||||
# Validation + logging + metrics + approval...
|
||||
...
|
||||
```
|
||||
|
||||
### 2. Handle Errors Gracefully
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def safe_hook(context):
|
||||
try:
|
||||
# Your logic
|
||||
if some_condition:
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Hook error: {e}")
|
||||
return None # Allow execution despite error
|
||||
```
|
||||
|
||||
### 3. Modify Context In-Place
|
||||
|
||||
```python
|
||||
# ✅ Correct - modify in-place
|
||||
@before_llm_call
|
||||
def add_context(context):
|
||||
context.messages.append({"role": "system", "content": "Be concise"})
|
||||
|
||||
# ❌ Wrong - replaces reference
|
||||
@before_llm_call
|
||||
def wrong_approach(context):
|
||||
context.messages = [{"role": "system", "content": "Be concise"}]
|
||||
```
|
||||
|
||||
### 4. Use Type Hints
|
||||
|
||||
```python
|
||||
from crewai.hooks import LLMCallHookContext, ToolCallHookContext
|
||||
|
||||
def my_llm_hook(context: LLMCallHookContext) -> bool | None:
|
||||
# IDE autocomplete and type checking
|
||||
return None
|
||||
|
||||
def my_tool_hook(context: ToolCallHookContext) -> str | None:
|
||||
return None
|
||||
```
|
||||
|
||||
### 5. Clean Up in Tests
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from crewai.hooks import clear_all_global_hooks
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clean_hooks():
|
||||
"""Reset hooks before each test."""
|
||||
yield
|
||||
clear_all_global_hooks()
|
||||
```
|
||||
|
||||
## When to Use Which Hook
|
||||
|
||||
### Use LLM Hooks When:
|
||||
- Implementing iteration limits
|
||||
- Adding context or safety guidelines to prompts
|
||||
- Tracking token usage and costs
|
||||
- Sanitizing or transforming responses
|
||||
- Implementing approval gates for LLM calls
|
||||
- Debugging prompt/response interactions
|
||||
|
||||
### Use Tool Hooks When:
|
||||
- Blocking dangerous or destructive operations
|
||||
- Validating tool inputs before execution
|
||||
- Implementing approval gates for sensitive actions
|
||||
- Caching tool results
|
||||
- Tracking tool usage and performance
|
||||
- Sanitizing tool outputs
|
||||
- Rate limiting tool calls
|
||||
|
||||
### Use Both When:
|
||||
Building comprehensive observability, safety, or approval systems that need to monitor all agent operations.
|
||||
|
||||
## Alternative Registration Methods
|
||||
|
||||
### Programmatic Registration (Advanced)
|
||||
|
||||
For dynamic hook registration or when you need to register hooks programmatically:
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
register_before_llm_call_hook,
|
||||
register_after_tool_call_hook
|
||||
)
|
||||
|
||||
def my_hook(context):
|
||||
return None
|
||||
|
||||
# Register programmatically
|
||||
register_before_llm_call_hook(my_hook)
|
||||
|
||||
# Useful for:
|
||||
# - Loading hooks from configuration
|
||||
# - Conditional hook registration
|
||||
# - Plugin systems
|
||||
```
|
||||
|
||||
**Note:** For most use cases, decorators are cleaner and more maintainable.
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Keep Hooks Fast**: Hooks execute on every call - avoid heavy computation
|
||||
2. **Cache When Possible**: Store expensive validations or lookups
|
||||
3. **Be Selective**: Use crew-scoped hooks when global hooks aren't needed
|
||||
4. **Monitor Hook Overhead**: Profile hook execution time in production
|
||||
5. **Lazy Import**: Import heavy dependencies only when needed
|
||||
|
||||
## Debugging Hooks
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@before_llm_call
|
||||
def debug_hook(context):
|
||||
logger.debug(f"LLM call: {context.agent.role}, iteration {context.iterations}")
|
||||
return None
|
||||
```
|
||||
|
||||
### Hook Execution Order
|
||||
|
||||
Hooks execute in registration order. If a before hook returns `False`, subsequent hooks don't execute:
|
||||
|
||||
```python
|
||||
# Register order matters!
|
||||
register_before_tool_call_hook(hook1) # Executes first
|
||||
register_before_tool_call_hook(hook2) # Executes second
|
||||
register_before_tool_call_hook(hook3) # Executes third
|
||||
|
||||
# If hook2 returns False:
|
||||
# - hook1 executed
|
||||
# - hook2 executed and returned False
|
||||
# - hook3 NOT executed
|
||||
# - Tool call blocked
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [LLM Call Hooks →](/learn/llm-hooks) - Detailed LLM hook documentation
|
||||
- [Tool Call Hooks →](/learn/tool-hooks) - Detailed tool hook documentation
|
||||
- [Before and After Kickoff Hooks →](/learn/before-and-after-kickoff-hooks) - Crew lifecycle hooks
|
||||
- [Human-in-the-Loop →](/learn/human-in-the-loop) - Human input patterns
|
||||
|
||||
## Conclusion
|
||||
|
||||
Execution hooks provide powerful control over agent runtime behavior. Use them to implement safety guardrails, approval workflows, comprehensive monitoring, and custom business logic. Combined with proper error handling, type safety, and performance considerations, hooks enable production-ready, secure, and observable agent systems.
|
||||
|
||||
@@ -240,15 +240,14 @@ from crewai import LLM
|
||||
|
||||
# After (OpenAI-compatible mode, no LiteLLM needed):
|
||||
llm = LLM(
|
||||
model="llama3",
|
||||
custom_openai=True,
|
||||
model="openai/llama3",
|
||||
base_url="http://localhost:11434/v1",
|
||||
api_key="ollama" # Ollama doesn't require a real API key
|
||||
)
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Many local inference servers (Ollama, vLLM, LM Studio, llama.cpp) expose an OpenAI-compatible API. You can use `custom_openai=True` with a custom `base_url` to connect to any of them natively while keeping the model ID your gateway expects.
|
||||
Many local inference servers (Ollama, vLLM, LM Studio, llama.cpp) expose an OpenAI-compatible API. You can use the `openai/` prefix with a custom `base_url` to connect to any of them natively.
|
||||
</Tip>
|
||||
|
||||
### Step 4: Update your YAML configs
|
||||
@@ -296,92 +295,6 @@ crewai run
|
||||
uv run pytest
|
||||
```
|
||||
|
||||
## Custom OpenAI-Compatible Endpoints
|
||||
|
||||
Many providers and local servers (Ollama, vLLM, LM Studio, llama.cpp, LiteLLM proxies, and hosted gateways) expose an **OpenAI-compatible** API. Instead of routing these through LiteLLM, you can talk to them directly with CrewAI's native OpenAI integration by setting `custom_openai=True`.
|
||||
|
||||
This is the recommended replacement for any LiteLLM provider that offers an OpenAI-compatible endpoint.
|
||||
|
||||
### How it works
|
||||
|
||||
- `custom_openai=True` forces CrewAI to use the native OpenAI SDK, regardless of the model name.
|
||||
- The model ID is passed to the endpoint without validation against OpenAI's known-model list. This lets you use arbitrary model IDs your gateway expects (for example, `anthropic/claude-sonnet-4-6` served behind an OpenAI-compatible proxy). An optional leading `openai/` routing prefix is stripped.
|
||||
- A base URL is **required**. CrewAI resolves it, in order, from:
|
||||
1. `base_url=...`
|
||||
2. `api_base=...`
|
||||
3. `OPENAI_BASE_URL` environment variable
|
||||
4. `OPENAI_API_BASE` environment variable (legacy)
|
||||
|
||||
If none are set, CrewAI raises a `ValueError` so misconfiguration fails fast instead of silently hitting `api.openai.com`.
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
llm = LLM(
|
||||
model="anthropic/claude-sonnet-4-6", # passed through as-is
|
||||
custom_openai=True,
|
||||
base_url="https://your-gateway.example/v1",
|
||||
api_key="your-key",
|
||||
)
|
||||
```
|
||||
|
||||
### Connect to common servers
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Ollama">
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
llm = LLM(
|
||||
model="llama3.2:latest",
|
||||
custom_openai=True,
|
||||
base_url="http://localhost:11434/v1",
|
||||
api_key="ollama", # Ollama ignores it, but the client requires a value
|
||||
)
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="vLLM">
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
llm = LLM(
|
||||
model="meta-llama/Meta-Llama-3.1-8B-Instruct",
|
||||
custom_openai=True,
|
||||
base_url="http://localhost:8000/v1",
|
||||
api_key="not-needed",
|
||||
)
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="LM Studio">
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
llm = LLM(
|
||||
model="your-loaded-model",
|
||||
custom_openai=True,
|
||||
base_url="http://localhost:1234/v1",
|
||||
api_key="lm-studio",
|
||||
)
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Env vars">
|
||||
```bash
|
||||
export OPENAI_BASE_URL="https://your-gateway.example/v1"
|
||||
export OPENAI_API_KEY="your-key"
|
||||
```
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
# base_url is picked up from OPENAI_BASE_URL / OPENAI_API_BASE
|
||||
llm = LLM(model="anthropic/claude-sonnet-4-6", custom_openai=True)
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Tip>
|
||||
If you use the `openai/` prefix with a model that isn't a known OpenAI model and pass `base_url` or `api_base` directly, CrewAI automatically treats it as a custom OpenAI-compatible endpoint. Environment variables alone do not enable automatic routing for unknown models; set `custom_openai=True` when configuring the endpoint through `OPENAI_BASE_URL` or `OPENAI_API_BASE`.
|
||||
</Tip>
|
||||
|
||||
## Quick Reference: Model String Mapping
|
||||
|
||||
Here are common migration paths from LiteLLM-dependent providers to native ones:
|
||||
@@ -408,8 +321,7 @@ llm = LLM(model="anthropic/claude-sonnet-4-20250514") # High quality
|
||||
# Ollama → OpenAI-compatible (keep using local models)
|
||||
# llm = LLM(model="ollama/llama3")
|
||||
llm = LLM(
|
||||
model="llama3",
|
||||
custom_openai=True,
|
||||
model="openai/llama3",
|
||||
base_url="http://localhost:11434/v1",
|
||||
api_key="ollama"
|
||||
)
|
||||
@@ -437,9 +349,6 @@ llm = LLM(
|
||||
<Accordion title="What about environment variables like OPENAI_API_KEY?">
|
||||
Native providers use the same environment variables you're already familiar with. No changes needed for `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, etc.
|
||||
</Accordion>
|
||||
<Accordion title="How do I connect to Groq, Together AI, or other OpenAI-compatible providers without LiteLLM?">
|
||||
Most of these providers expose an OpenAI-compatible API. Use `custom_openai=True` with their base URL and API key — see [Custom OpenAI-Compatible Endpoints](#custom-openai-compatible-endpoints). For example, Groq: `LLM(model="llama-3.1-70b-versatile", custom_openai=True, base_url="https://api.groq.com/openai/v1", api_key="...")`. The model ID is passed through untouched, so use whatever ID the provider expects.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Related Resources
|
||||
|
||||
@@ -4,51 +4,49 @@ description: Learn how to use LLM call hooks to intercept, modify, and control l
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
LLM Call Hooks provide fine-grained control over language model interactions
|
||||
during agent execution. These hooks allow you to intercept LLM calls, modify
|
||||
prompts, transform responses, implement approval gates, and add custom logging
|
||||
or monitoring.
|
||||
LLM Call Hooks provide fine-grained control over language model interactions during agent execution. These hooks allow you to intercept LLM calls, modify prompts, transform responses, implement approval gates, and add custom logging or monitoring.
|
||||
|
||||
## Overview
|
||||
|
||||
LLM hooks are executed at two interception points:
|
||||
LLM hooks are executed at two critical points:
|
||||
- **Before LLM Call**: Modify messages, validate inputs, or block execution
|
||||
- **After LLM Call**: Transform responses, sanitize outputs, or modify conversation history
|
||||
|
||||
| Point | When | Hook receives |
|
||||
|-------|------|---------------|
|
||||
| `PRE_MODEL_CALL` | Before every LLM call | `LLMCallHookContext` |
|
||||
| `POST_MODEL_CALL` | After every LLM call | `LLMCallHookContext` (with `response` set) |
|
||||
## Hook Types
|
||||
|
||||
Write them with the [`@on` decorator](/edge/en/learn/execution-hooks). The
|
||||
[legacy `@before_llm_call` / `@after_llm_call` decorators](#legacy-decorators)
|
||||
keep working unchanged — both styles register on the same engine and run in one
|
||||
ordered chain.
|
||||
### Before LLM Call Hooks
|
||||
|
||||
## Hook Signature
|
||||
Executed before every LLM call, these hooks can:
|
||||
- Inspect and modify messages sent to the LLM
|
||||
- Block LLM execution based on conditions
|
||||
- Implement rate limiting or approval gates
|
||||
- Add context or system messages
|
||||
- Log request details
|
||||
|
||||
**Signature:**
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint, LLMCallHookContext
|
||||
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def before_hook(ctx: LLMCallHookContext) -> None:
|
||||
# Mutate ctx.messages in place, or
|
||||
# raise HookAborted(reason, source) to block the call
|
||||
...
|
||||
|
||||
@on(InterceptionPoint.POST_MODEL_CALL)
|
||||
def after_hook(ctx: LLMCallHookContext) -> str | None:
|
||||
# Return a string to replace ctx.response
|
||||
# Return None to keep the original response
|
||||
def before_hook(context: LLMCallHookContext) -> bool | None:
|
||||
# Return False to block execution
|
||||
# Return True or None to allow execution
|
||||
...
|
||||
```
|
||||
|
||||
Unlike the boundary and step points, the model-call points pass the rich
|
||||
`LLMCallHookContext` directly as the hook argument (there is no separate
|
||||
`ctx.payload`): mutate `ctx.messages` in place before the call, and return a
|
||||
string to replace the response after it.
|
||||
### After LLM Call Hooks
|
||||
|
||||
Blocking a call raises `ValueError("LLM call blocked by before_llm_call hook")`
|
||||
inside the executor; the `HookAborted` reason and source are recorded in
|
||||
[telemetry](/edge/en/learn/execution-hooks#telemetry).
|
||||
Executed after every LLM call, these hooks can:
|
||||
- Modify or sanitize LLM responses
|
||||
- Add metadata or formatting
|
||||
- Log response details
|
||||
- Update conversation history
|
||||
- Implement content filtering
|
||||
|
||||
**Signature:**
|
||||
```python
|
||||
def after_hook(context: LLMCallHookContext) -> str | None:
|
||||
# Return modified response string
|
||||
# Return None to keep original response
|
||||
...
|
||||
```
|
||||
|
||||
## LLM Hook Context
|
||||
|
||||
@@ -56,171 +54,49 @@ The `LLMCallHookContext` object provides comprehensive access to execution state
|
||||
|
||||
```python
|
||||
class LLMCallHookContext:
|
||||
executor: CrewAgentExecutor | LiteAgent | None # Executor (None for direct LLM calls)
|
||||
executor: CrewAgentExecutor # Full executor reference
|
||||
messages: list # Mutable message list
|
||||
agent: Agent | None # Current agent (None for direct LLM calls)
|
||||
task: Task | None # Current task (None for direct calls or LiteAgent)
|
||||
crew: Crew | None # Crew instance (None for direct calls or LiteAgent)
|
||||
llm: BaseLLM | None # LLM instance
|
||||
iterations: int # Current iteration count (0 for direct calls)
|
||||
response: str | None # LLM response (POST_MODEL_CALL only)
|
||||
agent: Agent # Current agent
|
||||
task: Task # Current task
|
||||
crew: Crew # Crew instance
|
||||
llm: BaseLLM # LLM instance
|
||||
iterations: int # Current iteration count
|
||||
response: str | None # LLM response (after hooks only)
|
||||
```
|
||||
|
||||
The context also exposes `request_human_input(prompt, default_message)`, which
|
||||
pauses live console updates and collects input from the terminal — useful for
|
||||
approval gates.
|
||||
|
||||
### Modifying Messages
|
||||
|
||||
**Important:** Always modify messages in-place:
|
||||
|
||||
```python
|
||||
# ✅ Correct - modify in-place
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def add_context(ctx: LLMCallHookContext) -> None:
|
||||
ctx.messages.append({"role": "system", "content": "Be concise"})
|
||||
def add_context(context: LLMCallHookContext) -> None:
|
||||
context.messages.append({"role": "system", "content": "Be concise"})
|
||||
|
||||
# ❌ Wrong - replaces list reference and breaks the executor
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def wrong_approach(ctx: LLMCallHookContext) -> None:
|
||||
ctx.messages = [{"role": "system", "content": "Be concise"}]
|
||||
# ❌ Wrong - replaces list reference
|
||||
def wrong_approach(context: LLMCallHookContext) -> None:
|
||||
context.messages = [{"role": "system", "content": "Be concise"}]
|
||||
```
|
||||
|
||||
## Registration Methods
|
||||
|
||||
### 1. Global Hooks
|
||||
### 1. Global Hook Registration
|
||||
|
||||
Apply to all LLM calls across all crews. Use the `agents=` filter to scope a
|
||||
hook to specific agent roles:
|
||||
Register hooks that apply to all LLM calls across all crews:
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, InterceptionPoint
|
||||
from crewai.hooks import register_before_llm_call_hook, register_after_llm_call_hook
|
||||
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def log_llm_call(ctx):
|
||||
print(f"LLM call by {ctx.agent.role} at iteration {ctx.iterations}")
|
||||
def log_llm_call(context):
|
||||
print(f"LLM call by {context.agent.role} at iteration {context.iterations}")
|
||||
return None # Allow execution
|
||||
|
||||
@on(InterceptionPoint.POST_MODEL_CALL, agents=["Researcher"])
|
||||
def log_researcher_responses(ctx):
|
||||
print(f"Response length: {len(ctx.response)}")
|
||||
register_before_llm_call_hook(log_llm_call)
|
||||
```
|
||||
|
||||
### 2. Crew-Scoped Hooks
|
||||
### 2. Decorator-Based Registration
|
||||
|
||||
Apply the same decorator to a method inside a `@CrewBase` class to scope the
|
||||
hook to that crew only:
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, InterceptionPoint
|
||||
|
||||
@CrewBase
|
||||
class MyProjCrew:
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def validate_inputs(self, ctx):
|
||||
# Only applies to this crew
|
||||
if ctx.iterations == 0:
|
||||
print(f"Starting task: {ctx.task.description}")
|
||||
|
||||
@crew
|
||||
def crew(self) -> Crew:
|
||||
return Crew(agents=self.agents, tasks=self.tasks, process=Process.sequential)
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### 1. Iteration Limiting
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def limit_iterations(ctx: LLMCallHookContext) -> None:
|
||||
if ctx.iterations > 15:
|
||||
raise HookAborted(reason="exceeded 15 iterations", source="loop-guard")
|
||||
```
|
||||
|
||||
### 2. Human Approval Gate
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def require_approval(ctx: LLMCallHookContext) -> None:
|
||||
if ctx.iterations > 5:
|
||||
response = ctx.request_human_input(
|
||||
prompt=f"Iteration {ctx.iterations}: Approve LLM call?",
|
||||
default_message="Press Enter to approve, or type 'no' to block:",
|
||||
)
|
||||
if response.lower() == "no":
|
||||
raise HookAborted(reason="blocked by user", source="approval-gate")
|
||||
```
|
||||
|
||||
### 3. Adding System Context
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def add_guardrails(ctx: LLMCallHookContext) -> None:
|
||||
ctx.messages.append({
|
||||
"role": "system",
|
||||
"content": "Ensure responses are factual and cite sources when possible."
|
||||
})
|
||||
```
|
||||
|
||||
### 4. Response Sanitization
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
@on(InterceptionPoint.POST_MODEL_CALL)
|
||||
def sanitize_sensitive_data(ctx: LLMCallHookContext) -> str | None:
|
||||
if not ctx.response:
|
||||
return None
|
||||
sanitized = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN-REDACTED]', ctx.response)
|
||||
return re.sub(r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b', '[CARD-REDACTED]', sanitized)
|
||||
```
|
||||
|
||||
### 5. Debug Logging
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_MODEL_CALL)
|
||||
def debug_request(ctx: LLMCallHookContext) -> None:
|
||||
print(f"Agent: {ctx.agent.role}, iteration {ctx.iterations}, "
|
||||
f"{len(ctx.messages)} messages")
|
||||
|
||||
@on(InterceptionPoint.POST_MODEL_CALL)
|
||||
def debug_response(ctx: LLMCallHookContext) -> None:
|
||||
if ctx.response:
|
||||
print(f"Response preview: {ctx.response[:100]}...")
|
||||
```
|
||||
|
||||
## Hook Management
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
InterceptionPoint,
|
||||
clear_all_hooks,
|
||||
clear_hooks,
|
||||
get_hooks,
|
||||
unregister_hook,
|
||||
)
|
||||
|
||||
# Unregister a specific hook
|
||||
unregister_hook(InterceptionPoint.PRE_MODEL_CALL, my_hook)
|
||||
|
||||
# Clear one point, or everything (e.g. between tests)
|
||||
clear_hooks(InterceptionPoint.POST_MODEL_CALL)
|
||||
clear_all_hooks()
|
||||
|
||||
# Inspect what's registered
|
||||
print(len(get_hooks(InterceptionPoint.PRE_MODEL_CALL)))
|
||||
```
|
||||
|
||||
The legacy management API (`register_before_llm_call_hook`,
|
||||
`unregister_before_llm_call_hook`, `clear_before_llm_call_hooks`,
|
||||
`clear_all_llm_call_hooks`, `get_before_llm_call_hooks`, and their `after_`
|
||||
counterparts) operates on the same underlying registries, so either API can
|
||||
manage hooks registered by the other.
|
||||
|
||||
## Legacy Decorators
|
||||
|
||||
The original per-point decorators keep working unchanged and run in the same
|
||||
registration-order chain as `@on` hooks:
|
||||
Use decorators for cleaner syntax:
|
||||
|
||||
```python
|
||||
from crewai.hooks import before_llm_call, after_llm_call
|
||||
@@ -228,55 +104,324 @@ from crewai.hooks import before_llm_call, after_llm_call
|
||||
@before_llm_call
|
||||
def validate_iteration_count(context):
|
||||
if context.iterations > 10:
|
||||
print("⚠️ Exceeded maximum iterations")
|
||||
return False # Block execution
|
||||
return None
|
||||
|
||||
@after_llm_call(agents=["Researcher"])
|
||||
@after_llm_call
|
||||
def sanitize_response(context):
|
||||
if context.response and "API_KEY" in context.response:
|
||||
return context.response.replace("API_KEY", "[REDACTED]")
|
||||
return None
|
||||
```
|
||||
|
||||
Differences from `@on`:
|
||||
### 3. Crew-Scoped Hooks
|
||||
|
||||
- **Blocking** is `return False` from a before hook — equivalent to raising
|
||||
`HookAborted`, but without a custom reason or source for telemetry.
|
||||
- **Signatures** are point-specific: before hooks return `bool | None`, after
|
||||
hooks return `str | None`. The context object is the same
|
||||
`LLMCallHookContext`.
|
||||
- **Filters and crew-scoping** work the same way: `@before_llm_call(agents=[...])`,
|
||||
and applying the decorator to a `@CrewBase` method scopes it to that crew.
|
||||
Register hooks for a specific crew instance:
|
||||
|
||||
Prefer `@on` for new code; keep the legacy style where it is already in use —
|
||||
there is no behavioral penalty.
|
||||
```python
|
||||
@CrewBase
|
||||
class MyProjCrew:
|
||||
@before_llm_call_crew
|
||||
def validate_inputs(self, context):
|
||||
# Only applies to this crew
|
||||
if context.iterations == 0:
|
||||
print(f"Starting task: {context.task.description}")
|
||||
return None
|
||||
|
||||
@after_llm_call_crew
|
||||
def log_responses(self, context):
|
||||
# Crew-specific response logging
|
||||
print(f"Response length: {len(context.response)}")
|
||||
return None
|
||||
|
||||
@crew
|
||||
def crew(self) -> Crew:
|
||||
return Crew(
|
||||
agents=self.agents,
|
||||
tasks=self.tasks,
|
||||
process=Process.sequential,
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### 1. Iteration Limiting
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def limit_iterations(context: LLMCallHookContext) -> bool | None:
|
||||
max_iterations = 15
|
||||
if context.iterations > max_iterations:
|
||||
print(f"⛔ Blocked: Exceeded {max_iterations} iterations")
|
||||
return False # Block execution
|
||||
return None
|
||||
```
|
||||
|
||||
### 2. Human Approval Gate
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def require_approval(context: LLMCallHookContext) -> bool | None:
|
||||
if context.iterations > 5:
|
||||
response = context.request_human_input(
|
||||
prompt=f"Iteration {context.iterations}: Approve LLM call?",
|
||||
default_message="Press Enter to approve, or type 'no' to block:"
|
||||
)
|
||||
if response.lower() == "no":
|
||||
print("🚫 LLM call blocked by user")
|
||||
return False
|
||||
return None
|
||||
```
|
||||
|
||||
### 3. Adding System Context
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def add_guardrails(context: LLMCallHookContext) -> None:
|
||||
# Add safety guidelines to every LLM call
|
||||
context.messages.append({
|
||||
"role": "system",
|
||||
"content": "Ensure responses are factual and cite sources when possible."
|
||||
})
|
||||
return None
|
||||
```
|
||||
|
||||
### 4. Response Sanitization
|
||||
|
||||
```python
|
||||
@after_llm_call
|
||||
def sanitize_sensitive_data(context: LLMCallHookContext) -> str | None:
|
||||
if not context.response:
|
||||
return None
|
||||
|
||||
# Remove sensitive patterns
|
||||
import re
|
||||
sanitized = context.response
|
||||
sanitized = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN-REDACTED]', sanitized)
|
||||
sanitized = re.sub(r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b', '[CARD-REDACTED]', sanitized)
|
||||
|
||||
return sanitized
|
||||
```
|
||||
|
||||
### 5. Cost Tracking
|
||||
|
||||
```python
|
||||
import tiktoken
|
||||
|
||||
@before_llm_call
|
||||
def track_token_usage(context: LLMCallHookContext) -> None:
|
||||
encoding = tiktoken.get_encoding("cl100k_base")
|
||||
total_tokens = sum(
|
||||
len(encoding.encode(msg.get("content", "")))
|
||||
for msg in context.messages
|
||||
)
|
||||
print(f"📊 Input tokens: ~{total_tokens}")
|
||||
return None
|
||||
|
||||
@after_llm_call
|
||||
def track_response_tokens(context: LLMCallHookContext) -> None:
|
||||
if context.response:
|
||||
encoding = tiktoken.get_encoding("cl100k_base")
|
||||
tokens = len(encoding.encode(context.response))
|
||||
print(f"📊 Response tokens: ~{tokens}")
|
||||
return None
|
||||
```
|
||||
|
||||
### 6. Debug Logging
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def debug_request(context: LLMCallHookContext) -> None:
|
||||
print(f"""
|
||||
🔍 LLM Call Debug:
|
||||
- Agent: {context.agent.role}
|
||||
- Task: {context.task.description[:50]}...
|
||||
- Iteration: {context.iterations}
|
||||
- Message Count: {len(context.messages)}
|
||||
- Last Message: {context.messages[-1] if context.messages else 'None'}
|
||||
""")
|
||||
return None
|
||||
|
||||
@after_llm_call
|
||||
def debug_response(context: LLMCallHookContext) -> None:
|
||||
if context.response:
|
||||
print(f"✅ Response Preview: {context.response[:100]}...")
|
||||
return None
|
||||
```
|
||||
|
||||
## Hook Management
|
||||
|
||||
### Unregistering Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
unregister_before_llm_call_hook,
|
||||
unregister_after_llm_call_hook
|
||||
)
|
||||
|
||||
# Unregister specific hook
|
||||
def my_hook(context):
|
||||
...
|
||||
|
||||
register_before_llm_call_hook(my_hook)
|
||||
# Later...
|
||||
unregister_before_llm_call_hook(my_hook) # Returns True if found
|
||||
```
|
||||
|
||||
### Clearing Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
clear_before_llm_call_hooks,
|
||||
clear_after_llm_call_hooks,
|
||||
clear_all_llm_call_hooks
|
||||
)
|
||||
|
||||
# Clear specific hook type
|
||||
count = clear_before_llm_call_hooks()
|
||||
print(f"Cleared {count} before hooks")
|
||||
|
||||
# Clear all LLM hooks
|
||||
before_count, after_count = clear_all_llm_call_hooks()
|
||||
print(f"Cleared {before_count} before and {after_count} after hooks")
|
||||
```
|
||||
|
||||
### Listing Registered Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
get_before_llm_call_hooks,
|
||||
get_after_llm_call_hooks
|
||||
)
|
||||
|
||||
# Get current hooks
|
||||
before_hooks = get_before_llm_call_hooks()
|
||||
after_hooks = get_after_llm_call_hooks()
|
||||
|
||||
print(f"Registered: {len(before_hooks)} before, {len(after_hooks)} after")
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Conditional Hook Execution
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def conditional_blocking(context: LLMCallHookContext) -> bool | None:
|
||||
# Only block for specific agents
|
||||
if context.agent.role == "researcher" and context.iterations > 10:
|
||||
return False
|
||||
|
||||
# Only block for specific tasks
|
||||
if "sensitive" in context.task.description.lower() and context.iterations > 5:
|
||||
return False
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### Context-Aware Modifications
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def adaptive_prompting(context: LLMCallHookContext) -> None:
|
||||
# Add different context based on iteration
|
||||
if context.iterations == 0:
|
||||
context.messages.append({
|
||||
"role": "system",
|
||||
"content": "Start with a high-level overview."
|
||||
})
|
||||
elif context.iterations > 3:
|
||||
context.messages.append({
|
||||
"role": "system",
|
||||
"content": "Focus on specific details and provide examples."
|
||||
})
|
||||
return None
|
||||
```
|
||||
|
||||
### Chaining Hooks
|
||||
|
||||
```python
|
||||
# Multiple hooks execute in registration order
|
||||
|
||||
@before_llm_call
|
||||
def first_hook(context):
|
||||
print("1. First hook executed")
|
||||
return None
|
||||
|
||||
@before_llm_call
|
||||
def second_hook(context):
|
||||
print("2. Second hook executed")
|
||||
return None
|
||||
|
||||
@before_llm_call
|
||||
def blocking_hook(context):
|
||||
if context.iterations > 10:
|
||||
print("3. Blocking hook - execution stopped")
|
||||
return False # Subsequent hooks won't execute
|
||||
print("3. Blocking hook - execution allowed")
|
||||
return None
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep hooks focused and fast** — they run on every LLM call
|
||||
2. **Modify in-place** — always mutate `ctx.messages`, never replace the list
|
||||
3. **Use type hints** — annotate with `LLMCallHookContext` for IDE support
|
||||
4. **Abort loudly** — raise `HookAborted` with a meaningful reason and source;
|
||||
any other exception is swallowed (fail-open)
|
||||
5. **Clear hooks in tests** — call `clear_all_hooks()` between test runs
|
||||
1. **Keep Hooks Focused**: Each hook should have a single responsibility
|
||||
2. **Avoid Heavy Computation**: Hooks execute on every LLM call
|
||||
3. **Handle Errors Gracefully**: Use try-except to prevent hook failures from breaking execution
|
||||
4. **Use Type Hints**: Leverage `LLMCallHookContext` for better IDE support
|
||||
5. **Document Hook Behavior**: Especially for blocking conditions
|
||||
6. **Test Hooks Independently**: Unit test hooks before using in production
|
||||
7. **Clear Hooks in Tests**: Use `clear_all_llm_call_hooks()` between test runs
|
||||
8. **Modify In-Place**: Always modify `context.messages` in-place, never replace
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
@before_llm_call
|
||||
def safe_hook(context: LLMCallHookContext) -> bool | None:
|
||||
try:
|
||||
# Your hook logic
|
||||
if some_condition:
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"⚠️ Hook error: {e}")
|
||||
# Decide: allow or block on error
|
||||
return None # Allow execution despite error
|
||||
```
|
||||
|
||||
## Type Safety
|
||||
|
||||
```python
|
||||
from crewai.hooks import LLMCallHookContext, BeforeLLMCallHookType, AfterLLMCallHookType
|
||||
|
||||
# Explicit type annotations
|
||||
def my_before_hook(context: LLMCallHookContext) -> bool | None:
|
||||
return None
|
||||
|
||||
def my_after_hook(context: LLMCallHookContext) -> str | None:
|
||||
return None
|
||||
|
||||
# Type-safe registration
|
||||
register_before_llm_call_hook(my_before_hook)
|
||||
register_after_llm_call_hook(my_after_hook)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Executing
|
||||
- Verify the hook is registered before crew execution
|
||||
- Check whether an earlier hook aborted (subsequent hooks don't run)
|
||||
- Verify hook is registered before crew execution
|
||||
- Check if previous hook returned `False` (blocks subsequent hooks)
|
||||
- Ensure hook signature matches expected type
|
||||
|
||||
### Message Modifications Not Persisting
|
||||
- Use in-place modifications: `ctx.messages.append(...)`
|
||||
- Don't replace the list: `ctx.messages = []`
|
||||
- Use in-place modifications: `context.messages.append()`
|
||||
- Don't replace the list: `context.messages = []`
|
||||
|
||||
### Response Modifications Not Working
|
||||
- Return the modified string from a `POST_MODEL_CALL` hook
|
||||
- Return the modified string from after hooks
|
||||
- Returning `None` keeps the original response
|
||||
|
||||
## Related Documentation
|
||||
## Conclusion
|
||||
|
||||
- [Execution Hooks Overview →](/edge/en/learn/execution-hooks)
|
||||
- [Tool Call Hooks →](/edge/en/learn/tool-hooks)
|
||||
- [Execution Boundary Hooks →](/edge/en/learn/execution-boundary-hooks)
|
||||
- [Step Hooks →](/edge/en/learn/step-hooks)
|
||||
LLM Call Hooks provide powerful capabilities for controlling and monitoring language model interactions in CrewAI. Use them to implement safety guardrails, approval gates, logging, cost tracking, and response sanitization. Combined with proper error handling and type safety, hooks enable robust and production-ready agent systems.
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
---
|
||||
title: Step Hooks
|
||||
description: Intercept task and flow-method steps with PRE_STEP and POST_STEP hooks in CrewAI
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Step hooks intercept each unit of work inside an execution: every crew **task**
|
||||
and every **flow method**. Use them to inspect or rewrite what goes into a
|
||||
step, transform what comes out, or trace step-by-step progress — without
|
||||
touching the level of individual LLM or tool calls.
|
||||
|
||||
## Overview
|
||||
|
||||
Two interception points cover steps:
|
||||
|
||||
| Point | When | `ctx.payload` |
|
||||
|-------|------|---------------|
|
||||
| `PRE_STEP` | Before a task or flow method runs | step input (see below) |
|
||||
| `POST_STEP` | After a task or flow method runs | step output (see below) |
|
||||
|
||||
What the payload holds depends on `ctx.kind`:
|
||||
|
||||
| `ctx.kind` | `PRE_STEP` payload | `POST_STEP` payload |
|
||||
|------------|--------------------|---------------------|
|
||||
| `"task"` | The context string passed to the agent | The `TaskOutput` object |
|
||||
| `"flow_method"` | The method's parameters as a `dict` | The method's return value |
|
||||
|
||||
For flow methods, positional arguments appear in the params dict under `_0`,
|
||||
`_1`, ... keys and keyword arguments under their own names; edits and
|
||||
replacements are mapped back onto the actual call.
|
||||
|
||||
## Hook Signature
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint
|
||||
|
||||
@on(InterceptionPoint.PRE_STEP)
|
||||
def step_hook(ctx) -> Any | None:
|
||||
# Mutate ctx.payload in place, or
|
||||
# return a non-None value to replace it, or
|
||||
# raise HookAborted(reason, source) to stop the step
|
||||
return None
|
||||
```
|
||||
|
||||
## Context Schema
|
||||
|
||||
Both points receive a `StepContext`:
|
||||
|
||||
```python
|
||||
class StepContext(InterceptionContext):
|
||||
payload: Any # Step input (pre) or step output (post)
|
||||
kind: str | None # "task" or "flow_method"
|
||||
step_name: str | None # Task name/description, or flow method name
|
||||
output: Any # POST_STEP only: same object as payload
|
||||
agent: Any # Task steps: the executing agent (else None)
|
||||
agent_role: str | None # Task steps: the agent's role (else None)
|
||||
task: Any # Task steps: the Task instance (else None)
|
||||
crew: Any # None for step points
|
||||
flow: Any # Flow-method steps: the Flow instance (else None)
|
||||
```
|
||||
|
||||
For task steps, `step_name` is the task's `name` (falling back to its
|
||||
description). For flow-method steps, it is the method name.
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Step Tracing
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.POST_STEP)
|
||||
def trace_steps(ctx):
|
||||
print(f"{ctx.kind} '{ctx.step_name}' finished")
|
||||
```
|
||||
|
||||
### Rewriting Task Context
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_STEP)
|
||||
def inject_disclaimer(ctx):
|
||||
if ctx.kind != "task":
|
||||
return None
|
||||
return f"{ctx.payload}\n\nNote: treat all figures as estimates."
|
||||
```
|
||||
|
||||
### Transforming Task Output
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.POST_STEP)
|
||||
def normalize_output(ctx):
|
||||
if ctx.kind != "task":
|
||||
return None
|
||||
ctx.payload.raw = ctx.payload.raw.strip()
|
||||
```
|
||||
|
||||
<Note>
|
||||
`POST_STEP` runs before the task's output is stored, so rewrites propagate
|
||||
everywhere the output is used: downstream task context, callbacks, the final
|
||||
crew output, and the task's `output_file` on disk.
|
||||
</Note>
|
||||
|
||||
### Guarding Flow Methods
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_STEP)
|
||||
def guard_publish(ctx):
|
||||
if ctx.kind == "flow_method" and ctx.step_name == "publish":
|
||||
if not ctx.flow.state.get("reviewed"):
|
||||
raise HookAborted(reason="publish requires review", source="review-gate")
|
||||
```
|
||||
|
||||
### Filtering by Agent
|
||||
|
||||
Step hooks support the same `agents=` filter as the other points (matched
|
||||
against the executing agent's role on task steps):
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.POST_STEP, agents=["Researcher"])
|
||||
def log_research_steps(ctx):
|
||||
print(f"research step done: {ctx.step_name}")
|
||||
```
|
||||
|
||||
## Aborting a Step
|
||||
|
||||
Raising `HookAborted` in `PRE_STEP` stops the step before any agent or method
|
||||
work happens, and the abort propagates out of the execution with its reason —
|
||||
it is not swallowed. Any other exception raised by a step hook is swallowed
|
||||
(fail-open), like at every other point.
|
||||
|
||||
## Managing Hooks in Tests
|
||||
|
||||
```python
|
||||
from crewai.hooks import clear_all_hooks
|
||||
|
||||
clear_all_hooks() # Clears every point, including steps
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Execution Hooks Overview →](/edge/en/learn/execution-hooks)
|
||||
- [Execution Boundary Hooks →](/edge/en/learn/execution-boundary-hooks)
|
||||
- [LLM Call Hooks →](/edge/en/learn/llm-hooks)
|
||||
- [Tool Call Hooks →](/edge/en/learn/tool-hooks)
|
||||
@@ -11,7 +11,7 @@ CrewAI Flows support streaming output, allowing you to receive real-time updates
|
||||
|
||||
## How Flow Streaming Works
|
||||
|
||||
When streaming is enabled on a Flow, CrewAI captures and streams output from any crews, LLM calls, tools, and lifecycle events within the flow. The stream delivers ordered `StreamFrame` items with printable content plus structured event data as execution progresses.
|
||||
When streaming is enabled on a Flow, CrewAI captures and streams output from any crews or LLM calls within the flow. The stream delivers structured chunks containing the content, task context, and agent information as execution progresses.
|
||||
|
||||
## Enabling Streaming
|
||||
|
||||
@@ -52,7 +52,7 @@ class ResearchFlow(Flow):
|
||||
|
||||
## Synchronous Streaming
|
||||
|
||||
When you call `kickoff()` on a flow with streaming enabled, it returns a stream session that yields ordered `StreamFrame` items:
|
||||
When you call `kickoff()` on a flow with streaming enabled, it returns a `FlowStreamingOutput` object that you can iterate over:
|
||||
|
||||
```python Code
|
||||
flow = ResearchFlow()
|
||||
@@ -60,43 +60,44 @@ flow = ResearchFlow()
|
||||
# Start streaming execution
|
||||
streaming = flow.kickoff()
|
||||
|
||||
# Iterate over stream items as they arrive
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Iterate over chunks as they arrive
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Access the final result after streaming completes
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal output: {result}")
|
||||
```
|
||||
|
||||
### Stream Item Information
|
||||
### Stream Chunk Information
|
||||
|
||||
Each item provides both printable content and structured event data:
|
||||
Each chunk provides context about where it originated in the flow:
|
||||
|
||||
```python Code
|
||||
streaming = flow.kickoff()
|
||||
|
||||
for item in streaming:
|
||||
print(f"Channel: {item.channel}")
|
||||
print(f"Type: {item.type}")
|
||||
print(f"Content: {item.content}")
|
||||
print(f"Event payload: {item.event}")
|
||||
for chunk in streaming:
|
||||
print(f"Agent: {chunk.agent_role}")
|
||||
print(f"Task: {chunk.task_name}")
|
||||
print(f"Content: {chunk.content}")
|
||||
print(f"Type: {chunk.chunk_type}") # TEXT or TOOL_CALL
|
||||
```
|
||||
|
||||
### Accessing Streaming Properties
|
||||
|
||||
The stream session provides useful properties and methods:
|
||||
The `FlowStreamingOutput` object provides useful properties and methods:
|
||||
|
||||
```python Code
|
||||
streaming = flow.kickoff()
|
||||
|
||||
# Iterate and collect items
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Iterate and collect chunks
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# After iteration completes
|
||||
print(f"\nCompleted: {streaming.is_completed}")
|
||||
print(f"Total frames: {len(streaming.frames)}")
|
||||
print(f"Full text: {streaming.get_full_text()}")
|
||||
print(f"Total chunks: {len(streaming.chunks)}")
|
||||
print(f"Final result: {streaming.result}")
|
||||
```
|
||||
|
||||
@@ -113,9 +114,9 @@ async def stream_flow():
|
||||
# Start async streaming
|
||||
streaming = await flow.kickoff_async()
|
||||
|
||||
# Async iteration over stream items
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
# Async iteration over chunks
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Access final result
|
||||
result = streaming.result
|
||||
@@ -180,14 +181,13 @@ flow = MultiStepFlow()
|
||||
streaming = flow.kickoff()
|
||||
|
||||
current_step = ""
|
||||
for item in streaming:
|
||||
for chunk in streaming:
|
||||
# Track which flow step is executing
|
||||
step_name = item.event.get("method_name") or item.event.get("task_name")
|
||||
if step_name and step_name != current_step:
|
||||
current_step = step_name
|
||||
print(f"\n\n=== {step_name} ===\n")
|
||||
if chunk.task_name != current_step:
|
||||
current_step = chunk.task_name
|
||||
print(f"\n\n=== {chunk.task_name} ===\n")
|
||||
|
||||
print(item.content, end="", flush=True)
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal analysis: {result}")
|
||||
@@ -201,6 +201,7 @@ Here's a complete example showing how to build a progress dashboard with streami
|
||||
import asyncio
|
||||
from crewai.flow.flow import Flow, listen, start
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai.types.streaming import StreamChunkType
|
||||
|
||||
class ResearchPipeline(Flow):
|
||||
stream = True
|
||||
@@ -253,35 +254,33 @@ async def run_with_dashboard():
|
||||
|
||||
current_agent = ""
|
||||
current_task = ""
|
||||
frame_count = 0
|
||||
chunk_count = 0
|
||||
|
||||
async for item in streaming:
|
||||
frame_count += 1
|
||||
async for chunk in streaming:
|
||||
chunk_count += 1
|
||||
|
||||
# Display phase transitions
|
||||
task_name = item.event.get("task_name", "")
|
||||
agent_role = item.event.get("agent_role", "")
|
||||
if task_name and task_name != current_task:
|
||||
current_task = task_name
|
||||
current_agent = agent_role
|
||||
if chunk.task_name != current_task:
|
||||
current_task = chunk.task_name
|
||||
current_agent = chunk.agent_role
|
||||
print(f"\n\n📋 Phase: {current_task}")
|
||||
print(f"👤 Agent: {current_agent}")
|
||||
print("-" * 60)
|
||||
|
||||
# Display text output
|
||||
if item.content:
|
||||
print(item.content, end="", flush=True)
|
||||
if chunk.chunk_type == StreamChunkType.TEXT:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
# Display tool usage
|
||||
elif item.channel == "tools":
|
||||
print(f"\n🔧 Tool event: {item.type}")
|
||||
elif chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
|
||||
print(f"\n🔧 Tool: {chunk.tool_call.tool_name}")
|
||||
|
||||
# Show completion summary
|
||||
result = streaming.result
|
||||
print(f"\n\n{'='*60}")
|
||||
print("PIPELINE COMPLETE")
|
||||
print(f"{'='*60}")
|
||||
print(f"Total frames: {frame_count}")
|
||||
print(f"Total chunks: {chunk_count}")
|
||||
print(f"Final output length: {len(str(result))} characters")
|
||||
|
||||
asyncio.run(run_with_dashboard())
|
||||
@@ -354,8 +353,8 @@ class StatefulStreamingFlow(Flow[AnalysisState]):
|
||||
flow = StatefulStreamingFlow()
|
||||
streaming = flow.kickoff(inputs={"topic": "quantum computing"})
|
||||
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\n\nFinal state:")
|
||||
@@ -375,29 +374,29 @@ Flow streaming is particularly valuable for:
|
||||
- **Progress Tracking**: Show users which stage of the workflow is currently executing
|
||||
- **Live Dashboards**: Create monitoring interfaces for production flows
|
||||
|
||||
## Stream Frame Channels
|
||||
## Stream Chunk Types
|
||||
|
||||
Flow streaming yields `StreamFrame` items across several channels:
|
||||
Like crew streaming, flow chunks can be of different types:
|
||||
|
||||
### LLM Frames
|
||||
### TEXT Chunks
|
||||
|
||||
Standard text content from LLM responses:
|
||||
|
||||
```python Code
|
||||
for item in streaming:
|
||||
if item.channel == "llm" and item.content:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
if chunk.chunk_type == StreamChunkType.TEXT:
|
||||
print(chunk.content, end="", flush=True)
|
||||
```
|
||||
|
||||
### Tool Frames
|
||||
### TOOL_CALL Chunks
|
||||
|
||||
Information about tool calls within the flow:
|
||||
|
||||
```python Code
|
||||
for item in streaming:
|
||||
if item.channel == "tools":
|
||||
print(f"\nTool event: {item.type}")
|
||||
print(f"Payload: {item.event}")
|
||||
for chunk in streaming:
|
||||
if chunk.chunk_type == StreamChunkType.TOOL_CALL and chunk.tool_call:
|
||||
print(f"\nTool: {chunk.tool_call.tool_name}")
|
||||
print(f"Args: {chunk.tool_call.arguments}")
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
@@ -409,8 +408,8 @@ flow = ResearchFlow()
|
||||
streaming = flow.kickoff()
|
||||
|
||||
try:
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\nSuccess! Result: {result}")
|
||||
@@ -423,7 +422,7 @@ except Exception as e:
|
||||
|
||||
## Cancellation and Resource Cleanup
|
||||
|
||||
The stream session supports graceful cancellation so that in-flight work stops promptly when the consumer disconnects.
|
||||
`FlowStreamingOutput` supports graceful cancellation so that in-flight work stops promptly when the consumer disconnects.
|
||||
|
||||
### Async Context Manager
|
||||
|
||||
@@ -431,8 +430,8 @@ The stream session supports graceful cancellation so that in-flight work stops p
|
||||
streaming = await flow.kickoff_async()
|
||||
|
||||
async with streaming:
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
```
|
||||
|
||||
### Explicit Cancellation
|
||||
@@ -440,8 +439,8 @@ async with streaming:
|
||||
```python Code
|
||||
streaming = await flow.kickoff_async()
|
||||
try:
|
||||
async for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
async for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
finally:
|
||||
await streaming.aclose() # async
|
||||
# streaming.close() # sync equivalent
|
||||
@@ -452,10 +451,10 @@ After cancellation, `streaming.is_cancelled` and `streaming.is_completed` are bo
|
||||
## Important Notes
|
||||
|
||||
- Streaming automatically enables LLM streaming for any crews used within the flow
|
||||
- You must iterate through all stream items before accessing the `.result` property
|
||||
- You must iterate through all chunks before accessing the `.result` property
|
||||
- Streaming works with both structured and unstructured flow state
|
||||
- Flow streaming captures output from all crews and LLM calls in the flow
|
||||
- Each frame includes structured event context such as channel, type, namespace, and payload
|
||||
- Each chunk includes context about which agent and task generated it
|
||||
- Streaming adds minimal overhead to flow execution
|
||||
|
||||
## Combining with Flow Visualization
|
||||
@@ -469,11 +468,11 @@ flow.plot("research_flow") # Creates HTML visualization
|
||||
|
||||
# Run with streaming
|
||||
streaming = flow.kickoff()
|
||||
for item in streaming:
|
||||
print(item.content, end="", flush=True)
|
||||
for chunk in streaming:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = streaming.result
|
||||
print(f"\nFlow complete! View structure at: research_flow.html")
|
||||
```
|
||||
|
||||
By leveraging flow streaming, you can build sophisticated, responsive applications that provide users with real-time visibility into complex multi-stage workflows, making your AI automations more transparent and engaging.
|
||||
By leveraging flow streaming, you can build sophisticated, responsive applications that provide users with real-time visibility into complex multi-stage workflows, making your AI automations more transparent and engaging.
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
title: Streaming Runtime Contract
|
||||
description: Stream ordered runtime frames from Flows, direct LLM calls, and conversational turns.
|
||||
icon: tower-broadcast
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
CrewAI exposes a frame-based streaming contract for runtimes that need more than plain text chunks. The contract emits ordered `StreamFrame` objects for Flow lifecycle events, direct LLM tokens, tool activity, conversation messages, and custom events.
|
||||
|
||||
Use this API when you are building a UI, service bridge, terminal app, or deployment runtime that needs a stable stream of structured events while a Flow, chat turn, or direct LLM call is running.
|
||||
|
||||
## StreamFrame
|
||||
|
||||
Every frame has the same envelope:
|
||||
|
||||
```python
|
||||
from crewai.types.streaming import StreamFrame
|
||||
|
||||
frame.id # unique frame id
|
||||
frame.seq # execution-local order, when available
|
||||
frame.type # source event type, such as "flow_started"
|
||||
frame.channel # "llm", "flow", "tools", "messages", "lifecycle", or "custom"
|
||||
frame.namespace # source/runtime namespace
|
||||
frame.timestamp # event timestamp
|
||||
frame.parent_id # parent event id, when available
|
||||
frame.previous_id # previous event id, when available
|
||||
frame.data # event payload
|
||||
frame.event # alias for frame.data
|
||||
frame.content # printable text for token-like frames, otherwise ""
|
||||
```
|
||||
|
||||
The `channel` field is the fastest way to route frames in consumers:
|
||||
|
||||
| Channel | Contains |
|
||||
|---------|----------|
|
||||
| `llm` | Token and thinking chunks from LLM streaming events |
|
||||
| `flow` | Flow lifecycle, method execution, routing, and pause/resume events |
|
||||
| `tools` | Tool usage events |
|
||||
| `messages` | Conversation transcript events |
|
||||
| `lifecycle` | Runtime lifecycle events that are not specific to another channel |
|
||||
| `custom` | Events that do not map to a built-in channel |
|
||||
|
||||
`frame.type` preserves the source event type, so consumers can handle specific events inside a channel.
|
||||
|
||||
## Stream a Flow
|
||||
|
||||
Set `stream=True` on a Flow to make `kickoff()` return a stream session:
|
||||
|
||||
```python
|
||||
from crewai.flow import Flow, start
|
||||
|
||||
|
||||
class ReportFlow(Flow):
|
||||
@start()
|
||||
def generate(self):
|
||||
return "done"
|
||||
|
||||
|
||||
flow = ReportFlow(stream=True)
|
||||
stream = flow.kickoff()
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
if chunk.type == "tool_usage_started":
|
||||
print(chunk.event["tool_name"])
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
You must consume the stream before reading `stream.result`. Accessing the result early raises a `RuntimeError` so consumers do not accidentally treat a partial run as complete.
|
||||
|
||||
You can also call `flow.stream_events(...)` directly when you want streaming for a single invocation without setting `stream=True` on the Flow instance.
|
||||
|
||||
## Filter by Channel
|
||||
|
||||
`StreamSession` exposes channel projections that preserve global frame order within the selected channel:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Available projections are:
|
||||
|
||||
| Projection | Frames |
|
||||
|------------|--------|
|
||||
| `stream.events` | All frames |
|
||||
| `stream.llm` | LLM frames |
|
||||
| `stream.messages` | Conversation message frames |
|
||||
| `stream.flow` | Flow frames |
|
||||
| `stream.tools` | Tool frames |
|
||||
| `stream.interleave([...])` | A selected set of channels |
|
||||
|
||||
Use `stream.interleave(["flow", "llm", "messages"])` when a consumer wants only some channels but still needs their relative order.
|
||||
|
||||
## Async Streaming
|
||||
|
||||
Use `astream()` for async consumers:
|
||||
|
||||
```python
|
||||
flow = ReportFlow()
|
||||
stream = flow.astream()
|
||||
|
||||
async with stream:
|
||||
async for chunk in stream.events:
|
||||
print(chunk.channel, chunk.type, chunk.content)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
The async session has the same projections as the sync session.
|
||||
|
||||
## Stream a Direct LLM Call
|
||||
|
||||
`llm.call(...)` still returns the final assembled result. Use `llm.stream_events(...)` when you want to iterate over chunks as they arrive while keeping the structured event payload:
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
stream = llm.stream_events(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Explain CrewAI streaming in two short sentences.",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`llm.stream_events(...)` temporarily enables streaming for the wrapped call and restores the LLM's previous `stream` setting afterward. Provider integrations continue to emit the underlying LLM stream events; this helper provides a common iterator API over those events for every LLM provider.
|
||||
|
||||
## Conversational Turns
|
||||
|
||||
Conversational Flows can stream one user turn with `stream_turn()`:
|
||||
|
||||
```python
|
||||
from crewai import Flow
|
||||
from crewai.experimental.conversational import ConversationConfig, ConversationState
|
||||
|
||||
|
||||
@ConversationConfig(llm="gpt-4o-mini", defer_trace_finalization=True)
|
||||
class ChatFlow(Flow[ConversationState]):
|
||||
conversational = True
|
||||
|
||||
|
||||
flow = ChatFlow()
|
||||
stream = flow.stream_turn("What can you help me with?", session_id="session-1")
|
||||
|
||||
with stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.type == "llm_stream_chunk":
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
reply = stream.result
|
||||
```
|
||||
|
||||
During `stream_turn()`, the built-in conversational answer path enables LLM token streaming for that turn and restores the LLM's previous `stream` setting afterward. Custom route handlers that create their own agents or LLM instances should configure those LLMs for streaming if they need token-level output.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Use the session as a context manager when possible. If a client disconnects before the stream is exhausted, close the session explicitly:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
try:
|
||||
for frame in stream.events:
|
||||
print(frame.type)
|
||||
finally:
|
||||
if not stream.is_exhausted:
|
||||
stream.close()
|
||||
```
|
||||
|
||||
For async streams, use `await stream.aclose()`.
|
||||
|
||||
## Legacy Chunk Streaming
|
||||
|
||||
Crew streaming with `stream=True` still returns the chunk-oriented `CrewStreamingOutput` API described in [Streaming Crew Execution](/en/learn/streaming-crew-execution). Direct `llm.call(...)` still returns the final LLM result. The frame contract is intended for runtimes that need a stable event envelope across Flows, direct LLM calls, conversational turns, tools, and messages.
|
||||
@@ -4,57 +4,53 @@ description: Learn how to use tool call hooks to intercept, modify, and control
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
Tool Call Hooks provide fine-grained control over tool execution during agent
|
||||
operations. These hooks allow you to intercept tool calls, modify inputs,
|
||||
transform outputs, implement safety checks, and add comprehensive logging or
|
||||
monitoring.
|
||||
Tool Call Hooks provide fine-grained control over tool execution during agent operations. These hooks allow you to intercept tool calls, modify inputs, transform outputs, implement safety checks, and add comprehensive logging or monitoring.
|
||||
|
||||
## Overview
|
||||
|
||||
Tool hooks are executed at two interception points:
|
||||
Tool hooks are executed at two critical points:
|
||||
- **Before Tool Call**: Modify inputs, validate parameters, or block execution
|
||||
- **After Tool Call**: Transform results, sanitize outputs, or log execution details
|
||||
|
||||
| Point | When | Hook receives |
|
||||
|-------|------|---------------|
|
||||
| `PRE_TOOL_CALL` | Before every tool execution | `ToolCallHookContext` |
|
||||
| `POST_TOOL_CALL` | After every tool execution | `ToolCallHookContext` (with results set) |
|
||||
## Hook Types
|
||||
|
||||
Write them with the [`@on` decorator](/edge/en/learn/execution-hooks). The
|
||||
[legacy `@before_tool_call` / `@after_tool_call` decorators](#legacy-decorators)
|
||||
keep working unchanged — both styles register on the same engine and run in one
|
||||
ordered chain.
|
||||
### Before Tool Call Hooks
|
||||
|
||||
## Hook Signature
|
||||
Executed before every tool execution, these hooks can:
|
||||
- Inspect and modify tool inputs
|
||||
- Block tool execution based on conditions
|
||||
- Implement approval gates for dangerous operations
|
||||
- Validate parameters
|
||||
- Log tool invocations
|
||||
|
||||
**Signature:**
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint, ToolCallHookContext
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def before_hook(ctx: ToolCallHookContext) -> None:
|
||||
# Mutate ctx.tool_input in place, or
|
||||
# raise HookAborted(reason, source) to block the call
|
||||
...
|
||||
|
||||
@on(InterceptionPoint.POST_TOOL_CALL)
|
||||
def after_hook(ctx: ToolCallHookContext) -> str | None:
|
||||
# Return a string to replace ctx.tool_result
|
||||
# Return None to keep the original result
|
||||
def before_hook(context: ToolCallHookContext) -> bool | None:
|
||||
# Return False to block execution
|
||||
# Return True or None to allow execution
|
||||
...
|
||||
```
|
||||
|
||||
Unlike the boundary and step points, the tool-call points pass the rich
|
||||
`ToolCallHookContext` directly as the hook argument (there is no separate
|
||||
`ctx.payload`): mutate `ctx.tool_input` in place before the call, and return a
|
||||
string to replace the result after it.
|
||||
### After Tool Call Hooks
|
||||
|
||||
When a call is blocked, the tool does not run and the agent receives
|
||||
`"Tool execution blocked by hook. Tool: <name>"` as the result — the run
|
||||
continues. `POST_TOOL_CALL` hooks still fire on blocked calls, so monitoring
|
||||
hooks see every attempt.
|
||||
Executed after every tool execution, these hooks can:
|
||||
- Modify or sanitize tool results
|
||||
- Add metadata or formatting
|
||||
- Log execution results
|
||||
- Implement result validation
|
||||
- Transform output formats
|
||||
|
||||
**Signature:**
|
||||
```python
|
||||
def after_hook(context: ToolCallHookContext) -> str | None:
|
||||
# Return modified result string
|
||||
# Return None to keep original result
|
||||
...
|
||||
```
|
||||
|
||||
## Tool Hook Context
|
||||
|
||||
The `ToolCallHookContext` object provides comprehensive access to tool
|
||||
execution state:
|
||||
The `ToolCallHookContext` object provides comprehensive access to tool execution state:
|
||||
|
||||
```python
|
||||
class ToolCallHookContext:
|
||||
@@ -64,18 +60,11 @@ class ToolCallHookContext:
|
||||
agent: Agent | BaseAgent | None # Agent executing the tool
|
||||
task: Task | None # Current task
|
||||
crew: Crew | None # Crew instance
|
||||
tool_result: str | None # Agent-facing result string (POST_TOOL_CALL only)
|
||||
raw_tool_result: Any | None # Raw Python result (POST_TOOL_CALL only)
|
||||
tool_result: str | None # Agent-facing result string (after hooks only)
|
||||
raw_tool_result: Any | None # Raw Python result (after hooks only)
|
||||
```
|
||||
|
||||
For typed tool outputs, `tool_result` is the string the agent sees. By default,
|
||||
this is JSON. If the tool uses custom formatting, it can be Markdown or another
|
||||
string. Use `raw_tool_result` when your hook needs the typed object or
|
||||
dictionary; it is not affected by result replacement.
|
||||
|
||||
The context also exposes `request_human_input(prompt, default_message)`, which
|
||||
pauses live console updates and collects input from the terminal — useful for
|
||||
approval gates.
|
||||
For typed tool outputs, `tool_result` is the string the agent sees. By default, this is JSON. If the tool uses custom formatting, it can be Markdown or another string. Use `raw_tool_result` when your hook needs the typed object or dictionary.
|
||||
|
||||
### Modifying Tool Inputs
|
||||
|
||||
@@ -83,58 +72,83 @@ approval gates.
|
||||
|
||||
```python
|
||||
# ✅ Correct - modify in-place
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def sanitize_input(ctx: ToolCallHookContext) -> None:
|
||||
ctx.tool_input['query'] = ctx.tool_input['query'].lower()
|
||||
def sanitize_input(context: ToolCallHookContext) -> None:
|
||||
context.tool_input['query'] = context.tool_input['query'].lower()
|
||||
|
||||
# ❌ Wrong - replaces dict reference; the tool never sees it
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def wrong_approach(ctx: ToolCallHookContext) -> None:
|
||||
ctx.tool_input = {'query': 'new query'}
|
||||
# ❌ Wrong - replaces dict reference
|
||||
def wrong_approach(context: ToolCallHookContext) -> None:
|
||||
context.tool_input = {'query': 'new query'}
|
||||
```
|
||||
|
||||
## Registration Methods
|
||||
|
||||
### 1. Global Hooks
|
||||
### 1. Global Hook Registration
|
||||
|
||||
Apply to all tool calls across all crews. Use `tools=` / `agents=` filters to
|
||||
scope a hook:
|
||||
Register hooks that apply to all tool calls across all crews:
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, HookAborted, InterceptionPoint
|
||||
from crewai.hooks import register_before_tool_call_hook, register_after_tool_call_hook
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def log_tool_call(ctx):
|
||||
print(f"Tool: {ctx.tool_name}, input: {ctx.tool_input}")
|
||||
def log_tool_call(context):
|
||||
print(f"Tool: {context.tool_name}")
|
||||
print(f"Input: {context.tool_input}")
|
||||
return None # Allow execution
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["delete_file", "drop_table"])
|
||||
def block_destructive(ctx):
|
||||
raise HookAborted(reason=f"{ctx.tool_name} is not allowed", source="safety-policy")
|
||||
|
||||
@on(InterceptionPoint.POST_TOOL_CALL, tools=["web_search"], agents=["Researcher"])
|
||||
def log_search_results(ctx):
|
||||
print(f"search returned {len(ctx.tool_result or '')} chars")
|
||||
register_before_tool_call_hook(log_tool_call)
|
||||
```
|
||||
|
||||
### 2. Crew-Scoped Hooks
|
||||
### 2. Decorator-Based Registration
|
||||
|
||||
Apply the same decorator to a method inside a `@CrewBase` class to scope the
|
||||
hook to that crew only:
|
||||
Use decorators for cleaner syntax:
|
||||
|
||||
```python
|
||||
from crewai.hooks import on, InterceptionPoint
|
||||
from crewai.hooks import before_tool_call, after_tool_call
|
||||
|
||||
@before_tool_call
|
||||
def block_dangerous_tools(context):
|
||||
dangerous_tools = ['delete_database', 'drop_table', 'rm_rf']
|
||||
if context.tool_name in dangerous_tools:
|
||||
print(f"⛔ Blocked dangerous tool: {context.tool_name}")
|
||||
return False # Block execution
|
||||
return None
|
||||
|
||||
@after_tool_call
|
||||
def sanitize_results(context):
|
||||
if context.tool_result and "password" in context.tool_result.lower():
|
||||
return context.tool_result.replace("password", "[REDACTED]")
|
||||
return None
|
||||
```
|
||||
|
||||
### 3. Crew-Scoped Hooks
|
||||
|
||||
Register hooks for a specific crew instance:
|
||||
|
||||
```python
|
||||
@CrewBase
|
||||
class MyProjCrew:
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def validate_tool_inputs(self, ctx):
|
||||
@before_tool_call_crew
|
||||
def validate_tool_inputs(self, context):
|
||||
# Only applies to this crew
|
||||
if ctx.tool_name == "web_search" and not ctx.tool_input.get("query"):
|
||||
raise HookAborted(reason="empty search query", source="input-validation")
|
||||
if context.tool_name == "web_search":
|
||||
if not context.tool_input.get('query'):
|
||||
print("❌ Invalid search query")
|
||||
return False
|
||||
return None
|
||||
|
||||
@after_tool_call_crew
|
||||
def log_tool_results(self, context):
|
||||
# Crew-specific tool logging
|
||||
print(f"✅ {context.tool_name} completed")
|
||||
return None
|
||||
|
||||
@crew
|
||||
def crew(self) -> Crew:
|
||||
return Crew(agents=self.agents, tasks=self.tasks, process=Process.sequential)
|
||||
return Crew(
|
||||
agents=self.agents,
|
||||
tasks=self.tasks,
|
||||
process=Process.sequential,
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
## Common Use Cases
|
||||
@@ -142,63 +156,112 @@ class MyProjCrew:
|
||||
### 1. Safety Guardrails
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def safety_check(ctx: ToolCallHookContext) -> None:
|
||||
destructive = {'delete_file', 'drop_table', 'remove_user', 'system_shutdown'}
|
||||
if ctx.tool_name in destructive:
|
||||
raise HookAborted(reason=f"{ctx.tool_name} is destructive", source="safety-policy")
|
||||
@before_tool_call
|
||||
def safety_check(context: ToolCallHookContext) -> bool | None:
|
||||
# Block tools that could cause harm
|
||||
destructive_tools = [
|
||||
'delete_file',
|
||||
'drop_table',
|
||||
'remove_user',
|
||||
'system_shutdown'
|
||||
]
|
||||
|
||||
if context.tool_name in destructive_tools:
|
||||
print(f"🛑 Blocked destructive tool: {context.tool_name}")
|
||||
return False
|
||||
|
||||
# Warn on sensitive operations
|
||||
sensitive_tools = ['send_email', 'post_to_social_media', 'charge_payment']
|
||||
if context.tool_name in sensitive_tools:
|
||||
print(f"⚠️ Executing sensitive tool: {context.tool_name}")
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### 2. Human Approval Gate
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["send_email", "make_purchase", "delete_file"])
|
||||
def require_approval(ctx: ToolCallHookContext) -> None:
|
||||
response = ctx.request_human_input(
|
||||
prompt=f"Approve {ctx.tool_name}?",
|
||||
default_message=f"Input: {ctx.tool_input}\nType 'yes' to approve:",
|
||||
)
|
||||
if response.lower() != 'yes':
|
||||
raise HookAborted(reason="denied by operator", source="approval-gate")
|
||||
@before_tool_call
|
||||
def require_approval_for_actions(context: ToolCallHookContext) -> bool | None:
|
||||
approval_required = [
|
||||
'send_email',
|
||||
'make_purchase',
|
||||
'delete_file',
|
||||
'post_message'
|
||||
]
|
||||
|
||||
if context.tool_name in approval_required:
|
||||
response = context.request_human_input(
|
||||
prompt=f"Approve {context.tool_name}?",
|
||||
default_message=f"Input: {context.tool_input}\nType 'yes' to approve:"
|
||||
)
|
||||
|
||||
if response.lower() != 'yes':
|
||||
print(f"❌ Tool execution denied: {context.tool_name}")
|
||||
return False
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### 3. Input Validation and Sanitization
|
||||
|
||||
```python
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["web_search"])
|
||||
def validate_query(ctx: ToolCallHookContext) -> None:
|
||||
query = ctx.tool_input.get('query', '')
|
||||
if len(query) < 3:
|
||||
raise HookAborted(reason="search query too short", source="input-validation")
|
||||
ctx.tool_input['query'] = query.strip().lower()
|
||||
@before_tool_call
|
||||
def validate_and_sanitize_inputs(context: ToolCallHookContext) -> bool | None:
|
||||
# Validate search queries
|
||||
if context.tool_name == 'web_search':
|
||||
query = context.tool_input.get('query', '')
|
||||
if len(query) < 3:
|
||||
print("❌ Search query too short")
|
||||
return False
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL, tools=["read_file"])
|
||||
def validate_path(ctx: ToolCallHookContext) -> None:
|
||||
path = ctx.tool_input.get('path', '')
|
||||
if '..' in path or path.startswith('/'):
|
||||
raise HookAborted(reason="invalid file path", source="input-validation")
|
||||
# Sanitize query
|
||||
context.tool_input['query'] = query.strip().lower()
|
||||
|
||||
# Validate file paths
|
||||
if context.tool_name == 'read_file':
|
||||
path = context.tool_input.get('path', '')
|
||||
if '..' in path or path.startswith('/'):
|
||||
print("❌ Invalid file path")
|
||||
return False
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### 4. Result Sanitization
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
@on(InterceptionPoint.POST_TOOL_CALL)
|
||||
def sanitize_sensitive_data(ctx: ToolCallHookContext) -> str | None:
|
||||
if not ctx.tool_result:
|
||||
@after_tool_call
|
||||
def sanitize_sensitive_data(context: ToolCallHookContext) -> str | None:
|
||||
if not context.tool_result:
|
||||
return None
|
||||
|
||||
import re
|
||||
result = context.tool_result
|
||||
|
||||
# Remove API keys
|
||||
result = re.sub(
|
||||
r'(api[_-]?key|token)["\']?\s*[:=]\s*["\']?[\w-]+',
|
||||
r'\1: [REDACTED]',
|
||||
ctx.tool_result,
|
||||
flags=re.IGNORECASE,
|
||||
result,
|
||||
flags=re.IGNORECASE
|
||||
)
|
||||
return re.sub(
|
||||
|
||||
# Remove email addresses
|
||||
result = re.sub(
|
||||
r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
|
||||
'[EMAIL-REDACTED]',
|
||||
result,
|
||||
result
|
||||
)
|
||||
|
||||
# Remove credit card numbers
|
||||
result = re.sub(
|
||||
r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b',
|
||||
'[CARD-REDACTED]',
|
||||
result
|
||||
)
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
### 5. Tool Usage Analytics
|
||||
@@ -207,17 +270,32 @@ def sanitize_sensitive_data(ctx: ToolCallHookContext) -> str | None:
|
||||
import time
|
||||
from collections import defaultdict
|
||||
|
||||
tool_stats = defaultdict(lambda: {'count': 0, 'total_time': 0})
|
||||
tool_stats = defaultdict(lambda: {'count': 0, 'total_time': 0, 'failures': 0})
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def start_timer(ctx: ToolCallHookContext) -> None:
|
||||
ctx.tool_input['_start_time'] = time.time()
|
||||
@before_tool_call
|
||||
def start_timer(context: ToolCallHookContext) -> None:
|
||||
context.tool_input['_start_time'] = time.time()
|
||||
return None
|
||||
|
||||
@on(InterceptionPoint.POST_TOOL_CALL)
|
||||
def track_tool_usage(ctx: ToolCallHookContext) -> None:
|
||||
start_time = ctx.tool_input.pop('_start_time', time.time())
|
||||
tool_stats[ctx.tool_name]['count'] += 1
|
||||
tool_stats[ctx.tool_name]['total_time'] += time.time() - start_time
|
||||
@after_tool_call
|
||||
def track_tool_usage(context: ToolCallHookContext) -> None:
|
||||
start_time = context.tool_input.get('_start_time', time.time())
|
||||
duration = time.time() - start_time
|
||||
|
||||
tool_stats[context.tool_name]['count'] += 1
|
||||
tool_stats[context.tool_name]['total_time'] += duration
|
||||
|
||||
if not context.tool_result or 'error' in context.tool_result.lower():
|
||||
tool_stats[context.tool_name]['failures'] += 1
|
||||
|
||||
print(f"""
|
||||
📊 Tool Stats for {context.tool_name}:
|
||||
- Executions: {tool_stats[context.tool_name]['count']}
|
||||
- Avg Time: {tool_stats[context.tool_name]['total_time'] / tool_stats[context.tool_name]['count']:.2f}s
|
||||
- Failures: {tool_stats[context.tool_name]['failures']}
|
||||
""")
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### 6. Rate Limiting
|
||||
@@ -228,113 +306,298 @@ from datetime import datetime, timedelta
|
||||
|
||||
tool_call_history = defaultdict(list)
|
||||
|
||||
@on(InterceptionPoint.PRE_TOOL_CALL)
|
||||
def rate_limit_tools(ctx: ToolCallHookContext) -> None:
|
||||
@before_tool_call
|
||||
def rate_limit_tools(context: ToolCallHookContext) -> bool | None:
|
||||
tool_name = context.tool_name
|
||||
now = datetime.now()
|
||||
history = tool_call_history[ctx.tool_name]
|
||||
history[:] = [t for t in history if now - t < timedelta(minutes=1)]
|
||||
if len(history) >= 10:
|
||||
raise HookAborted(reason=f"rate limit exceeded for {ctx.tool_name}",
|
||||
source="rate-limiter")
|
||||
history.append(now)
|
||||
|
||||
# Clean old entries (older than 1 minute)
|
||||
tool_call_history[tool_name] = [
|
||||
call_time for call_time in tool_call_history[tool_name]
|
||||
if now - call_time < timedelta(minutes=1)
|
||||
]
|
||||
|
||||
# Check rate limit (max 10 calls per minute)
|
||||
if len(tool_call_history[tool_name]) >= 10:
|
||||
print(f"🚫 Rate limit exceeded for {tool_name}")
|
||||
return False
|
||||
|
||||
# Record this call
|
||||
tool_call_history[tool_name].append(now)
|
||||
return None
|
||||
```
|
||||
|
||||
### 7. Caching Tool Results
|
||||
|
||||
```python
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
tool_cache = {}
|
||||
|
||||
def cache_key(tool_name: str, tool_input: dict) -> str:
|
||||
"""Generate cache key from tool name and input."""
|
||||
input_str = json.dumps(tool_input, sort_keys=True)
|
||||
return hashlib.md5(f"{tool_name}:{input_str}".encode()).hexdigest()
|
||||
|
||||
@before_tool_call
|
||||
def check_cache(context: ToolCallHookContext) -> bool | None:
|
||||
key = cache_key(context.tool_name, context.tool_input)
|
||||
if key in tool_cache:
|
||||
print(f"💾 Cache hit for {context.tool_name}")
|
||||
# Note: Can't return cached result from before hook
|
||||
# Would need to implement this differently
|
||||
return None
|
||||
|
||||
@after_tool_call
|
||||
def cache_result(context: ToolCallHookContext) -> None:
|
||||
if context.tool_result:
|
||||
key = cache_key(context.tool_name, context.tool_input)
|
||||
tool_cache[key] = context.tool_result
|
||||
print(f"💾 Cached result for {context.tool_name}")
|
||||
return None
|
||||
```
|
||||
|
||||
### 8. Debug Logging
|
||||
|
||||
```python
|
||||
@before_tool_call
|
||||
def debug_tool_call(context: ToolCallHookContext) -> None:
|
||||
print(f"""
|
||||
🔍 Tool Call Debug:
|
||||
- Tool: {context.tool_name}
|
||||
- Agent: {context.agent.role if context.agent else 'Unknown'}
|
||||
- Task: {context.task.description[:50] if context.task else 'Unknown'}...
|
||||
- Input: {context.tool_input}
|
||||
""")
|
||||
return None
|
||||
|
||||
@after_tool_call
|
||||
def debug_tool_result(context: ToolCallHookContext) -> None:
|
||||
if context.tool_result:
|
||||
result_preview = context.tool_result[:200]
|
||||
print(f"✅ Result Preview: {result_preview}...")
|
||||
else:
|
||||
print("⚠️ No result returned")
|
||||
return None
|
||||
```
|
||||
|
||||
## Hook Management
|
||||
|
||||
### Unregistering Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
InterceptionPoint,
|
||||
clear_all_hooks,
|
||||
clear_hooks,
|
||||
get_hooks,
|
||||
unregister_hook,
|
||||
unregister_before_tool_call_hook,
|
||||
unregister_after_tool_call_hook
|
||||
)
|
||||
|
||||
# Unregister a specific hook
|
||||
unregister_hook(InterceptionPoint.PRE_TOOL_CALL, my_hook)
|
||||
# Unregister specific hook
|
||||
def my_hook(context):
|
||||
...
|
||||
|
||||
# Clear one point, or everything (e.g. between tests)
|
||||
clear_hooks(InterceptionPoint.POST_TOOL_CALL)
|
||||
clear_all_hooks()
|
||||
|
||||
# Inspect what's registered
|
||||
print(len(get_hooks(InterceptionPoint.PRE_TOOL_CALL)))
|
||||
register_before_tool_call_hook(my_hook)
|
||||
# Later...
|
||||
success = unregister_before_tool_call_hook(my_hook)
|
||||
print(f"Unregistered: {success}")
|
||||
```
|
||||
|
||||
The legacy management API (`register_before_tool_call_hook`,
|
||||
`unregister_before_tool_call_hook`, `clear_before_tool_call_hooks`,
|
||||
`clear_all_tool_call_hooks`, `get_before_tool_call_hooks`, and their `after_`
|
||||
counterparts) operates on the same underlying registries, so either API can
|
||||
manage hooks registered by the other.
|
||||
|
||||
## Legacy Decorators
|
||||
|
||||
The original per-point decorators keep working unchanged and run in the same
|
||||
registration-order chain as `@on` hooks:
|
||||
### Clearing Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import before_tool_call, after_tool_call
|
||||
from crewai.hooks import (
|
||||
clear_before_tool_call_hooks,
|
||||
clear_after_tool_call_hooks,
|
||||
clear_all_tool_call_hooks
|
||||
)
|
||||
|
||||
# Clear specific hook type
|
||||
count = clear_before_tool_call_hooks()
|
||||
print(f"Cleared {count} before hooks")
|
||||
|
||||
# Clear all tool hooks
|
||||
before_count, after_count = clear_all_tool_call_hooks()
|
||||
print(f"Cleared {before_count} before and {after_count} after hooks")
|
||||
```
|
||||
|
||||
### Listing Registered Hooks
|
||||
|
||||
```python
|
||||
from crewai.hooks import (
|
||||
get_before_tool_call_hooks,
|
||||
get_after_tool_call_hooks
|
||||
)
|
||||
|
||||
# Get current hooks
|
||||
before_hooks = get_before_tool_call_hooks()
|
||||
after_hooks = get_after_tool_call_hooks()
|
||||
|
||||
print(f"Registered: {len(before_hooks)} before, {len(after_hooks)} after")
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Conditional Hook Execution
|
||||
|
||||
```python
|
||||
@before_tool_call
|
||||
def block_dangerous_tools(context):
|
||||
if context.tool_name in ('delete_database', 'drop_table'):
|
||||
return False # Block execution
|
||||
return None
|
||||
def conditional_blocking(context: ToolCallHookContext) -> bool | None:
|
||||
# Only block for specific agents
|
||||
if context.agent and context.agent.role == "junior_agent":
|
||||
if context.tool_name in ['delete_file', 'send_email']:
|
||||
print(f"❌ Junior agents cannot use {context.tool_name}")
|
||||
return False
|
||||
|
||||
# Only block during specific tasks
|
||||
if context.task and "sensitive" in context.task.description.lower():
|
||||
if context.tool_name == 'web_search':
|
||||
print("❌ Web search blocked for sensitive tasks")
|
||||
return False
|
||||
|
||||
@after_tool_call(tools=["web_search"])
|
||||
def sanitize_results(context):
|
||||
if context.tool_result and "password" in context.tool_result.lower():
|
||||
return context.tool_result.replace("password", "[REDACTED]")
|
||||
return None
|
||||
```
|
||||
|
||||
Differences from `@on`:
|
||||
### Context-Aware Input Modification
|
||||
|
||||
- **Blocking** is `return False` from a before hook — equivalent to raising
|
||||
`HookAborted`, but without a custom reason or source for telemetry. The agent
|
||||
sees the same `"Tool execution blocked by hook"` message.
|
||||
- **Signatures** are point-specific: before hooks return `bool | None`, after
|
||||
hooks return `str | None`. The context object is the same
|
||||
`ToolCallHookContext`.
|
||||
- **Filters and crew-scoping** work the same way:
|
||||
`@before_tool_call(tools=[...], agents=[...])`, and applying the decorator to
|
||||
a `@CrewBase` method scopes it to that crew.
|
||||
```python
|
||||
@before_tool_call
|
||||
def enhance_tool_inputs(context: ToolCallHookContext) -> None:
|
||||
# Add context based on agent role
|
||||
if context.agent and context.agent.role == "researcher":
|
||||
if context.tool_name == 'web_search':
|
||||
# Add domain restrictions for researchers
|
||||
context.tool_input['domains'] = ['edu', 'gov', 'org']
|
||||
|
||||
Prefer `@on` for new code; keep the legacy style where it is already in use —
|
||||
there is no behavioral penalty.
|
||||
# Add context based on task
|
||||
if context.task and "urgent" in context.task.description.lower():
|
||||
if context.tool_name == 'send_email':
|
||||
context.tool_input['priority'] = 'high'
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
### Tool Chain Monitoring
|
||||
|
||||
```python
|
||||
tool_call_chain = []
|
||||
|
||||
@before_tool_call
|
||||
def track_tool_chain(context: ToolCallHookContext) -> None:
|
||||
tool_call_chain.append({
|
||||
'tool': context.tool_name,
|
||||
'timestamp': time.time(),
|
||||
'agent': context.agent.role if context.agent else 'Unknown'
|
||||
})
|
||||
|
||||
# Detect potential infinite loops
|
||||
recent_calls = tool_call_chain[-5:]
|
||||
if len(recent_calls) == 5 and all(c['tool'] == context.tool_name for c in recent_calls):
|
||||
print(f"⚠️ Warning: {context.tool_name} called 5 times in a row")
|
||||
|
||||
return None
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep hooks focused and fast** — they run on every tool call
|
||||
2. **Modify in-place** — always mutate `ctx.tool_input`, never replace the dict
|
||||
3. **Prefer filters over conditionals** — `tools=` / `agents=` keep hook bodies small
|
||||
4. **Abort loudly** — raise `HookAborted` with a meaningful reason and source;
|
||||
any other exception is swallowed (fail-open)
|
||||
5. **Use type hints** — annotate with `ToolCallHookContext` for IDE support
|
||||
6. **Clear hooks in tests** — call `clear_all_hooks()` between test runs
|
||||
1. **Keep Hooks Focused**: Each hook should have a single responsibility
|
||||
2. **Avoid Heavy Computation**: Hooks execute on every tool call
|
||||
3. **Handle Errors Gracefully**: Use try-except to prevent hook failures
|
||||
4. **Use Type Hints**: Leverage `ToolCallHookContext` for better IDE support
|
||||
5. **Document Blocking Conditions**: Make it clear when/why tools are blocked
|
||||
6. **Test Hooks Independently**: Unit test hooks before using in production
|
||||
7. **Clear Hooks in Tests**: Use `clear_all_tool_call_hooks()` between test runs
|
||||
8. **Modify In-Place**: Always modify `context.tool_input` in-place, never replace
|
||||
9. **Log Important Decisions**: Especially when blocking tool execution
|
||||
10. **Consider Performance**: Cache expensive validations when possible
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
@before_tool_call
|
||||
def safe_validation(context: ToolCallHookContext) -> bool | None:
|
||||
try:
|
||||
# Your validation logic
|
||||
if not validate_input(context.tool_input):
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"⚠️ Hook error: {e}")
|
||||
# Decide: allow or block on error
|
||||
return None # Allow execution despite error
|
||||
```
|
||||
|
||||
## Type Safety
|
||||
|
||||
```python
|
||||
from crewai.hooks import ToolCallHookContext, BeforeToolCallHookType, AfterToolCallHookType
|
||||
|
||||
# Explicit type annotations
|
||||
def my_before_hook(context: ToolCallHookContext) -> bool | None:
|
||||
return None
|
||||
|
||||
def my_after_hook(context: ToolCallHookContext) -> str | None:
|
||||
return None
|
||||
|
||||
# Type-safe registration
|
||||
register_before_tool_call_hook(my_before_hook)
|
||||
register_after_tool_call_hook(my_after_hook)
|
||||
```
|
||||
|
||||
## Integration with Existing Tools
|
||||
|
||||
### Wrapping Existing Validation
|
||||
|
||||
```python
|
||||
def existing_validator(tool_name: str, inputs: dict) -> bool:
|
||||
"""Your existing validation function."""
|
||||
# Your validation logic
|
||||
return True
|
||||
|
||||
@before_tool_call
|
||||
def integrate_validator(context: ToolCallHookContext) -> bool | None:
|
||||
if not existing_validator(context.tool_name, context.tool_input):
|
||||
print(f"❌ Validation failed for {context.tool_name}")
|
||||
return False
|
||||
return None
|
||||
```
|
||||
|
||||
### Logging to External Systems
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@before_tool_call
|
||||
def log_to_external_system(context: ToolCallHookContext) -> None:
|
||||
logger.info(f"Tool call: {context.tool_name}", extra={
|
||||
'tool_name': context.tool_name,
|
||||
'tool_input': context.tool_input,
|
||||
'agent': context.agent.role if context.agent else None
|
||||
})
|
||||
return None
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Executing
|
||||
- Verify the hook is registered before crew execution
|
||||
- Check whether an earlier hook blocked the call (subsequent pre hooks don't run)
|
||||
- Check `tools=` / `agents=` filters against the actual tool name and agent role
|
||||
- Verify hook is registered before crew execution
|
||||
- Check if previous hook returned `False` (blocks execution and subsequent hooks)
|
||||
- Ensure hook signature matches expected type
|
||||
|
||||
### Input Modifications Not Working
|
||||
- Use in-place modifications: `ctx.tool_input['key'] = value`
|
||||
- Don't replace the dict: `ctx.tool_input = {}`
|
||||
- Use in-place modifications: `context.tool_input['key'] = value`
|
||||
- Don't replace the dict: `context.tool_input = {}`
|
||||
|
||||
### Result Modifications Not Working
|
||||
- Return the modified string from a `POST_TOOL_CALL` hook
|
||||
- Return the modified string from after hooks
|
||||
- Returning `None` keeps the original result
|
||||
- Ensure the tool actually returned a result
|
||||
|
||||
### Tool Blocked Unexpectedly
|
||||
- Check all pre hooks for `HookAborted` / `return False` conditions
|
||||
- The abort reason and source appear on the `HookDispatchedEvent` telemetry
|
||||
- Check all before hooks for blocking conditions
|
||||
- Verify hook execution order
|
||||
- Add debug logging to identify which hook is blocking
|
||||
|
||||
## Related Documentation
|
||||
## Conclusion
|
||||
|
||||
- [Execution Hooks Overview →](/edge/en/learn/execution-hooks)
|
||||
- [LLM Call Hooks →](/edge/en/learn/llm-hooks)
|
||||
- [Execution Boundary Hooks →](/edge/en/learn/execution-boundary-hooks)
|
||||
- [Step Hooks →](/edge/en/learn/step-hooks)
|
||||
Tool Call Hooks provide powerful capabilities for controlling and monitoring tool execution in CrewAI. Use them to implement safety guardrails, approval gates, input validation, result sanitization, logging, and analytics. Combined with proper error handling and type safety, hooks enable secure and production-ready agent systems with comprehensive observability.
|
||||
|
||||
@@ -4,396 +4,6 @@ description: "CrewAI의 제품 업데이트, 개선 사항 및 버그 수정"
|
||||
icon: "clock"
|
||||
mode: "wide"
|
||||
---
|
||||
<Update label="2026년 7월 17일">
|
||||
## v1.15.4
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.4)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 기술 저장소를 실험적 상태에서 벗어나도록 승격
|
||||
|
||||
### 문서
|
||||
- Studio 문서에 흐름 추가
|
||||
|
||||
## 기여자
|
||||
|
||||
@jessemiller, @joaomdmoura, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 7월 16일">
|
||||
## v1.15.3
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- PlusAPI 클라이언트에 조직 ID 매개변수 추가
|
||||
- @on을 중심으로 단계 가로채기 포인트 및 실행 훅 문서 재작업
|
||||
- 실행 경계 가로채기 포인트 연결
|
||||
- 일반 가로채기 훅 디스패처 추가
|
||||
- TUI(헤드리스 터미널 대체)에서 선언적 흐름 실행
|
||||
|
||||
### 버그 수정
|
||||
- OUTPUT 훅 결과와 kickoff-completed 이벤트 동기화
|
||||
- null 리포지토리 에이전트 속성 수정
|
||||
- after_llm_call 훅이 네이티브 도구 실행을 방해하지 않도록 보장
|
||||
- 핸들러가 히스토리를 잘라낼 때 턴 응답의 중복 추가 방지
|
||||
- 도구 결과 캐싱을 기본값이 아닌 선택 사항으로 설정
|
||||
- 생성 시 작성된 도구 설명 재작성 중지
|
||||
- 에이전트 및 크루 결과에서 두 이름 아래의 토큰 사용량 노출
|
||||
- kickoff 결과에 대한 호출당 사용 메트릭 보고
|
||||
- route_turn()이 falsy를 반환할 때 이전 턴의 의도를 재생하지 않도록 중지
|
||||
|
||||
### 문서화
|
||||
- 실행 훅 그룹화 업데이트 및 모든 훅 컨텍스트 문서화
|
||||
|
||||
## 기여자
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 7월 16일">
|
||||
## v1.15.3a2
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a2)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 버그 수정
|
||||
- OUTPUT 훅 결과와 kickoff-completed 이벤트의 동기화 수정
|
||||
|
||||
### 문서
|
||||
- v1.15.3a1에 대한 스냅샷 및 변경 로그 업데이트
|
||||
|
||||
### 의존성 업데이트
|
||||
- PYSEC-2026-3447 문제를 해결하기 위해 setuptools를 0.83.0으로 업데이트
|
||||
|
||||
## 기여자
|
||||
|
||||
@lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 7월 16일">
|
||||
## v1.15.3a1
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a1)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- PlusAPI 클라이언트에 조직 ID 매개변수 추가.
|
||||
- `@on` 주위의 실행 후크 문서를 재작업하고 단계 가로채기 포인트 추가.
|
||||
- 실행 경계 가로채기 포인트 연결.
|
||||
- 일반 가로채기 후크 디스패처 추가.
|
||||
- TUI(헤드리스 터미널 대체)에서 선언적 흐름 실행.
|
||||
- 사용자 정의 OpenAI URL 개선.
|
||||
|
||||
### 버그 수정
|
||||
- null 리포지토리 에이전트 속성 수정.
|
||||
- 기본 도구 실행이 중단되지 않도록 `after_llm_call` 후크 수정.
|
||||
- 핸들러가 기록을 잘라낼 때 턴 응답을 이중으로 추가하는 것을 중지.
|
||||
- 도구 결과 캐싱을 기본값이 아닌 선택적으로 설정.
|
||||
- 생성 시 작성된 도구 설명을 재작성하는 것을 중지.
|
||||
- 에이전트 및 크루 결과에서 두 이름으로 토큰 사용량 노출.
|
||||
- 시작 결과에서 호출당 사용 메트릭 보고.
|
||||
- `route_turn()`이 falsy를 반환할 때 이전 턴의 의도를 재생하지 않도록 중지.
|
||||
- 시작 및 흐름 완료 이벤트 전에 메모리 쓰기 배수.
|
||||
|
||||
### 문서
|
||||
- 실행 후크를 그룹화하고 모든 후크 컨텍스트 문서화.
|
||||
- 실행 후크에 대한 문서 업데이트.
|
||||
|
||||
## 기여자
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 7월 7일">
|
||||
## v1.15.2
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 크루 마법사에서 최신 LLM 모델을 동적으로 가져옵니다.
|
||||
- 인라인 기술 정의를 지원합니다.
|
||||
- 생성된 흐름 정의 작성 기술을 추가합니다.
|
||||
- 템플릿화된 흐름 액션 입력을 지원합니다.
|
||||
- 흐름 CEL 프롬프트를 위한 텍스트 도우미를 추가합니다.
|
||||
- 흐름 기술 예제를 위한 텍스트 도우미를 추가합니다.
|
||||
- AgentExecutor에서 메시지 설정 및 피드백 처리를 구현합니다.
|
||||
- 흐름 정의에 리포지토리 에이전트를 추가합니다.
|
||||
- 흐름을 위한 스트림 프레임 프로토콜을 정의합니다.
|
||||
- CrewDefinition에서 도구 및 앱 유형을 지정합니다.
|
||||
- 템플릿 명령을 crewAIInc-fde 조직으로 다시 포인팅합니다.
|
||||
|
||||
### 버그 수정
|
||||
- 정확한 API 키로 모델 카탈로그 캐시를 키하고 TTL을 단축하며 Ollama를 건너뜁니다.
|
||||
- `crewai run` 흐름 입력 해상도 및 상태 스키마에서 프롬프트를 통합합니다.
|
||||
- onnx 1.22.0 및 nltk PYSEC-2026-597에 대한 pip-audit 실패를 해결합니다.
|
||||
- 흐름에 대한 버전을 작성하고 있는지 확인합니다.
|
||||
- bedrock 추가에 aiobotocore를 포함합니다.
|
||||
- 자기 청취 흐름 메서드를 거부합니다.
|
||||
- Edge에서 문서 버전 내비게이션을 제거하여 새 페이지가 누락되지 않도록 합니다.
|
||||
|
||||
### 문서
|
||||
- 새로운 대시보드 변경 사항에 맞추어 규칙에서 정책으로 언어를 업데이트합니다.
|
||||
- 흐름 에이전트 옵션을 문서화합니다.
|
||||
- 내비게이션에 스트리밍 문서를 추가합니다.
|
||||
- 에이전트 제어 평면에서 비용 제한 규칙 유형을 문서화합니다.
|
||||
- Datadog 가이드에서 CREWAI_LOG_FORMAT 참조를 제거합니다.
|
||||
|
||||
## 기여자
|
||||
|
||||
@akaKuruma, @danielfsbarreto, @github-code-quality[bot], @joaomdmoura, @lorenzejay, @lucasgomide, @manisrinivasan2k1, @renatonitta, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 7월 1일">
|
||||
## v1.15.2a2
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a2)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- bedrock 추가에 aiobotocore 추가
|
||||
- 흐름 에이전트 옵션 문서화
|
||||
- 흐름 기술 예제에 텍스트 도우미 추가
|
||||
- 흐름 CEL 프롬프트를 위한 텍스트 도우미 추가
|
||||
- 탐색에 스트리밍 문서 추가
|
||||
|
||||
### 버그 수정
|
||||
- 자기 청취 흐름 메서드 거부
|
||||
|
||||
### 문서
|
||||
- v1.15.2a1에 대한 스냅샷 및 변경 로그 업데이트
|
||||
- AGENTS.md 파일 압축
|
||||
|
||||
## 기여자
|
||||
|
||||
@akaKuruma, @github-code-quality[bot], @lorenzejay, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 30일">
|
||||
## v1.15.2a1
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a1)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 템플릿 명령을 crewAIInc-fde 조직으로 재지정
|
||||
- 인라인 기술 정의 지원
|
||||
- 흐름을 위한 스트림 프레임 프로토콜 정의
|
||||
- CrewDefinition에 타입 도구 및 앱 추가
|
||||
- 생성된 흐름 정의 저작 기술 추가
|
||||
|
||||
### 버그 수정
|
||||
- 새로운 페이지가 삭제되는 것을 방지하기 위해 Edge에서 문서 버전 탐색 제거
|
||||
|
||||
### 문서
|
||||
- 에이전트 제어 평면에서 비용 한도 규칙 유형 문서화
|
||||
- Datadog 가이드에서 CREWAI_LOG_FORMAT 참조 제거
|
||||
|
||||
## 기여자
|
||||
|
||||
@danielfsbarreto, @joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 26일">
|
||||
## v1.15.1
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 생성된 프로젝트에 대한 Git 저장소 초기화 (#6364)
|
||||
- 명시적인 CrewAI 프로젝트 정의 필요 (#6358)
|
||||
- CLI 배포 후 배포 페이지 열기 (#6343)
|
||||
|
||||
### 버그 수정
|
||||
- 배포 페이지 링크 ID 해상도 수정 (#6365)
|
||||
- JSON 크루 템플릿 렌더링 수정 (#6359)
|
||||
- JSON 크루 버전 고정 수정 (#6342)
|
||||
- 스크래핑 페치에서 SSRF 리디렉션 우회 수정 (#6331)
|
||||
|
||||
### 문서
|
||||
- README에서 오픈 소스 위치 개선 (#6363)
|
||||
- 코딩 에이전트 설정을 위한 행동 촉구 개선 (#6344)
|
||||
- 버전 1.15.1a1에 대한 스냅샷 및 변경 로그 추가 (#6362)
|
||||
|
||||
## 기여자
|
||||
|
||||
@joaomdmoura, @lorenzejay, @oalami, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<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
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.15.0)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 텔레메트리에서 대화 흐름 턴 사용 추적
|
||||
- CLI TUI에서 대화 흐름 지원
|
||||
- 통합 선언적 흐름 로딩 추가
|
||||
- 선언적 흐름 CLI 지원 추가
|
||||
- 각 단계에 선택적 if 표현식 추가
|
||||
- 흐름 정의에 단일 에이전트 작업 추가
|
||||
- FlowDefinition에 크루 작업 추가
|
||||
- 인라인 크루 정의 로딩 추가
|
||||
- FlowDefinition에 `each` 복합 작업 추가
|
||||
- 크루 생성 및 실행에서 DMN 모드 지원 구현
|
||||
|
||||
### 버그 수정
|
||||
- 자격 증명 파일에 대한 소유자 전용 권한 집행 수정
|
||||
- JSON 스키마 흐름 상태 시작 입력 수정
|
||||
- 기술 아카이브 추출에서 심볼릭 링크 경로 탐색 수정
|
||||
- 모든 LLM 호출에 대한 토큰 사용 집계
|
||||
- 중복된 Exa 도구 제거
|
||||
- JSON 크루 문제 해결
|
||||
- JSON 크루 처리 수정 및 메모리 재설정 기능 향상
|
||||
|
||||
### 문서
|
||||
- JSON 우선 크루 프로젝트에 대한 설치 및 빠른 시작 문서 업데이트
|
||||
- 가져올 수 있는 작업 대시보드와 함께 Datadog 통합 가이드 추가
|
||||
- "단계당 한 카드" 스튜디오 페이지 추가
|
||||
- v1.15.0으로 이어지는 이전 버전의 스냅샷 및 변경 로그 추가
|
||||
|
||||
### 성능
|
||||
- crewai 실행 시작 UX 개선
|
||||
- 중첩된 크루에 대한 흐름 메서드 진행 상황 표시 유지
|
||||
|
||||
### 리팩토링
|
||||
- 흐름 상태 접근에서 `StateProxy` 제거
|
||||
- `crewai run`과 `crewai flow kickoff` 통합
|
||||
- FlowDefinition 상태 유형 구분
|
||||
- FlowDefinition에서 런타임으로 구성 및 지속성 연결
|
||||
|
||||
## 기여자
|
||||
|
||||
@gabemilani, @github-code-quality[bot], @greysonlalonde, @iris-clawd, @jessemiller, @joaomdmoura, @lorenzejay, @lucasgomide, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 24일">
|
||||
## v1.14.8a5
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a5)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 선언적 참조가 흐름과 크루 간에 작동하도록 수정 (#6326)
|
||||
|
||||
### 버그 수정
|
||||
- JSON 스키마 흐름 상태 시작 입력 수정 (#6325)
|
||||
|
||||
### 문서
|
||||
- Crew Studio 아래에 단계별 One Card를 중첩하고 롤아웃 배너 제거 (AGE-107) (#6317)
|
||||
- v1.14.8a4의 스냅샷 및 변경 로그 업데이트 (#6319)
|
||||
|
||||
### 리팩토링
|
||||
- 흐름 상태 접근에서 `StateProxy` 제거 (#6327)
|
||||
|
||||
## 기여자
|
||||
|
||||
@jessemiller, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 24일">
|
||||
## v1.14.8a4
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a4)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- CLI TUI에서 대화형 흐름 지원.
|
||||
|
||||
### 버그 수정
|
||||
- 기술 아카이브 추출 시 심볼릭 링크 경로 탐색 문제 수정.
|
||||
- 선언적 흐름 정의 경로 검증.
|
||||
|
||||
### 문서
|
||||
- v1.14.8a3에 대한 스냅샷 및 변경 로그 업데이트.
|
||||
|
||||
## 기여자
|
||||
|
||||
@lorenzejay, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 23일">
|
||||
## v1.14.8a3
|
||||
|
||||
[GitHub 릴리스 보기](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a3)
|
||||
|
||||
## 변경 사항
|
||||
|
||||
### 기능
|
||||
- 통합 선언적 흐름 로딩 추가
|
||||
- crewai run 시작 UX 개선
|
||||
- `crewai run`과 `crewai flow kickoff` 통합
|
||||
- 중첩된 크루의 흐름 메서드 진행 상황 표시 유지
|
||||
- 선언적 Flow CLI 지원 추가
|
||||
- 흐름의 시작 메서드로 `@router()` 허용
|
||||
- CrewAI 도구에 대한 타입이 지정된 출력 스키마 추가
|
||||
|
||||
### 버그 수정
|
||||
- opentelemetry를 ~=1.42.0으로 고정
|
||||
|
||||
### 문서
|
||||
- "단계당 한 카드" 스튜디오 페이지 추가
|
||||
|
||||
## 기여자
|
||||
|
||||
@jessemiller, @joaomdmoura, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="2026년 6월 18일">
|
||||
## v1.14.8a2
|
||||
|
||||
|
||||
@@ -24,23 +24,15 @@ mode: "wide"
|
||||
|
||||
## 빠른 시작
|
||||
|
||||
### 1. CLI로 스킬 생성
|
||||
|
||||
CLI는 스킬을 생성하는 공식 지원 방식입니다 — 디렉터리 레이아웃과 유효한 `SKILL.md`를 자동으로 스캐폴딩해 줍니다:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create code-review
|
||||
```
|
||||
|
||||
크루 프로젝트 내부(`pyproject.toml`이 있는 곳)에서는 `./skills/code-review/`가 생성되고, 프로젝트 외부에서는 현재 디렉터리에 `./code-review/`가 생성됩니다 (`--no-project`로 이 동작을 강제할 수 있습니다):
|
||||
### 1. 스킬 디렉터리 생성
|
||||
|
||||
```
|
||||
skills/
|
||||
└── code-review/
|
||||
├── SKILL.md # 필수 — 지침 (미리 채워진 템플릿)
|
||||
├── SKILL.md # 필수 — 지침
|
||||
├── references/ # 선택 — 참조 문서
|
||||
├── scripts/ # 선택 — 실행 가능한 스크립트
|
||||
└── assets/ # 선택 — 정적 파일
|
||||
│ └── style-guide.md
|
||||
└── scripts/ # 선택 — 실행 가능한 스크립트
|
||||
```
|
||||
|
||||
### 2. SKILL.md 작성
|
||||
@@ -172,65 +164,6 @@ agent = Agent(
|
||||
|
||||
---
|
||||
|
||||
## 스킬 생성, 게시 및 설치
|
||||
|
||||
스킬은 CLI로 관리되는 전체 라이프사이클을 갖습니다: **`crewai skill create`로 생성하고, `crewai skill publish`로 게시하세요** — 디렉터리를 직접 만드는 방식도 로컬 실험에는 사용할 수 있지만, CLI가 의도된 워크플로우이며 스킬 레이아웃과 프론트매터를 유효하게 유지해 줍니다.
|
||||
|
||||
### 생성
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create my-skill
|
||||
```
|
||||
|
||||
디렉터리를 스캐폴딩하고 (크루 프로젝트 내부에서는 `./skills/`에 생성) 템플릿 `SKILL.md`와 함께 빈 `scripts/`, `references/`, `assets/` 디렉터리를 만듭니다. `SKILL.md`를 편집하여 지침을 정의하세요.
|
||||
|
||||
### 게시
|
||||
|
||||
스킬 디렉터리 내부(`SKILL.md`가 있는 곳)에서 실행하세요:
|
||||
|
||||
```shell Terminal
|
||||
cd skills/my-skill
|
||||
crewai skill publish
|
||||
```
|
||||
|
||||
게시 시 `SKILL.md` 프론트매터에서 `name`, `description`, `metadata.version`을 읽어 스킬을 CrewAI 레지스트리로 푸시합니다. **게시된 스킬은 항상 조직 범위로 제한됩니다** — 도구와 마찬가지로 게시한 조직의 멤버만 스킬을 보고 설치할 수 있으며, 공개 가시성은 없습니다. 유용한 플래그:
|
||||
|
||||
| 플래그 | 효과 |
|
||||
| :--- | :--- |
|
||||
| `--org <slug>` | 특정 조직으로 게시합니다 (설정을 재정의). |
|
||||
| `--force` | git 상태 검증을 건너뜁니다 (커밋되지 않은 변경 사항 등). |
|
||||
|
||||
### 설치
|
||||
|
||||
게시된 스킬을 `@org/name` 참조로 설치합니다:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill install @acme/code-review
|
||||
```
|
||||
|
||||
크루 프로젝트 내부에서는 스킬이 `./skills/{name}/`에 설치되고, 프로젝트 외부에서는 공유 캐시인 `~/.crewai/skills/{org}/{name}/`에 저장됩니다.
|
||||
|
||||
에이전트는 레지스트리 스킬을 직접 참조할 수도 있습니다 — 런타임에 로컬 캐시(또는 프로젝트 `skills/` 디렉터리)에서 해석됩니다:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
role="Senior Code Reviewer",
|
||||
goal="Review pull requests for quality and security issues",
|
||||
backstory="Staff engineer with expertise in secure coding practices.",
|
||||
skills=["@acme/code-review"], # registry ref, resolved locally
|
||||
)
|
||||
```
|
||||
|
||||
### 목록 조회
|
||||
|
||||
```shell Terminal
|
||||
crewai skill list
|
||||
```
|
||||
|
||||
프로젝트 `./skills/` 디렉터리와 전역 캐시 양쪽에 설치된 스킬을 버전 및 경로와 함께 보여줍니다.
|
||||
|
||||
---
|
||||
|
||||
## 크루 레벨 스킬
|
||||
|
||||
스킬을 크루에 설정하여 **모든 에이전트**에 적용할 수 있습니다:
|
||||
|
||||
@@ -11,7 +11,7 @@ mode: "wide"
|
||||
|
||||
- [개요](/ko/enterprise/features/agent-control-plane/overview)
|
||||
- **모니터링** *(현재 페이지)*
|
||||
- [정책](/edge/ko/enterprise/features/agent-control-plane/policies)
|
||||
- [규칙](/ko/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## 개요
|
||||
@@ -58,7 +58,7 @@ mode: "wide"
|
||||
| **Last execution** | 가장 최근 실행 이후 경과 시간. |
|
||||
| **Health Status Breakdown** | 윈도우 내 실행에 대한 `Critical` / `Warning` / `Healthy` 비율의 누적 막대. |
|
||||
| **Executions with Errors** | 윈도우 내 총 실패 실행 수. |
|
||||
| **PII detection applied** | deployment별 PII 설정 또는 일치하는 [PII 정책](/edge/ko/enterprise/features/agent-control-plane/policies)이 활성화된 경우 `Yes`. |
|
||||
| **PII detection applied** | deployment별 PII 설정 또는 일치하는 [PII 규칙](/ko/enterprise/features/agent-control-plane/rules)이 활성화된 경우 `Yes`. |
|
||||
| **Executions** | 윈도우 내 총 실행 수. |
|
||||
| **Last updated** | deployment의 마지막 재배포 시점. |
|
||||
| **Crew Version** | deployment가 보고한 `crewai` 버전. `1.13` 미만 버전 옆의 정보 아이콘은 메트릭에 기여할 수 없는 행을 표시합니다. |
|
||||
@@ -96,8 +96,8 @@ mode: "wide"
|
||||
<Card title="Agent Control Plane — 개요" icon="book-open" href="/ko/enterprise/features/agent-control-plane/overview">
|
||||
ACP란 무엇이며, 요구사항, 플랜 등급, RBAC에 대해.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — 정책" icon="shield-check" href="/edge/ko/enterprise/features/agent-control-plane/policies">
|
||||
조직 단위 PII Redaction 정책을 여러 자동화에 적용합니다.
|
||||
<Card title="Agent Control Plane — 규칙" icon="shield-check" href="/ko/enterprise/features/agent-control-plane/rules">
|
||||
조직 단위 PII Redaction 규칙을 여러 자동화에 적용합니다.
|
||||
</Card>
|
||||
<Card title="Traces" icon="timeline" href="/ko/enterprise/features/traces">
|
||||
개별 실행을 드릴다운하여 에이전트의 추론, 도구 호출, 토큰 사용량을 확인합니다.
|
||||
|
||||
@@ -10,17 +10,17 @@ icon: "book-open"
|
||||
|
||||
- **개요** *(현재 페이지)*
|
||||
- [모니터링](/ko/enterprise/features/agent-control-plane/monitoring)
|
||||
- [정책](/edge/ko/enterprise/features/agent-control-plane/policies)
|
||||
- [규칙](/ko/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## 개요
|
||||
|
||||
**Agent Control Plane**(ACP)은 CrewAI AMP에서 실행 중인 모든 워크로드를 위한 운영 허브입니다. **Automations**와 **Policies** 두 개의 탭으로 구성된 단일 화면에서 다음 작업을 할 수 있습니다:
|
||||
**Agent Control Plane**(ACP)은 CrewAI AMP에서 실행 중인 모든 워크로드를 위한 운영 허브입니다. **Automations**와 **Rules** 두 개의 탭으로 구성된 단일 화면에서 다음 작업을 할 수 있습니다:
|
||||
|
||||
- 모든 라이브 자동화(crew 또는 flow)의 **상태(health)**를 `Critical` / `Warning` / `Healthy` 분포와 실행 횟수로 모니터링합니다.
|
||||
- 자동화별·공급자별·모델별 **LLM 소비**(토큰 및 비용)를 추적하고, 이전 기간 대비 변화량을 확인합니다.
|
||||
- 임의의 자동화 또는 모델 공급자를 드릴다운하여 시계열 차트와 공급자별 분해를 살펴봅니다.
|
||||
- 조직 전체에 **정책(Policies)**(현재: PII Redaction)을 적용하여 각 deployment를 개별 편집하지 않고 한 번에 여러 자동화에 정책을 강제합니다.
|
||||
- 조직 전체에 **규칙(Rules)**(현재: PII Redaction)을 적용하여 각 deployment를 개별 편집하지 않고 한 번에 여러 자동화에 정책을 강제합니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
@@ -33,7 +33,7 @@ icon: "book-open"
|
||||
두 탭은 서로 다른 두 가지 질문에 답합니다:
|
||||
|
||||
- **Automations** — *"지금 내 플릿은 어떻게 동작하고 있고, 얼마나 비용이 들고 있는가?"* [모니터링](/ko/enterprise/features/agent-control-plane/monitoring)을 참고하세요.
|
||||
- **Policies** — *"정책(예: PII redaction)을 매번 재배포하지 않고 여러 deployment에 어떻게 강제할 수 있는가?"* [정책](/edge/ko/enterprise/features/agent-control-plane/policies)을 참고하세요.
|
||||
- **Rules** — *"정책(예: PII redaction)을 매번 재배포하지 않고 여러 deployment에 어떻게 강제할 수 있는가?"* [규칙](/ko/enterprise/features/agent-control-plane/rules)을 참고하세요.
|
||||
|
||||
## 요구사항
|
||||
|
||||
@@ -42,11 +42,11 @@ icon: "book-open"
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
[정책](/edge/ko/enterprise/features/agent-control-plane/policies)을 생성하거나 편집하려면 **Enterprise 또는 Ultra 플랜**이 필요합니다. 하위 플랜의 조직도 Policies 탭을 열고 기존 정책을 볼 수 있지만, 편집기는 "Enterprise" 잠금 핀과 *"PII Redaction policies require an Enterprise plan."* 경고와 함께 읽기 전용으로 표시됩니다. 모니터링(Automations 탭)은 기능이 활성화된 모든 플랜에서 사용할 수 있습니다.
|
||||
[규칙](/ko/enterprise/features/agent-control-plane/rules)을 생성하거나 편집하려면 **Enterprise 또는 Ultra 플랜**이 필요합니다. 하위 플랜의 조직도 Rules 탭을 열고 기존 규칙을 볼 수 있지만, 편집기는 "Enterprise" 잠금 핀과 *"PII Redaction rules require an Enterprise plan."* 경고와 함께 읽기 전용으로 표시됩니다. 모니터링(Automations 탭)은 기능이 활성화된 모든 플랜에서 사용할 수 있습니다.
|
||||
</Warning>
|
||||
|
||||
- **Agent Control Plane** 기능이 조직에 대해 활성화되어 있어야 합니다. 사이드바에 보이지 않으면 계정 오너에게 활성화를 요청하세요.
|
||||
- ACP 내부에서는 [RBAC](/ko/enterprise/features/rbac)가 접근 권한을 관리합니다: 대시보드 및 정책을 보려면 `read`, 정책을 생성·편집·토글·삭제하려면 `manage` 권한이 필요합니다.
|
||||
- ACP 내부에서는 [RBAC](/ko/enterprise/features/rbac)가 접근 권한을 관리합니다: 대시보드 및 규칙을 보려면 `read`, 규칙을 생성·편집·토글·삭제하려면 `manage` 권한이 필요합니다.
|
||||
- 모든 차트와 테이블은 오른쪽 상단의 시간 선택기를 통해 **지난 24시간**, **지난 1주**, **지난 30일**로 범위를 조정할 수 있습니다. 변화량(`↑ 8 vs yesterday`, `↓ $20.57 vs yesterday` 등)은 선택한 윈도우를 같은 길이의 이전 윈도우와 비교합니다.
|
||||
|
||||
## 여기에서 할 수 있는 일
|
||||
@@ -55,7 +55,7 @@ icon: "book-open"
|
||||
<Card title="모니터링" icon="gauge" href="/ko/enterprise/features/agent-control-plane/monitoring">
|
||||
메트릭 카드, 인터랙티브 sankey, 자동화별 테이블, 자동화 또는 공급자별 드릴다운 사이드 패널로 플릿 상태와 LLM 지출을 살펴봅니다.
|
||||
</Card>
|
||||
<Card title="정책" icon="shield-check" href="/edge/ko/enterprise/features/agent-control-plane/policies">
|
||||
<Card title="규칙" icon="shield-check" href="/ko/enterprise/features/agent-control-plane/rules">
|
||||
도구와 태그로 범위를 지정한 PII Redaction 정책을 조직 단위로 적용합니다. 변경 사항은 다음 실행부터 적용되며 재배포가 필요 없습니다.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -67,10 +67,10 @@ icon: "book-open"
|
||||
개별 실행을 드릴다운하여 에이전트의 추론, 도구 호출, 토큰 사용량을 확인합니다.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/ko/enterprise/features/rbac">
|
||||
누가 Agent Control Plane을 읽을 수 있고 누가 정책을 편집할 수 있는지 관리합니다.
|
||||
누가 Agent Control Plane을 읽을 수 있고 누가 규칙을 편집할 수 있는지 관리합니다.
|
||||
</Card>
|
||||
<Card title="Traces용 PII Redaction" icon="lock" href="/ko/enterprise/features/pii-trace-redactions">
|
||||
정책이 참조하는 엔티티 카탈로그 및 deployment 단위 PII 설정.
|
||||
규칙이 참조하는 엔티티 카탈로그 및 deployment 단위 PII 설정.
|
||||
</Card>
|
||||
<Card title="AMP에 배포" icon="rocket" href="/ko/enterprise/guides/deploy-to-amp">
|
||||
Agent Control Plane을 지원하는 crewAI 버전으로 crew를 배포합니다.
|
||||
@@ -78,5 +78,5 @@ icon: "book-open"
|
||||
</CardGroup>
|
||||
|
||||
<Card title="도움이 필요하신가요?" icon="headset" href="mailto:support@crewai.com">
|
||||
메트릭 해석 또는 정책 설계에 도움이 필요하시면 지원 팀에 문의하세요.
|
||||
메트릭 해석 또는 규칙 설계에 도움이 필요하시면 지원 팀에 문의하세요.
|
||||
</Card>
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
---
|
||||
title: "정책 설정하기"
|
||||
description: "한 곳에서 조직 단위 정책을 여러 자동화에 적용합니다."
|
||||
sidebarTitle: "정책"
|
||||
icon: "shield-check"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**ACP (베타) 문서 내비게이션**
|
||||
|
||||
- [개요](/ko/enterprise/features/agent-control-plane/overview)
|
||||
- [모니터링](/ko/enterprise/features/agent-control-plane/monitoring)
|
||||
- **정책** *(현재 페이지)*
|
||||
</Info>
|
||||
|
||||
## 개요
|
||||
|
||||
정책(Policies)은 각 deployment를 개별 설정하는 대신, 정책 — 현재: **PII Redaction** — 을 한 번에 여러 자동화에 적용할 수 있게 해줍니다. 관리하려면 [Agent Control Plane](/ko/enterprise/features/agent-control-plane/overview)에서 **Policies** 탭을 엽니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
각 정책 카드에는 이름, 설명, 정책이 적용되는 **범위(scope)**(선택된 도구와 태그), 그리고 현재 범위와 일치하는 deployment의 수인 **engaged automations**가 표시됩니다. 오른쪽 토글로 정책을 삭제하지 않고 활성/비활성할 수 있습니다.
|
||||
|
||||
## 요구사항
|
||||
|
||||
<Warning>
|
||||
PII Redaction 정책을 생성하거나 편집하려면 **Enterprise 또는 Ultra 플랜**이 필요합니다. 하위 플랜의 조직도 Policies 탭을 열고 기존 정책을 볼 수는 있지만, 편집기는 "Enterprise" 잠금 핀과 *"PII Redaction policies require an Enterprise plan."* 경고와 함께 읽기 전용으로 렌더링됩니다. 업그레이드하려면 계정 오너 또는 영업팀에 문의하세요.
|
||||
</Warning>
|
||||
|
||||
- **Agent Control Plane** 기능이 조직에 대해 활성화되어 있어야 합니다. [개요 — 요구사항](/ko/enterprise/features/agent-control-plane/overview#요구사항)을 참고하세요.
|
||||
- 정책을 생성·편집·토글·삭제하려면 Agent Control Plane에 대한 [RBAC](/ko/enterprise/features/rbac)의 `manage` 권한이 필요합니다. 보려면 `read` 권한만으로 충분합니다.
|
||||
- 모든 정책 변경은 감사를 위해 버전 관리됩니다.
|
||||
|
||||
## 사용 가능한 정책 유형
|
||||
|
||||
| 유형 | 동작 |
|
||||
|------|---------------|
|
||||
| **PII Redaction** | 일치하는 모든 자동화의 실행에 PII redaction을 적용합니다. [Traces용 PII Redaction](/ko/enterprise/features/pii-trace-redactions)에 문서화된 동일한 엔티티 카탈로그와 커스텀 recognizer를 사용합니다. |
|
||||
|
||||
향후 더 많은 정책 유형이 추가될 예정입니다.
|
||||
|
||||
## 정책 만들기
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/acp-policies-new-side-panel.png" alt="조건 및 PII 마스크 유형이 있는 정책 편집 사이드 패널" width="450" />
|
||||
</Frame>
|
||||
|
||||
<Steps>
|
||||
<Step title="편집기 열기">
|
||||
Policies 탭 오른쪽 상단의 **+ Create new**를 클릭하거나, 기존 정책 카드의 **View Details**를 클릭합니다.
|
||||
</Step>
|
||||
|
||||
<Step title="정책 이름과 설명 작성">
|
||||
정책에 명확한 이름(예: *Mask PII (CC)*)과 적용 시점을 설명하는 description을 부여합니다. 둘 다 정책 카드와 Engaged Automations 모달에 표시됩니다.
|
||||
</Step>
|
||||
|
||||
<Step title="유형 선택">
|
||||
현재 **PII Redaction**만 사용할 수 있습니다.
|
||||
</Step>
|
||||
|
||||
<Step title="조건 설정">
|
||||
조건은 정책이 어떤 자동화에 engage 할지 결정합니다. 둘 다 선택 사항이며 **집합 동일성(set-equality)** 의미론을 사용합니다:
|
||||
|
||||
- **Tools** — 도구 집합이 선택된 도구와 **정확히 일치**하는 자동화만 engage 됩니다. Studio 앱, MCP, OSS 도구, Tool Repository registry 도구 중에서 선택합니다.
|
||||
- **Automations** — 태그 집합이 선택된 태그와 **정확히 일치**하는 자동화만 engage 됩니다.
|
||||
|
||||
피커를 비워두면 "이 차원에서 필터링하지 않음"을 의미합니다. 두 피커를 모두 비워두면 정책이 조직의 **모든** 자동화에 적용됩니다.
|
||||
</Step>
|
||||
|
||||
<Step title="PII Mask Type 테이블 구성">
|
||||
적용할 각 엔티티 유형을 체크하고 **Mask**(엔티티 레이블로 치환, 예: `<CREDIT_CARD>`) 또는 **Redact**(일치하는 텍스트를 완전히 제거) 중에서 선택합니다. 전체 엔티티 카탈로그와 조직 단위 커스텀 recognizer 추가 방법은 [Traces용 PII Redaction](/ko/enterprise/features/pii-trace-redactions)을 참고하세요.
|
||||
</Step>
|
||||
|
||||
<Step title="저장">
|
||||
저장하는 즉시 engage 된 모든 자동화의 **향후** 실행에 정책이 적용됩니다. 재배포는 필요 없습니다.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Engaged automations
|
||||
|
||||
정책 카드의 **Engaged N automations**를 클릭하면 현재 정책이 일치시키고 있는 deployment와 각 deployment의 마지막 실행을 정확히 확인할 수 있습니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
정책을 활성화하기 전에 범위를 빠르게 점검하는 가장 좋은 방법입니다. 예를 들어, `production` 태그로 범위를 지정한 정책이 의도치 않게 staging deployment를 일치시키지 않는지 확인할 수 있습니다.
|
||||
|
||||
## 조직 단위 정책 vs deployment 단위 설정
|
||||
|
||||
PII Redaction은 두 곳에서 설정할 수 있습니다:
|
||||
|
||||
- **deployment 단위** — 각 deployment의 **Settings → PII Protection** ([가이드](/ko/enterprise/features/pii-trace-redactions))
|
||||
- **조직 단위** — 이 페이지의 정책
|
||||
|
||||
활성화된 조직 단위 정책의 범위가 어떤 deployment와 일치하면, 정책의 엔티티 구성이 그 deployment의 실행에 대해 **deployment가 소유한 PII 설정을 덮어씁니다**. 정책이 연결된 동안에는 정책이 단일 진실 공급원이 됩니다. 정책을 비활성화하거나 분리하면(또는 범위를 변경하여 더 이상 일치하지 않게 만들면) deployment는 자체 PII Protection 설정으로 되돌아갑니다.
|
||||
|
||||
여러 deployment에 걸쳐 일관된 정책을 강제하고 싶을 때는 조직 단위 정책을 선호하고, 일회성 예외에 대해서는 deployment 단위 설정을 사용하세요.
|
||||
|
||||
## 관련 문서
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agent Control Plane — 개요" icon="book-open" href="/ko/enterprise/features/agent-control-plane/overview">
|
||||
ACP란 무엇이며, 요구사항, 플랜 등급, RBAC에 대해.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — 모니터링" icon="gauge" href="/ko/enterprise/features/agent-control-plane/monitoring">
|
||||
플릿 전반의 자동화와 LLM 소비를 모니터링합니다.
|
||||
</Card>
|
||||
<Card title="Traces용 PII Redaction" icon="lock" href="/ko/enterprise/features/pii-trace-redactions">
|
||||
엔티티 카탈로그, 커스텀 recognizer, deployment 단위 구성.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/ko/enterprise/features/rbac">
|
||||
누가 정책을 만들거나 편집할 수 있는지 관리합니다.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Card title="도움이 필요하신가요?" icon="headset" href="mailto:support@crewai.com">
|
||||
조직의 정책을 설계하는 데 도움이 필요하시면 지원 팀에 문의하세요.
|
||||
</Card>
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**6월 24일 수요일 출시.** Studio 캔버스가 작업과 에이전트를 별도의 노드로 표시하는 대신 단계당 하나의 카드로 전환됩니다. 곧 추가될 새로운 기능을 위해 캔버스를 간소화하기 위한 변경입니다. 기존 자동화는 아무런 변경 없이 그대로 동작하며, 모든 작업 및 에이전트 설정은 단일 카드에 정리되어 그대로 사용할 수 있습니다.
|
||||
</Note>
|
||||
|
||||
## 개요
|
||||
|
||||
Studio 캔버스에서 각 작업 단계는 **하나의 카드**로 표현됩니다. 이 카드는 이전에 별도의 노드에 있던 두 가지를 결합합니다:
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
---
|
||||
title: "Studio의 Flows"
|
||||
description: "결정론적인 단계별 제어와 에이전트 지능을 결합한 이벤트 기반 워크플로우를 코드 없이 구축하세요."
|
||||
icon: "diagram-project"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**점진적 출시 중**: Studio의 Flows는 2026년 7월 20일 주간에 걸쳐 순차적으로 출시됩니다. Studio에서 아직 Flows 옵션이 보이지 않는다면 소속 조직에 아직 배포되지 않은 것이니 곧 다시 확인해 주세요.
|
||||
</Info>
|
||||
|
||||
## 개요
|
||||
|
||||
이제 Studio에서 Crew뿐 아니라 **Flows**도 구축할 수 있습니다. Flows는 어떤 단계가 어떤 순서로, 어떤 조건에서 실행될지를 직접 제어하는 이벤트 기반 워크플로우이며, 각 단계 내부의 지능적인 작업은 AI 에이전트에게 맡길 수 있습니다.
|
||||
|
||||
Flow를 만들려면 Studio를 열고 자동화를 설명한 뒤, 프롬프트 입력창 옆의 선택기에서 **Flows**를 선택하세요.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
## 왜 Flows인가?
|
||||
|
||||
Crew는 에이전트 팀이 목표를 향해 자율적으로 협업하도록 할 때 매우 유용합니다. 하지만 실제 자동화 중 상당수는 더 높은 예측 가능성이 필요합니다. 먼저 이 데이터를 가져오고, 그다음 요약하고, 마지막으로 결과를 게시하는 식으로 — 매번 같은 순서로요.
|
||||
|
||||
Flows는 두 가지를 모두 제공합니다:
|
||||
|
||||
- **필요한 곳의 결정론**: 단계가 정의된 순서와 명시적인 분기에 따라 실행되므로, 실행 결과가 예측 가능하고 반복 가능하며 디버깅하기 쉽습니다.
|
||||
- **필요한 곳의 지능**: 각 단계는 에이전트(또는 전체 crew)가 수행하므로, 요약·평가·작성·판단 같은 단계 내부의 작업은 LLM의 추론 능력을 온전히 활용합니다.
|
||||
|
||||
이 조합 덕분에 Flows는 프로덕션 자동화에 적합합니다. 구조는 보장되고, 에이전트의 자율성은 그것이 필요한 단계로만 한정됩니다.
|
||||
|
||||
## Flow 구축하기
|
||||
|
||||
원하는 것을 자연어로 설명하면 Studio Assistant가 Flow를 설계해 줍니다. 단계를 만들고, 서로 연결하고, 각 단계에 필요한 에이전트와 앱 연동을 구성합니다. 오른쪽 캔버스에는 완성된 워크플로우가 연결된 노드로 표시되며, 대화를 이어가며 반복 수정하거나 노드를 직접 편집할 수 있습니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
준비가 되면 **Run**으로 Flow를 처음부터 끝까지 테스트하고, **Output** 및 **Traces** 탭에서 결과를 확인한 뒤, 안정화되면 **Deploy**하세요. 프로젝트를 **Share**하거나 소스 코드를 **Download**할 수도 있습니다.
|
||||
|
||||
## 노드 유형
|
||||
|
||||
Flows는 세 가지 핵심 노드 유형으로 구성됩니다. 각 노드는 워크플로우의 한 단계이며 자유롭게 조합할 수 있습니다.
|
||||
|
||||
### Single Agent
|
||||
|
||||
Single Agent 노드는 하나의 에이전트가 하나의 집중된 작업을 수행합니다. 연동 서비스에서 데이터 가져오기, 콘텐츠 변환, 메시지 게시처럼 범위가 명확한 단계에 적합합니다.
|
||||
|
||||
에이전트 노드를 클릭하면 전체 구성이 열립니다:
|
||||
|
||||
- **Task**: 이 단계가 달성해야 할 목표와 생성해야 할 출력
|
||||
- **Profile**: 에이전트의 role, goal, backstory
|
||||
- **Model**: 에이전트를 구동하는 LLM
|
||||
- **Apps**: 에이전트가 사용할 수 있는 연동 서비스(예: Linear, Slack, HubSpot)
|
||||
- **Runtime Controls**: 실행 전 계획 수립, 위임, 메모리에 대한 토글
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
### Crews
|
||||
|
||||
Crew 노드는 여러 에이전트가 여러 작업을 협업으로 수행하는 전체 crew를 Flow의 단일 단계로 포함합니다. 데이터를 팀별로 그룹화·요약한 뒤 전달용으로 포맷을 정리하는 것처럼, 하나의 에이전트로 감당하기 어려운 단계에 사용하세요.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Crew 노드를 열면 내부 구조가 표시됩니다. 수행하는 작업, 각 작업에 배정된 에이전트, 사용하는 앱을 확인할 수 있습니다. crew는 해당 단계 내에서 자율적으로 실행된 뒤 결과를 Flow의 다음 노드로 전달합니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
이것이 결정론과 에이전트 지능이 결합된 패턴입니다. Flow는 crew가 *언제* 실행될지를 보장하고, crew는 작업을 *어떻게* 수행할지에 협업 지능을 더합니다.
|
||||
|
||||
### Router
|
||||
|
||||
Router 노드는 조건에 따라 Flow를 분기시켜 결과에 따라 서로 다른 경로를 따르게 합니다. 예를 들어 리드 라우팅 Flow는 유입 리드를 평가한 뒤, 고품질 리드는 영업 배정 단계로 보내고 나머지는 향후 육성을 위해 기록만 남길 수 있습니다.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Router가 있기에 Flows는 진정한 이벤트 기반 워크플로우가 됩니다. 하나의 워크플로우가 모든 경우를 처리하되, 각 실행은 데이터에 해당하는 분기만 따라갑니다 — 불필요한 단계도, 다음에 무슨 일이 일어날지에 대한 모호함도 없습니다.
|
||||
|
||||
## Agent Repository 동기화
|
||||
|
||||
Flows에서 만든 에이전트를 하나의 프로젝트에 가둘 필요가 없습니다. 모든 에이전트 노드에는 **Publish to Agent Repository** 버튼이 있어, 에이전트의 role, goal, backstory, 모델, 구성을 조직의 [Agent Repository](/ko/enterprise/features/agent-repositories)에 저장할 수 있습니다.
|
||||
|
||||
양방향으로 동작합니다:
|
||||
|
||||
- **게시(Publish)**: Flow에서 다듬은 에이전트를 리포지토리로 승격하여 다른 팀과 프로젝트에서 재사용할 수 있게 합니다.
|
||||
- **가져오기(Pull)**: 처음부터 다시 만드는 대신 리포지토리의 기존 에이전트를 새 Flow로 가져옵니다.
|
||||
|
||||
리포지토리 에이전트는 조직 전체에 동기화되므로, 공유 에이전트를 한 번 개선하면 이를 사용하는 모든 Flow가 혜택을 받습니다. 에이전트 동작을 일관되고 관리 가능하게 유지하며 중복 작업을 없앨 수 있습니다.
|
||||
|
||||
## 모범 사례
|
||||
|
||||
- 자동화에 명확한 순서나 분기 로직이 있다면 **Flow를 선택**하고, 목표까지의 경로가 열려 있다면 Crew를 선택하세요.
|
||||
- **에이전트 작업은 집중적으로 유지하세요** — 작업 설명이 명확한 Single Agent 노드가 세 가지 일을 한꺼번에 맡은 에이전트보다 안정적입니다.
|
||||
- **Router로 모든 경우를 명시적으로 처리하세요.** "아무것도 하지 않는" 경로(예: 건너뛴 리드 기록)까지 포함해 모든 실행이 빠짐없이 처리되도록 합니다.
|
||||
- **안정화된 에이전트는 Agent Repository에 게시**하여 조직이 일회성 복사본 대신 공유 라이브러리를 구축하도록 하세요.
|
||||
- **배포 전에 Run으로 테스트하고 Traces를 확인**하여 연동이나 프롬프트 문제를 조기에 발견하세요.
|
||||
|
||||
## 관련 문서
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="Crew Studio" href="/ko/enterprise/features/crew-studio" icon="pencil">
|
||||
Studio에서 Crew를 구축하세요.
|
||||
</Card>
|
||||
<Card title="Agent Repositories" href="/ko/enterprise/features/agent-repositories" icon="people-group">
|
||||
조직 전체에서 에이전트를 공유하고 재사용하세요.
|
||||
</Card>
|
||||
<Card title="Flows 개념" href="/ko/concepts/flows" icon="diagram-project">
|
||||
CrewAI 프레임워크에서 Flows가 동작하는 방식을 알아보세요.
|
||||
</Card>
|
||||
<Card title="Tools & Integrations" href="/ko/enterprise/features/tools-and-integrations" icon="plug">
|
||||
에이전트가 사용할 앱을 연결하세요.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -21,11 +21,12 @@ CrewAI supports two log-ingestion paths to Datadog — both are first-class and
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Datadog Agent">
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. Each log event ships as a single billable line with structured attributes — see the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. With `CREWAI_LOG_FORMAT=json` set, each log event ships as a single billable line with structured attributes.
|
||||
|
||||
**Setup:**
|
||||
1. Run the Datadog Agent next to your CrewAI containers — see [Datadog's deployment docs](https://docs.datadoghq.com/agent/) for Kubernetes, ECS, or VM setup. Enable log collection (`logs_enabled: true`) and container log collection (`logs_config.container_collect_all: true`).
|
||||
2. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
2. Set `CREWAI_LOG_FORMAT=json` as an **automation environment variable** in CrewAI AMP (open your automation → **Settings → Environment Variables**) so each log event is a single line instead of a multi-line traceback. AMP propagates the value to every container in the deployment (API + workers) — don't set it on the container or host directly. See [Enabling JSON output](#enabling-json-output) below for the AMP UI walkthrough and the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
3. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
|
||||
**Pick this path if** you already operate Datadog Agents (e.g. for infrastructure metrics), or your log volume makes per-event ingestion cost a real concern — collapsing tracebacks into single events keeps Agent ingestion cheap at scale.
|
||||
</Tab>
|
||||
@@ -56,10 +57,10 @@ Either path lands the same structured facets in Datadog (`@automation_id`, `@kic
|
||||
## Log schema reference
|
||||
|
||||
<Info>
|
||||
This schema applies to the **Datadog Agent path** — structured stdout JSON logs emitted by every CrewAI worker container. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
This schema applies to the **Datadog Agent path** — stdout JSON logs produced when `CREWAI_LOG_FORMAT=json` is set. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
</Info>
|
||||
|
||||
Every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
When `CREWAI_LOG_FORMAT=json` is set, every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
|
||||
### Why JSON output
|
||||
|
||||
@@ -78,6 +79,20 @@ Every log event is emitted as a **single JSON object per line** to stdout, with
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Enabling JSON output
|
||||
|
||||
`CREWAI_LOG_FORMAT=json` must be set as an **automation environment variable** in CrewAI AMP — it is **not** a container, host, or Docker setting. Open your automation in AMP, click the **Settings** icon, and add the variable under the **Environment Variables** section. AMP applies the value to every container in the deployment (API + workers) on the next restart. See [Update Your Crew](./update-crew) for the full UI walkthrough with screenshots.
|
||||
|
||||
```shell
|
||||
CREWAI_LOG_FORMAT=json
|
||||
```
|
||||
|
||||
Restart the deployment to pick up the change. Every log line on stdout from that point on is a single JSON object.
|
||||
|
||||
<Note>
|
||||
The default value is `text`, which preserves the legacy human-readable line format byte-for-byte. Setting any value other than `json` falls back to text mode. There is no migration step — the variable is read at process start and the format switches immediately.
|
||||
</Note>
|
||||
|
||||
### Example events
|
||||
|
||||
A single info-level log inside an active automation kickoff:
|
||||
@@ -120,7 +135,7 @@ An error with a Python exception is collapsed into a single event with the trace
|
||||
}
|
||||
```
|
||||
|
||||
Without JSON output, that same error would produce ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
The same error in legacy text mode would have produced ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
|
||||
### Schema v1 fields
|
||||
|
||||
@@ -222,7 +237,7 @@ Open [Logs Explorer](https://app.datadoghq.com/logs) and run a query that matche
|
||||
<Tab title="Datadog Agent">
|
||||
Search `service:crewai* @schema:v1`. You should see structured logs with the JSON fields parsed into Datadog facets. Pick a recent event and verify it has `@automation_id`, `@kickoff_id`, `@execution_id`, `@crewai_version`, and (when running inside a span) `@trace_id` / `@span_id` populated.
|
||||
|
||||
If nothing appears, confirm the Datadog Agent is tailing container stdout and that the deployment is running a recent enough CrewAI Enterprise build.
|
||||
If nothing appears, confirm `CREWAI_LOG_FORMAT=json` is set under your automation's **Environment Variables** in AMP, the deployment was restarted after the change, and the Datadog Agent is tailing container stdout.
|
||||
</Tab>
|
||||
<Tab title="Datadog OTLP intake">
|
||||
Search `source:otlp service:crewai*`. OTLP attributes land with their OpenTelemetry names (`automation_id`, `crewai.kickoff.id`, etc.) rather than the stdout JSON keys, but they map to the same dashboard facets after [facet promotion](#prerequisite-promote-facets).
|
||||
@@ -265,7 +280,7 @@ The `$service` template variable defaults to `*` and will catch every CrewAI dep
|
||||
| All widgets show "No data" | Facets aren't promoted | Re-do the [Promote facets](#prerequisite-promote-facets) step. Datadog won't query against an un-promoted field. |
|
||||
| Error Rate widget shows `NaN` | No executions in the time window | Either no traffic, or `@execution_id` isn't faceted. Expand the time range and re-check facets. |
|
||||
| Throughput chart is flat at the same value | Logs aren't reaching Datadog | Search `service:crewai*` in Logs Explorer. If nothing shows, verify the Datadog Agent is running (Agent path) or the OTel collector endpoint is correct (OTLP path). |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments (pre-structured-logs AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments running text mode (or older AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| Template variables don't filter widgets | The widget's filter line doesn't reference the template variable | Edit the widget and confirm the search includes `$automation $version $service`. |
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
title: 스트리밍 런타임 계약
|
||||
description: Flow, 직접 LLM 호출, 대화 턴에서 정렬된 런타임 프레임을 스트리밍합니다.
|
||||
icon: tower-broadcast
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## 개요
|
||||
|
||||
CrewAI는 단순한 텍스트 청크보다 더 많은 정보가 필요한 런타임을 위해 프레임 기반 스트리밍 계약을 제공합니다. 이 계약은 Flow 생명주기 이벤트, 직접 LLM 토큰, 도구 활동, 대화 메시지, 사용자 지정 이벤트에 대해 정렬된 `StreamFrame` 객체를 방출합니다.
|
||||
|
||||
UI, 서비스 브리지, 터미널 앱, 배포 런타임을 만들 때 Flow, 채팅 턴, 직접 LLM 호출이 실행되는 동안 안정적인 구조화 이벤트 스트림이 필요하다면 이 API를 사용하세요.
|
||||
|
||||
## StreamFrame
|
||||
|
||||
모든 프레임은 같은 envelope를 가집니다:
|
||||
|
||||
```python
|
||||
from crewai.types.streaming import StreamFrame
|
||||
|
||||
frame.id # 고유 프레임 id
|
||||
frame.seq # 사용 가능한 경우 실행 로컬 순서
|
||||
frame.type # "flow_started" 같은 원본 이벤트 타입
|
||||
frame.channel # "llm", "flow", "tools", "messages", "lifecycle", "custom"
|
||||
frame.namespace # 소스/런타임 namespace
|
||||
frame.timestamp # 이벤트 timestamp
|
||||
frame.parent_id # 사용 가능한 경우 부모 이벤트 id
|
||||
frame.previous_id # 사용 가능한 경우 이전 이벤트 id
|
||||
frame.data # 이벤트 payload
|
||||
frame.event # frame.data의 alias
|
||||
frame.content # 토큰류 프레임의 출력 가능한 텍스트, 그 외에는 ""
|
||||
```
|
||||
|
||||
`channel` 필드는 소비자에서 프레임을 라우팅하는 가장 빠른 방법입니다:
|
||||
|
||||
| 채널 | 포함 내용 |
|
||||
|------|-----------|
|
||||
| `llm` | LLM 스트리밍 이벤트의 토큰 및 thinking 청크 |
|
||||
| `flow` | Flow 생명주기, 메서드 실행, 라우팅, pause/resume 이벤트 |
|
||||
| `tools` | 도구 사용 이벤트 |
|
||||
| `messages` | 대화 transcript 이벤트 |
|
||||
| `lifecycle` | 다른 채널에 속하지 않는 런타임 생명주기 이벤트 |
|
||||
| `custom` | 내장 채널에 매핑되지 않는 이벤트 |
|
||||
|
||||
`frame.type`은 원본 이벤트 타입을 보존하므로, 소비자는 채널 안에서 특정 이벤트를 처리할 수 있습니다.
|
||||
|
||||
## Flow 스트리밍
|
||||
|
||||
Flow에 `stream=True`를 설정하면 `kickoff()`가 stream session을 반환합니다:
|
||||
|
||||
```python
|
||||
from crewai.flow import Flow, start
|
||||
|
||||
|
||||
class ReportFlow(Flow):
|
||||
@start()
|
||||
def generate(self):
|
||||
return "done"
|
||||
|
||||
|
||||
flow = ReportFlow(stream=True)
|
||||
stream = flow.kickoff()
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
if chunk.type == "tool_usage_started":
|
||||
print(chunk.event["tool_name"])
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`stream.result`를 읽기 전에 stream을 소비해야 합니다. 결과를 너무 일찍 접근하면 `RuntimeError`가 발생하여, 소비자가 부분 실행을 완료된 실행으로 잘못 처리하지 않도록 합니다.
|
||||
|
||||
Flow 인스턴스에 `stream=True`를 설정하지 않고 단일 호출만 스트리밍하려면 `flow.stream_events(...)`를 직접 호출할 수도 있습니다.
|
||||
|
||||
## 채널별 필터링
|
||||
|
||||
`StreamSession`은 선택한 채널 안에서 전역 프레임 순서를 보존하는 채널 projection을 제공합니다:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
사용 가능한 projection은 다음과 같습니다:
|
||||
|
||||
| Projection | 프레임 |
|
||||
|------------|--------|
|
||||
| `stream.events` | 모든 프레임 |
|
||||
| `stream.llm` | LLM 프레임 |
|
||||
| `stream.messages` | 대화 메시지 프레임 |
|
||||
| `stream.flow` | Flow 프레임 |
|
||||
| `stream.tools` | 도구 프레임 |
|
||||
| `stream.interleave([...])` | 선택한 채널 집합 |
|
||||
|
||||
소비자가 일부 채널만 원하지만 상대 순서도 필요하다면 `stream.interleave(["flow", "llm", "messages"])`를 사용하세요.
|
||||
|
||||
## 비동기 스트리밍
|
||||
|
||||
비동기 소비자는 `astream()`을 사용하세요:
|
||||
|
||||
```python
|
||||
flow = ReportFlow()
|
||||
stream = flow.astream()
|
||||
|
||||
async with stream:
|
||||
async for chunk in stream.events:
|
||||
print(chunk.channel, chunk.type, chunk.content)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
비동기 세션은 동기 세션과 같은 projection을 제공합니다.
|
||||
|
||||
## 직접 LLM 호출 스트리밍
|
||||
|
||||
`llm.call(...)`은 계속 최종 조립 결과를 반환합니다. 구조화된 이벤트 payload를 유지하면서 청크가 도착하는 대로 반복 처리하려면 `llm.stream_events(...)`를 사용하세요:
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
stream = llm.stream_events(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Explain CrewAI streaming in two short sentences.",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`llm.stream_events(...)`는 감싼 호출 동안 일시적으로 streaming을 활성화하고, 이후 LLM의 이전 `stream` 설정을 복원합니다. provider 통합은 계속 기본 LLM stream 이벤트를 방출하며, 이 helper는 모든 LLM provider에서 그 이벤트 위에 공통 iterator API를 제공합니다.
|
||||
|
||||
## 대화 턴
|
||||
|
||||
대화형 Flow는 `stream_turn()`으로 사용자 턴 하나를 스트리밍할 수 있습니다:
|
||||
|
||||
```python
|
||||
from crewai import Flow
|
||||
from crewai.experimental.conversational import ConversationConfig, ConversationState
|
||||
|
||||
|
||||
@ConversationConfig(llm="gpt-4o-mini", defer_trace_finalization=True)
|
||||
class ChatFlow(Flow[ConversationState]):
|
||||
conversational = True
|
||||
|
||||
|
||||
flow = ChatFlow()
|
||||
stream = flow.stream_turn("What can you help me with?", session_id="session-1")
|
||||
|
||||
with stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.type == "llm_stream_chunk":
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
reply = stream.result
|
||||
```
|
||||
|
||||
`stream_turn()` 중에는 내장 대화 응답 경로가 해당 턴에 대해 LLM 토큰 스트리밍을 활성화하고 이후 LLM의 이전 `stream` 설정을 복원합니다. 자체 agent 또는 LLM 인스턴스를 만드는 사용자 지정 route handler는 토큰 단위 출력이 필요하다면 해당 LLM을 streaming으로 구성해야 합니다.
|
||||
|
||||
## 정리
|
||||
|
||||
가능하면 세션을 context manager로 사용하세요. stream이 끝나기 전에 클라이언트 연결이 끊기면 세션을 명시적으로 닫으세요:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
try:
|
||||
for frame in stream.events:
|
||||
print(frame.type)
|
||||
finally:
|
||||
if not stream.is_exhausted:
|
||||
stream.close()
|
||||
```
|
||||
|
||||
비동기 stream에서는 `await stream.aclose()`를 사용하세요.
|
||||
|
||||
## 레거시 청크 스트리밍
|
||||
|
||||
`stream=True`를 사용하는 Crew 스트리밍은 계속 [스트리밍 Crew 실행](/ko/learn/streaming-crew-execution)에 설명된 청크 중심 `CrewStreamingOutput` API를 반환합니다. 직접 `llm.call(...)` 호출도 계속 최종 LLM 결과를 반환합니다. 프레임 계약은 Flow, 직접 LLM 호출, 대화 턴, 도구, 메시지 전반에서 안정적인 이벤트 envelope가 필요한 런타임을 위한 것입니다.
|
||||
115
docs/edge/openapi/platform-v1.yaml
Normal file
@@ -0,0 +1,115 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: CrewAI Platform API
|
||||
version: v1
|
||||
description: Supported public API for CrewAI Platform.
|
||||
servers:
|
||||
- url: https://app.crewai.com
|
||||
description: CrewAI Platform
|
||||
security: []
|
||||
tags:
|
||||
- name: Status
|
||||
description: Platform health and API availability.
|
||||
paths:
|
||||
/api/v1/status:
|
||||
get:
|
||||
summary: Check API status
|
||||
operationId: getStatus
|
||||
tags:
|
||||
- Status
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
data:
|
||||
status: ok
|
||||
summary: API is available
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
additionalProperties: false
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
required:
|
||||
- status
|
||||
additionalProperties: false
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- ok
|
||||
example: ok
|
||||
components:
|
||||
schemas:
|
||||
SuccessEnvelope:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
additionalProperties: false
|
||||
properties:
|
||||
data:
|
||||
description: Endpoint-specific response payload.
|
||||
ErrorEnvelope:
|
||||
type: object
|
||||
required:
|
||||
- errors
|
||||
additionalProperties: false
|
||||
properties:
|
||||
errors:
|
||||
type: array
|
||||
minItems: 1
|
||||
items:
|
||||
$ref: '#/components/schemas/Error'
|
||||
Error:
|
||||
type: object
|
||||
description: Public API error object.
|
||||
required:
|
||||
- type
|
||||
- code
|
||||
- title
|
||||
- status
|
||||
- detail
|
||||
additionalProperties: false
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
format: uri
|
||||
enum:
|
||||
- https://docs.crewai.com/api/v1/problems/bad_request
|
||||
- https://docs.crewai.com/api/v1/problems/internal_error
|
||||
- https://docs.crewai.com/api/v1/problems/not_found
|
||||
- https://docs.crewai.com/api/v1/problems/validation_error
|
||||
example: https://docs.crewai.com/api/v1/problems/bad_request
|
||||
code:
|
||||
type: string
|
||||
enum:
|
||||
- bad_request
|
||||
- internal_error
|
||||
- not_found
|
||||
- validation_error
|
||||
example: bad_request
|
||||
title:
|
||||
type: string
|
||||
enum:
|
||||
- Bad request
|
||||
- Internal error
|
||||
- Not found
|
||||
- Validation error
|
||||
example: Bad request
|
||||
status:
|
||||
type: integer
|
||||
enum:
|
||||
- 400
|
||||
- 404
|
||||
- 422
|
||||
- 500
|
||||
example: 400
|
||||
detail:
|
||||
type: string
|
||||
example: The request is invalid.
|
||||
@@ -4,396 +4,6 @@ description: "Atualizações de produto, melhorias e correções do CrewAI"
|
||||
icon: "clock"
|
||||
mode: "wide"
|
||||
---
|
||||
<Update label="17 jul 2026">
|
||||
## v1.15.4
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.4)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Funcionalidades
|
||||
- Promover o Repositório de Habilidades para fora do status experimental
|
||||
|
||||
### Documentação
|
||||
- Adicionar Fluxos na documentação do Studio
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@jessemiller, @joaomdmoura, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 jul 2026">
|
||||
## v1.15.3
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Funcionalidades
|
||||
- Adicionar parâmetro de ID da organização ao cliente PlusAPI
|
||||
- Adicionar pontos de interceptação de etapas e reformular a documentação dos hooks de execução em torno de @on
|
||||
- Conectar pontos de interceptação de limite de execução
|
||||
- Adicionar despachador de hook de interceptação genérico
|
||||
- Executar fluxos declarativos na TUI (fallback de terminal sem interface gráfica)
|
||||
|
||||
### Correções de Bugs
|
||||
- Sincronizar evento de kickoff-completed com o resultado do hook OUTPUT
|
||||
- Corrigir atributos de agente de repositório nulos
|
||||
- Garantir que os hooks after_llm_call não quebrem a execução de ferramentas nativas
|
||||
- Evitar duplicação da resposta da rodada quando um manipulador corta o histórico
|
||||
- Tornar o cache de resultados de ferramentas opcional em vez de ativado por padrão
|
||||
- Parar de reescrever a descrição da ferramenta criada na construção
|
||||
- Expor o uso de tokens sob ambos os nomes nos resultados de agente e equipe
|
||||
- Relatar métricas de uso por chamada nos resultados de kickoff
|
||||
- Parar de reproduzir a intenção da rodada anterior quando route_turn() retorna um valor falso
|
||||
|
||||
### Documentação
|
||||
- Atualizar o agrupamento de hooks de execução e documentar todos os contextos de hooks
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 jul 2026">
|
||||
## v1.15.3a2
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a2)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir a sincronização do evento kickoff-completed com o resultado do hook OUTPUT
|
||||
|
||||
### Documentação
|
||||
- Atualizar snapshot e changelog para v1.15.3a1
|
||||
|
||||
### Atualizações de Dependências
|
||||
- Atualizar setuptools para 0.83.0 para resolver PYSEC-2026-3447
|
||||
|
||||
## Contributors
|
||||
|
||||
@lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="16 jul 2026">
|
||||
## v1.15.3a1
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.3a1)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Adicionar parâmetro de ID da organização ao cliente PlusAPI.
|
||||
- Adicionar pontos de interceptação de etapas e reformular a documentação dos hooks de execução em torno de `@on`.
|
||||
- Conectar pontos de interceptação de limites de execução.
|
||||
- Adicionar despachador genérico de hooks de interceptação.
|
||||
- Executar fluxos declarativos na TUI (fallback de terminal sem cabeça).
|
||||
- Melhorar URLs personalizadas do OpenAI.
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir atributos de agente de repositório nulos.
|
||||
- Corrigir hooks `after_llm_call` para evitar quebrar a execução de ferramentas nativas.
|
||||
- Parar de adicionar a resposta da rodada duas vezes quando um manipulador reduz o histórico.
|
||||
- Tornar o cache de resultados de ferramentas opcional em vez de ativado por padrão.
|
||||
- Parar de reescrever a descrição da ferramenta autoral na construção.
|
||||
- Expor o uso de tokens sob ambos os nomes nos resultados de agente e equipe.
|
||||
- Relatar métricas de uso por chamada nos resultados de início.
|
||||
- Parar de reproduzir a intenção da rodada anterior quando `route_turn()` retorna um valor falso.
|
||||
- Esvaziar gravações de memória antes dos eventos de início e conclusão de fluxo.
|
||||
|
||||
### Documentação
|
||||
- Agrupar hooks de execução e documentar todos os contextos de hooks.
|
||||
- Atualizar a documentação para hooks de execução.
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="07 jul 2026">
|
||||
## v1.15.2
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Puxe os modelos LLM mais recentes dinamicamente no assistente de equipe.
|
||||
- Suporte a definições de habilidades inline.
|
||||
- Adicione habilidade de autoria de definição de fluxo gerada.
|
||||
- Suporte a entradas de ação de fluxo template.
|
||||
- Adicione um helper de texto para prompts CEL de fluxo.
|
||||
- Adicione um helper de texto para exemplo de habilidade de fluxo.
|
||||
- Implemente configuração de mensagem e tratamento de feedback no AgentExecutor.
|
||||
- Adicione agentes de repositório às definições de fluxo.
|
||||
- Defina o protocolo de quadro de stream para fluxos.
|
||||
- Tipo de ferramenta e aplicativo em CrewDefinition.
|
||||
- Reponha comandos de template para a organização crewAIInc-fde.
|
||||
|
||||
### Correções de Bugs
|
||||
- Chaveie o cache do catálogo de modelos pela chave de API exata, reduza o TTL e ignore Ollama.
|
||||
- Unifique a resolução de entrada de fluxo e prompt do comando `crewai run` a partir do esquema de estado.
|
||||
- Resolva falhas de pip-audit para onnx 1.22.0 e nltk PYSEC-2026-597.
|
||||
- Garanta que estamos escrevendo a versão para fluxos.
|
||||
- Inclua aiobotocore no extra do bedrock.
|
||||
- Rejeite métodos de fluxo de autoescuta.
|
||||
- Remova a navegação de versão de docs do Edge para que novas páginas não sejam descartadas.
|
||||
|
||||
### Documentação
|
||||
- Atualize a linguagem de Regras para Políticas para corresponder às novas mudanças do painel.
|
||||
- Documente opções de agente de fluxo.
|
||||
- Adicione documentação de streaming à navegação.
|
||||
- Documente o tipo de regra Limite de Custo no Planejamento de Controle do Agente.
|
||||
- Remova referências a CREWAI_LOG_FORMAT do guia Datadog.
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@akaKuruma, @danielfsbarreto, @github-code-quality[bot], @joaomdmoura, @lorenzejay, @lucasgomide, @manisrinivasan2k1, @renatonitta, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="01 jul 2026">
|
||||
## v1.15.2a2
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a2)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Adicionar aiobotocore ao extra bedrock
|
||||
- Documentar opções do agente de fluxo
|
||||
- Adicionar helper de texto ao exemplo de habilidade de fluxo
|
||||
- Adicionar helper de texto para prompts CEL de fluxo
|
||||
- Adicionar documentação de streaming à navegação
|
||||
|
||||
### Correções de Bugs
|
||||
- Rejeitar métodos de fluxo de autoescuta
|
||||
|
||||
### Documentação
|
||||
- Atualizar snapshot e changelog para v1.15.2a1
|
||||
- Compactar arquivo AGENTS.md
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@akaKuruma, @github-code-quality[bot], @lorenzejay, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="30 jun 2026">
|
||||
## v1.15.2a1
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.2a1)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Reapontar comandos de template para a organização crewAIInc-fde
|
||||
- Suporte a definições de habilidades inline
|
||||
- Definir protocolo de quadro de fluxo para fluxos
|
||||
- Adicionar ferramenta de tipo e aplicativo em CrewDefinition
|
||||
- Adicionar habilidade de autoria de Definição de Fluxo gerada
|
||||
|
||||
### Correções de Bugs
|
||||
- Remover a navegação de versão de docs do Edge para evitar que novas páginas sejam descartadas
|
||||
|
||||
### Documentação
|
||||
- Documentar o tipo de regra Limite de Custo no Painel de Controle do Agente
|
||||
- Remover referências a CREWAI_LOG_FORMAT do guia Datadog
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@danielfsbarreto, @joaomdmoura, @lorenzejay, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="26 jun 2026">
|
||||
## v1.15.1
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.1)
|
||||
|
||||
## O Que Mudou
|
||||
|
||||
### Funcionalidades
|
||||
- Inicializar repositórios Git para projetos gerados (#6364)
|
||||
- Exigir definições explícitas de projetos CrewAI (#6358)
|
||||
- Abrir a página de implantação após o deploy pelo CLI (#6343)
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir a resolução do ID do link da página de implantação (#6365)
|
||||
- Corrigir a renderização do template de equipe em JSON (#6359)
|
||||
- Corrigir o bloqueio da versão da equipe em JSON (#6342)
|
||||
- Corrigir a bypass de redirecionamento SSRF em fetches de scraping (#6331)
|
||||
|
||||
### Documentação
|
||||
- Melhorar o posicionamento de código aberto no README (#6363)
|
||||
- Melhorar a chamada para ação na configuração do agente de codificação (#6344)
|
||||
- Adicionar snapshot e changelog para a versão 1.15.1a1 (#6362)
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@joaomdmoura, @lorenzejay, @oalami, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<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
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.15.0)
|
||||
|
||||
## O que mudou
|
||||
|
||||
### Recursos
|
||||
- Rastrear o uso de turnos de fluxo conversacional na telemetria
|
||||
- Suporte a fluxos conversacionais na TUI do CLI
|
||||
- Adicionar carregamento de fluxo declarativo unificado
|
||||
- Adicionar suporte a Flow CLI declarativo
|
||||
- Adicionar expressão if opcional a cada etapa do each.do
|
||||
- Adicionar ação de agente único às definições de Flow
|
||||
- Adicionar ações de equipe à FlowDefinition
|
||||
- Adicionar carregamento de definição de equipe inline
|
||||
- Adicionar ação composta `each` à FlowDefinition
|
||||
- Implementar suporte ao modo DMN na criação e execução de equipes
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir a aplicação de permissões apenas para o proprietário em arquivos de credenciais
|
||||
- Corrigir entradas de inicialização de estado de fluxo do esquema JSON
|
||||
- Corrigir travessia de caminho de symlink na extração de arquivos de habilidade
|
||||
- Agregar uso de token em todas as chamadas LLM
|
||||
- Remover ferramenta Exa duplicada
|
||||
- Resolver problemas de equipe JSON
|
||||
- Corrigir o manuseio de equipe JSON e aprimorar a funcionalidade de redefinição de memória
|
||||
|
||||
### Documentação
|
||||
- Atualizar a documentação de instalação e início rápido para projetos de equipe com JSON primeiro
|
||||
- Adicionar guia de integração do Datadog com painel de operações importável
|
||||
- Adicionar página "Um Cartão por Passo" no Studio
|
||||
- Adicionar instantâneas e changelogs para versões anteriores levando à v1.15.0
|
||||
|
||||
### Desempenho
|
||||
- Melhorar a experiência de inicialização do crewai run
|
||||
- Manter o progresso do método de fluxo visível para equipes aninhadas
|
||||
|
||||
### Refatoração
|
||||
- Remover `StateProxy` do acesso ao estado do fluxo
|
||||
- Consolidar `crewai run` e `crewai flow kickoff`
|
||||
- Discriminar tipos de estado da FlowDefinition
|
||||
- Conectar configuração e persistência da FlowDefinition ao tempo de execução
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@gabemilani, @github-code-quality[bot], @greysonlalonde, @iris-clawd, @jessemiller, @joaomdmoura, @lorenzejay, @lucasgomide, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="24 jun 2026">
|
||||
## v1.14.8a5
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a5)
|
||||
|
||||
## O que mudou
|
||||
|
||||
### Recursos
|
||||
- Fazer referências declarativas funcionarem em diferentes fluxos e equipes (#6326)
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir entradas de kickoff de estado de fluxo do esquema JSON (#6325)
|
||||
|
||||
### Documentação
|
||||
- Aninhar One Card por Etapa sob Crew Studio e remover banner de rollout (AGE-107) (#6317)
|
||||
- Atualizar snapshot e changelog para v1.14.8a4 (#6319)
|
||||
|
||||
### Refatoração
|
||||
- Remover `StateProxy` do acesso ao estado de fluxo (#6327)
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@jessemiller, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="24 jun 2026">
|
||||
## v1.14.8a4
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a4)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Suporte a fluxos de conversa na TUI do CLI.
|
||||
|
||||
### Correções de Bugs
|
||||
- Corrigir a travessia de caminho de symlink na extração de arquivo de habilidade.
|
||||
- Validar os caminhos de definição de fluxo declarativo.
|
||||
|
||||
### Documentação
|
||||
- Atualizar snapshot e changelog para v1.14.8a3.
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@lorenzejay, @theCyberTech, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="23 jun 2026">
|
||||
## v1.14.8a3
|
||||
|
||||
[Ver release no GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.14.8a3)
|
||||
|
||||
## O que Mudou
|
||||
|
||||
### Recursos
|
||||
- Adicionar carregamento de fluxo declarativo unificado
|
||||
- Melhorar a experiência de inicialização do crewai run
|
||||
- Consolidar `crewai run` e `crewai flow kickoff`
|
||||
- Manter o progresso do método de fluxo visível para equipes aninhadas
|
||||
- Adicionar suporte a Flow CLI declarativo
|
||||
- Permitir `@router()` como método de início de um fluxo
|
||||
- Adicionar esquemas de saída tipados para ferramentas CrewAI
|
||||
|
||||
### Correções de Bugs
|
||||
- Fixar opentelemetry em ~=1.42.0
|
||||
|
||||
### Documentação
|
||||
- Adicionar página "Uma Cartão por Etapa" no Studio
|
||||
|
||||
## Contribuidores
|
||||
|
||||
@jessemiller, @joaomdmoura, @lucasgomide, @vinibrsl
|
||||
|
||||
</Update>
|
||||
|
||||
<Update label="18 jun 2026">
|
||||
## v1.14.8a2
|
||||
|
||||
|
||||
@@ -24,23 +24,15 @@ Frequentemente você precisa de **ambos**: skills para expertise, ferramentas pa
|
||||
|
||||
## Início Rápido
|
||||
|
||||
### 1. Crie uma Skill com a CLI
|
||||
|
||||
A CLI é a forma suportada de criar uma skill — ela gera a estrutura de diretórios e um `SKILL.md` válido para você:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create code-review
|
||||
```
|
||||
|
||||
Dentro de um projeto de crew (onde o `pyproject.toml` está) isso cria `./skills/code-review/`; fora de um projeto, cria `./code-review/` no diretório atual (você pode forçar esse comportamento com `--no-project`):
|
||||
### 1. Crie um Diretório de Skill
|
||||
|
||||
```
|
||||
skills/
|
||||
└── code-review/
|
||||
├── SKILL.md # Obrigatório — instruções (template pré-preenchido)
|
||||
├── SKILL.md # Obrigatório — instruções
|
||||
├── references/ # Opcional — documentos de referência
|
||||
├── scripts/ # Opcional — scripts executáveis
|
||||
└── assets/ # Opcional — arquivos estáticos
|
||||
│ └── style-guide.md
|
||||
└── scripts/ # Opcional — scripts executáveis
|
||||
```
|
||||
|
||||
### 2. Escreva seu SKILL.md
|
||||
@@ -172,65 +164,6 @@ agent = Agent(
|
||||
|
||||
---
|
||||
|
||||
## Criando, Publicando e Instalando Skills
|
||||
|
||||
Skills têm um ciclo de vida completo gerenciado pela CLI: **crie-as com `crewai skill create`, publique-as com `crewai skill publish`** — criar diretórios à mão funciona para experimentos locais, mas a CLI é o fluxo de trabalho pretendido e mantém a estrutura e o frontmatter da sua skill válidos.
|
||||
|
||||
### Criar
|
||||
|
||||
```shell Terminal
|
||||
crewai skill create my-skill
|
||||
```
|
||||
|
||||
Gera o diretório (em `./skills/` dentro de um projeto de crew) com um `SKILL.md` de template, além dos diretórios vazios `scripts/`, `references/` e `assets/`. Edite o `SKILL.md` para definir as instruções.
|
||||
|
||||
### Publicar
|
||||
|
||||
Execute de dentro do diretório da skill (onde o `SKILL.md` está):
|
||||
|
||||
```shell Terminal
|
||||
cd skills/my-skill
|
||||
crewai skill publish
|
||||
```
|
||||
|
||||
A publicação lê `name`, `description` e `metadata.version` do frontmatter do `SKILL.md` e envia a skill para o registro da CrewAI. **Skills publicadas são sempre escopadas à sua organização** — assim como ferramentas, apenas membros da organização que publicou podem vê-las e instalá-las; não há visibilidade pública. Flags úteis:
|
||||
|
||||
| Flag | Efeito |
|
||||
| :--- | :--- |
|
||||
| `--org <slug>` | Publica sob uma organização específica (sobrepõe as configurações). |
|
||||
| `--force` | Pula a validação de estado do git (alterações não commitadas, etc.). |
|
||||
|
||||
### Instalar
|
||||
|
||||
Instale uma skill publicada pela sua referência `@org/name`:
|
||||
|
||||
```shell Terminal
|
||||
crewai skill install @acme/code-review
|
||||
```
|
||||
|
||||
Dentro de um projeto de crew, a skill é colocada em `./skills/{name}/`; fora de um projeto, vai para o cache compartilhado em `~/.crewai/skills/{org}/{name}/`.
|
||||
|
||||
Agentes também podem referenciar skills do registro diretamente — elas são resolvidas a partir do cache local (ou do diretório `skills/` do projeto) em tempo de execução:
|
||||
|
||||
```python
|
||||
agent = Agent(
|
||||
role="Senior Code Reviewer",
|
||||
goal="Review pull requests for quality and security issues",
|
||||
backstory="Staff engineer with expertise in secure coding practices.",
|
||||
skills=["@acme/code-review"], # registry ref, resolved locally
|
||||
)
|
||||
```
|
||||
|
||||
### Listar
|
||||
|
||||
```shell Terminal
|
||||
crewai skill list
|
||||
```
|
||||
|
||||
Mostra as skills instaladas tanto do diretório `./skills/` do projeto quanto do cache global, com suas versões e caminhos.
|
||||
|
||||
---
|
||||
|
||||
## Skills no Nível do Crew
|
||||
|
||||
Skills podem ser definidas no crew para aplicar a **todos os agentes**:
|
||||
|
||||
@@ -11,7 +11,7 @@ mode: "wide"
|
||||
|
||||
- [Visão Geral](/pt-BR/enterprise/features/agent-control-plane/overview)
|
||||
- **Monitoramento** *(você está aqui)*
|
||||
- [Políticas](/edge/pt-BR/enterprise/features/agent-control-plane/policies)
|
||||
- [Regras](/pt-BR/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## Visão Geral
|
||||
@@ -58,7 +58,7 @@ A sub-aba **Automações** é o detalhamento por deployment da saúde da frota.
|
||||
| **Última execução** | Tempo decorrido desde a execução mais recente. |
|
||||
| **Health Status Breakdown** | Barra empilhada com percentuais de `Critical` / `Warning` / `Healthy` para as execuções na janela. |
|
||||
| **Executions with Errors** | Total de execuções com falha na janela. |
|
||||
| **PII detection applied** | `Yes` se houver configuração de PII por deployment ou uma [política de PII](/edge/pt-BR/enterprise/features/agent-control-plane/policies) correspondente ativa. |
|
||||
| **PII detection applied** | `Yes` se houver configuração de PII por deployment ou uma [regra de PII](/pt-BR/enterprise/features/agent-control-plane/rules) correspondente ativa. |
|
||||
| **Executions** | Total de execuções na janela. |
|
||||
| **Last updated** | Quando o deployment foi re-implantado pela última vez. |
|
||||
| **Crew Version** | A versão do `crewai` reportada pelo deployment. Um ícone de informação ao lado de versões abaixo de `1.13` indica linhas que não conseguem contribuir com métricas. |
|
||||
@@ -96,8 +96,8 @@ Filtre por **LLM provider** e ordene por `Cost`, `Executions` ou `Last run`.
|
||||
<Card title="Agent Control Plane — Visão Geral" icon="book-open" href="/pt-BR/enterprise/features/agent-control-plane/overview">
|
||||
O que é o ACP, requisitos, planos suportados e RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — Políticas" icon="shield-check" href="/edge/pt-BR/enterprise/features/agent-control-plane/policies">
|
||||
Aplique políticas de PII Redaction em nível de organização em muitas automações.
|
||||
<Card title="Agent Control Plane — Regras" icon="shield-check" href="/pt-BR/enterprise/features/agent-control-plane/rules">
|
||||
Aplique regras de PII Redaction em nível de organização em muitas automações.
|
||||
</Card>
|
||||
<Card title="Traces" icon="timeline" href="/pt-BR/enterprise/features/traces">
|
||||
Aprofunde em uma única execução para ver o raciocínio do agente, chamadas de ferramentas e uso de tokens.
|
||||
|
||||
@@ -10,17 +10,17 @@ icon: "book-open"
|
||||
|
||||
- **Visão Geral** *(você está aqui)*
|
||||
- [Monitoramento](/pt-BR/enterprise/features/agent-control-plane/monitoring)
|
||||
- [Políticas](/edge/pt-BR/enterprise/features/agent-control-plane/policies)
|
||||
- [Regras](/pt-BR/enterprise/features/agent-control-plane/rules)
|
||||
</Info>
|
||||
|
||||
## Visão Geral
|
||||
|
||||
O **Agent Control Plane** (ACP) é o hub de operações para tudo que você tem rodando no CrewAI AMP. É uma tela única — dividida nas abas **Automações** e **Políticas** — que permite à sua equipe:
|
||||
O **Agent Control Plane** (ACP) é o hub de operações para tudo que você tem rodando no CrewAI AMP. É uma tela única — dividida nas abas **Automações** e **Regras** — que permite à sua equipe:
|
||||
|
||||
- Monitorar a **saúde** de cada automação ao vivo (crew ou flow), com detalhamentos `Critical` / `Warning` / `Healthy` e contagem de execuções.
|
||||
- Acompanhar o **consumo de LLM** — tokens e custo — por automação, por provedor e por modelo, com a variação em relação ao período anterior.
|
||||
- Aprofundar em qualquer automação ou provedor de modelo para ver gráficos de série temporal e detalhamentos por provedor.
|
||||
- Aplicar **Políticas** em nível de organização (hoje: PII Redaction) em muitas automações de uma só vez, em vez de editar cada deployment individualmente.
|
||||
- Aplicar **Regras** em nível de organização (hoje: PII Redaction) em muitas automações de uma só vez, em vez de editar cada deployment individualmente.
|
||||
|
||||
<Frame>
|
||||

|
||||
@@ -33,7 +33,7 @@ O **Agent Control Plane** (ACP) é o hub de operações para tudo que você tem
|
||||
As duas abas respondem a duas perguntas distintas:
|
||||
|
||||
- **Automações** — *"Como minha frota está se comportando agora e quanto está me custando?"* Veja [Monitoramento](/pt-BR/enterprise/features/agent-control-plane/monitoring).
|
||||
- **Políticas** — *"Como aplico uma política (por exemplo, PII redaction) em muitos deployments sem precisar reimplantar cada um?"* Veja [Políticas](/edge/pt-BR/enterprise/features/agent-control-plane/policies).
|
||||
- **Regras** — *"Como aplico uma política (por exemplo, PII redaction) em muitos deployments sem precisar reimplantar cada um?"* Veja [Regras](/pt-BR/enterprise/features/agent-control-plane/rules).
|
||||
|
||||
## Requisitos
|
||||
|
||||
@@ -42,11 +42,11 @@ As duas abas respondem a duas perguntas distintas:
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
**Plano Enterprise ou Ultra** é necessário para criar ou editar [Políticas](/edge/pt-BR/enterprise/features/agent-control-plane/policies). Organizações em planos inferiores ainda podem abrir a aba Políticas e visualizar políticas existentes, mas o editor é renderizado em modo somente leitura, com um selo "Enterprise" de bloqueio e o alerta *"PII Redaction policies require an Enterprise plan."* O Monitoramento (a aba Automações) está disponível em todos os planos em que o recurso esteja habilitado.
|
||||
**Plano Enterprise ou Ultra** é necessário para criar ou editar [Regras](/pt-BR/enterprise/features/agent-control-plane/rules). Organizações em planos inferiores ainda podem abrir a aba Regras e visualizar regras existentes, mas o editor é renderizado em modo somente leitura, com um selo "Enterprise" de bloqueio e o alerta *"PII Redaction rules require an Enterprise plan."* O Monitoramento (a aba Automações) está disponível em todos os planos em que o recurso esteja habilitado.
|
||||
</Warning>
|
||||
|
||||
- O recurso **Agent Control Plane** precisa estar habilitado para sua organização. Se você não o vê na barra lateral, peça ao owner da conta para solicitar a habilitação.
|
||||
- Dentro do ACP, o [RBAC](/pt-BR/enterprise/features/rbac) controla o acesso: `read` para visualizar o dashboard e as políticas, `manage` para criar, editar, ligar/desligar ou excluir políticas.
|
||||
- Dentro do ACP, o [RBAC](/pt-BR/enterprise/features/rbac) controla o acesso: `read` para visualizar o dashboard e as regras, `manage` para criar, editar, ligar/desligar ou excluir regras.
|
||||
- Todos os gráficos e tabelas podem ser ajustados para **Últimas 24 horas**, **Última Semana** ou **Últimos 30 dias** usando o seletor de tempo no canto superior direito. As variações (`↑ 8 vs ontem`, `↓ $20.57 vs ontem`, etc.) comparam a janela selecionada com a janela anterior de mesma duração.
|
||||
|
||||
## O que você pode fazer aqui
|
||||
@@ -55,7 +55,7 @@ As duas abas respondem a duas perguntas distintas:
|
||||
<Card title="Monitoramento" icon="gauge" href="/pt-BR/enterprise/features/agent-control-plane/monitoring">
|
||||
Acompanhe a saúde da frota e o gasto com LLM com cards de métricas, um sankey interativo, tabelas por automação e painéis laterais de detalhamento para qualquer automação ou provedor.
|
||||
</Card>
|
||||
<Card title="Políticas" icon="shield-check" href="/edge/pt-BR/enterprise/features/agent-control-plane/policies">
|
||||
<Card title="Regras" icon="shield-check" href="/pt-BR/enterprise/features/agent-control-plane/rules">
|
||||
Aplique políticas de PII Redaction em nível de organização, com escopo por ferramentas e tags. As mudanças entram em vigor na próxima execução — sem necessidade de re-implantação.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -67,10 +67,10 @@ As duas abas respondem a duas perguntas distintas:
|
||||
Aprofunde em uma única execução para ver o raciocínio do agente, chamadas de ferramentas e uso de tokens.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/pt-BR/enterprise/features/rbac">
|
||||
Gerencie quem pode ler o Agent Control Plane e quem pode editar políticas.
|
||||
Gerencie quem pode ler o Agent Control Plane e quem pode editar regras.
|
||||
</Card>
|
||||
<Card title="PII Redaction para Traces" icon="lock" href="/pt-BR/enterprise/features/pii-trace-redactions">
|
||||
Catálogo de entidades e configuração de PII por deployment, referenciados pelas Políticas.
|
||||
Catálogo de entidades e configuração de PII por deployment, referenciados pelas Regras.
|
||||
</Card>
|
||||
<Card title="Deploy no AMP" icon="rocket" href="/pt-BR/enterprise/guides/deploy-to-amp">
|
||||
Implante uma crew em uma versão do crewAI que suporta o Agent Control Plane.
|
||||
@@ -78,5 +78,5 @@ As duas abas respondem a duas perguntas distintas:
|
||||
</CardGroup>
|
||||
|
||||
<Card title="Precisa de ajuda?" icon="headset" href="mailto:support@crewai.com">
|
||||
Entre em contato com nosso time de suporte para interpretar métricas ou desenhar políticas.
|
||||
Entre em contato com nosso time de suporte para interpretar métricas ou desenhar regras.
|
||||
</Card>
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
---
|
||||
title: "Configure as Políticas"
|
||||
description: "Aplique políticas em nível de organização em muitas automações a partir de um único lugar."
|
||||
sidebarTitle: "Políticas"
|
||||
icon: "shield-check"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**Navegação da Documentação do ACP (Beta)**
|
||||
|
||||
- [Visão Geral](/pt-BR/enterprise/features/agent-control-plane/overview)
|
||||
- [Monitoramento](/pt-BR/enterprise/features/agent-control-plane/monitoring)
|
||||
- **Políticas** *(você está aqui)*
|
||||
</Info>
|
||||
|
||||
## Visão Geral
|
||||
|
||||
As Políticas permitem aplicar políticas — hoje: **PII Redaction** — em muitas automações de uma só vez, em vez de configurar cada deployment individualmente. Abra a aba **Políticas** no [Agent Control Plane](/pt-BR/enterprise/features/agent-control-plane/overview) para gerenciá-las.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Cada card de política mostra o nome, a descrição, o **escopo** ao qual a política se aplica (ferramentas e tags selecionadas) e a contagem de **automações engajadas** — deployments que atualmente correspondem ao escopo. O toggle à direita ativa ou desativa a política sem excluí-la.
|
||||
|
||||
## Requisitos
|
||||
|
||||
<Warning>
|
||||
**Plano Enterprise ou Ultra** é necessário para criar ou editar políticas de PII Redaction. Organizações em planos inferiores ainda podem abrir a aba Políticas e visualizar políticas existentes, mas o editor é renderizado em modo somente leitura, com um selo "Enterprise" de bloqueio e o alerta *"PII Redaction policies require an Enterprise plan."* — entre em contato com o owner da sua conta ou com vendas para fazer upgrade.
|
||||
</Warning>
|
||||
|
||||
- O recurso **Agent Control Plane** precisa estar habilitado para sua organização. Veja [Visão Geral — Requisitos](/pt-BR/enterprise/features/agent-control-plane/overview#requisitos).
|
||||
- A permissão `manage` no [RBAC](/pt-BR/enterprise/features/rbac) sobre o Agent Control Plane é necessária para criar, editar, ligar/desligar ou excluir políticas. A permissão `read` é suficiente para visualizá-las.
|
||||
- Todas as mudanças de políticas são versionadas para auditoria.
|
||||
|
||||
## Tipos de política disponíveis
|
||||
|
||||
| Tipo | O que faz |
|
||||
|------|---------------|
|
||||
| **PII Redaction** | Aplica PII redaction às execuções de cada automação correspondente, usando o mesmo catálogo de entidades e recognizers customizados documentados em [PII Redaction para Traces](/pt-BR/enterprise/features/pii-trace-redactions). |
|
||||
|
||||
Mais tipos de políticas serão adicionados ao longo do tempo.
|
||||
|
||||
## Criando uma política
|
||||
|
||||
<Frame>
|
||||
<img src="/images/enterprise/acp-policies-new-side-panel.png" alt="Painel lateral de edição de política com condições e tipo de máscara de PII" width="450" />
|
||||
</Frame>
|
||||
|
||||
<Steps>
|
||||
<Step title="Abra o editor">
|
||||
Clique em **+ Create new** no canto superior direito da aba Políticas, ou em **View Details** em um card de política existente.
|
||||
</Step>
|
||||
|
||||
<Step title="Dê um nome e descreva a política">
|
||||
Dê à política um nome claro (ex.: *Mask PII (CC)*) e uma descrição explicando quando ela se aplica. Ambos aparecem no card da política e no modal de Automações Engajadas.
|
||||
</Step>
|
||||
|
||||
<Step title="Escolha o tipo">
|
||||
Hoje só **PII Redaction** está disponível.
|
||||
</Step>
|
||||
|
||||
<Step title="Defina as condições">
|
||||
As condições decidem quais automações a política engaja. Ambas são opcionais e usam a semântica de **igualdade de conjuntos**:
|
||||
|
||||
- **Tools** — apenas automações cujo conjunto de ferramentas **corresponde exatamente** às ferramentas selecionadas serão engajadas. Selecione entre apps do Studio, MCPs, ferramentas OSS e ferramentas do Tool Repository.
|
||||
- **Automations** — apenas automações cujo conjunto de tags **corresponde exatamente** às tags selecionadas serão engajadas.
|
||||
|
||||
Deixar um seletor vazio significa "sem filtro nesta dimensão". Deixar ambos vazios significa que a política se aplica a **todas** as automações da organização.
|
||||
</Step>
|
||||
|
||||
<Step title="Configure a tabela PII Mask Type">
|
||||
Marque cada tipo de entidade que deseja cobrir e escolha **Mask** (substitui pelo rótulo da entidade, ex.: `<CREDIT_CARD>`) ou **Redact** (remove o texto correspondente por completo). Veja [PII Redaction para Traces](/pt-BR/enterprise/features/pii-trace-redactions) para o catálogo completo de entidades e como adicionar recognizers customizados em nível de organização.
|
||||
</Step>
|
||||
|
||||
<Step title="Salve">
|
||||
A política se aplica a **futuras** execuções de cada automação engajada assim que você salva. Nenhuma re-implantação é necessária.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Automações engajadas
|
||||
|
||||
Clique em **Engaged N automations** em qualquer card de política para ver exatamente quais deployments a política está correspondendo no momento, junto com a última execução de cada um.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Esta é a forma mais rápida de validar o escopo de uma política antes de habilitá-la — por exemplo, para confirmar que uma política com escopo na tag `production` não está acidentalmente correspondendo a um deployment de staging.
|
||||
|
||||
## Políticas em nível de organização vs configurações por deployment
|
||||
|
||||
A PII Redaction pode ser configurada em dois lugares:
|
||||
|
||||
- **Por deployment** — em **Settings → PII Protection** em cada deployment individual ([guia](/pt-BR/enterprise/features/pii-trace-redactions))
|
||||
- **Em nível de organização** — como uma Política nesta página
|
||||
|
||||
Quando o escopo de uma política habilitada em nível de organização corresponde a um deployment, a configuração de entidades da política **sobrescreve** as configurações de PII pertencentes ao deployment para as execuções daquele deployment — a política se torna a fonte única da verdade enquanto está vinculada. Desabilite ou desvincule a política (ou altere o escopo para que ela não corresponda mais) e o deployment volta às suas próprias configurações de PII Protection.
|
||||
|
||||
Prefira políticas em nível de organização quando quiser impor uma política consistente em muitos deployments; reserve a configuração por deployment para exceções pontuais.
|
||||
|
||||
## Relacionados
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Agent Control Plane — Visão Geral" icon="book-open" href="/pt-BR/enterprise/features/agent-control-plane/overview">
|
||||
O que é o ACP, requisitos, planos suportados e RBAC.
|
||||
</Card>
|
||||
<Card title="Agent Control Plane — Monitoramento" icon="gauge" href="/pt-BR/enterprise/features/agent-control-plane/monitoring">
|
||||
Acompanhe automações e consumo de LLM em toda a sua frota.
|
||||
</Card>
|
||||
<Card title="PII Redaction para Traces" icon="lock" href="/pt-BR/enterprise/features/pii-trace-redactions">
|
||||
Catálogo de entidades, recognizers customizados e configuração por deployment.
|
||||
</Card>
|
||||
<Card title="RBAC" icon="users" href="/pt-BR/enterprise/features/rbac">
|
||||
Gerencie quem pode criar ou editar políticas.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
<Card title="Precisa de ajuda?" icon="headset" href="mailto:support@crewai.com">
|
||||
Entre em contato com nosso time de suporte para ajudar a desenhar políticas para a sua organização.
|
||||
</Card>
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**Lançamento na quarta-feira, 24 de junho.** O canvas do Studio passa a exibir um card por etapa, em vez de nós separados para tarefa e agente, para simplificar o canvas à medida que adicionamos novas funcionalidades em breve. Suas automações existentes continuam funcionando sem nenhuma alteração necessária — cada configuração de tarefa e de agente continua disponível, apenas organizada em um único card.
|
||||
</Note>
|
||||
|
||||
## Visão geral
|
||||
|
||||
No canvas do Studio, cada etapa de trabalho é representada por um **único card**. O card combina dois elementos que antes ficavam em nós separados:
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
---
|
||||
title: Flows no Studio
|
||||
description: "Crie fluxos de trabalho orientados a eventos que combinam controle determinístico passo a passo com inteligência agêntica — sem escrever código."
|
||||
icon: "diagram-project"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
<Info>
|
||||
**Lançamento em andamento**: Flows no Studio está sendo liberado gradualmente durante a semana de 20 de julho de 2026. Se você ainda não vê a opção Flows no Studio, o recurso ainda não chegou à sua organização — volte em breve.
|
||||
</Info>
|
||||
|
||||
## Visão geral
|
||||
|
||||
O Studio agora permite criar **Flows** além de Crews. Flows são fluxos de trabalho orientados a eventos em que você controla exatamente quais etapas são executadas, em que ordem e sob quais condições — enquanto delega o trabalho inteligente dentro de cada etapa a agentes de IA.
|
||||
|
||||
Para criar um Flow, abra o Studio, descreva sua automação e selecione **Flows** no seletor ao lado da caixa de prompt.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
## Por que Flows?
|
||||
|
||||
Crews são ótimos quando você quer que uma equipe de agentes colabore de forma autônoma em direção a um objetivo. Mas muitas automações do mundo real precisam de mais previsibilidade: buscar estes dados primeiro, depois resumi-los, depois publicar o resultado — sempre, nessa ordem.
|
||||
|
||||
Flows oferecem os dois:
|
||||
|
||||
- **Determinismo onde importa**: as etapas são executadas em uma sequência definida com ramificações explícitas, tornando as execuções previsíveis, repetíveis e fáceis de depurar.
|
||||
- **Inteligência onde você precisa**: cada etapa é executada por um agente (ou por um crew inteiro), então o trabalho dentro da etapa — resumir, pontuar, redigir, decidir — se beneficia de todo o raciocínio do LLM.
|
||||
|
||||
Essa combinação é o que torna os Flows adequados para automações em produção: a estrutura é garantida e a agência fica restrita às etapas que precisam dela.
|
||||
|
||||
## Criando um Flow
|
||||
|
||||
Descreva o que você quer em linguagem natural e o Studio Assistant projeta o Flow para você — criando as etapas, conectando-as e configurando os agentes e as integrações de apps de que cada etapa precisa. O canvas à direita mostra o fluxo resultante como nós conectados, e você pode continuar iterando por conversa ou editar qualquer nó diretamente.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Quando estiver pronto, use **Run** para testar o Flow de ponta a ponta, inspecione os resultados nas abas **Output** e **Traces** e faça o **Deploy** quando estiver estável. Você também pode compartilhar o projeto (**Share**) ou baixar o código-fonte (**Download**).
|
||||
|
||||
## Tipos de nós
|
||||
|
||||
Flows são compostos por três tipos principais de nós. Cada nó é uma etapa do fluxo de trabalho, e você pode combiná-los livremente.
|
||||
|
||||
### Single Agent
|
||||
|
||||
Um nó Single Agent executa um agente em uma única tarefa focada — ideal para etapas bem delimitadas, como buscar dados de uma integração, transformar conteúdo ou publicar uma mensagem.
|
||||
|
||||
Ao clicar em um nó de agente, você abre sua configuração completa:
|
||||
|
||||
- **Task**: o que essa etapa deve realizar e qual saída deve produzir
|
||||
- **Profile**: o papel (role), o objetivo (goal) e a história (backstory) do agente
|
||||
- **Model**: qual LLM alimenta o agente
|
||||
- **Apps**: as integrações que o agente pode usar (ex.: Linear, Slack, HubSpot)
|
||||
- **Runtime Controls**: opções para planejar antes de executar, delegação e memória
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
### Crews
|
||||
|
||||
Um nó Crew incorpora um crew inteiro — múltiplos agentes colaborando em múltiplas tarefas — como uma única etapa do seu Flow. Use-o quando uma etapa for rica demais para um único agente, como agrupar e resumir dados por equipe e depois formatar o resultado para entrega.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Ao abrir um nó Crew, você vê sua estrutura interna: as tarefas que ele executa, os agentes atribuídos a cada uma e os apps que eles usam. O crew é executado de forma autônoma dentro da etapa e entrega sua saída ao próximo nó do Flow.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Esse é o padrão determinístico-mais-agêntico em ação: o Flow garante *quando* o crew é executado, e o crew traz inteligência colaborativa para *como* o trabalho é feito.
|
||||
|
||||
### Router
|
||||
|
||||
Um nó Router ramifica o Flow com base em condições, para que resultados diferentes sigam caminhos diferentes. Por exemplo, um Flow de roteamento de leads pode pontuar os leads recebidos e encaminhar os de alta qualidade para uma etapa de atribuição de vendas, enquanto registra os demais para nutrição futura.
|
||||
|
||||
<Frame>
|
||||

|
||||
</Frame>
|
||||
|
||||
Os Routers são o que torna os Flows verdadeiramente orientados a eventos: o mesmo fluxo de trabalho lida com todos os casos, mas cada execução segue apenas o ramo que seus dados justificam — sem etapas desperdiçadas, sem ambiguidade sobre o que acontece a seguir.
|
||||
|
||||
## Sincronização com o Agent Repository
|
||||
|
||||
Os agentes que você cria em Flows não precisam ficar presos a um único projeto. Todo nó de agente inclui um botão **Publish to Agent Repository**, que salva o agente — papel, objetivo, história, modelo e configuração — no [Agent Repository](/pt-BR/enterprise/features/agent-repositories) da sua organização.
|
||||
|
||||
Isso funciona nos dois sentidos:
|
||||
|
||||
- **Publicar**: promova um agente refinado em um Flow para o repositório, para que outras equipes e projetos possam reutilizá-lo.
|
||||
- **Importar**: traga um agente existente do repositório para um novo Flow em vez de recriá-lo do zero.
|
||||
|
||||
Como os agentes do repositório são sincronizados em toda a organização, uma melhoria feita em um agente compartilhado beneficia todos os Flows que o utilizam — mantendo o comportamento dos agentes consistente, governado e sem duplicação de esforço.
|
||||
|
||||
## Boas práticas
|
||||
|
||||
- **Escolha um Flow** quando a automação tiver uma sequência clara ou lógica de ramificação; escolha um Crew quando o caminho até o objetivo for aberto.
|
||||
- **Mantenha as tarefas dos agentes focadas** — um nó Single Agent com uma descrição de tarefa enxuta é mais confiável do que um agente encarregado de três coisas.
|
||||
- **Use Routers para tratar todos os casos explicitamente**, inclusive o caminho "não fazer nada" (ex.: registrar leads ignorados), para que as execuções fiquem totalmente contabilizadas.
|
||||
- **Publique agentes estáveis no Agent Repository** para que sua organização construa uma biblioteca compartilhada em vez de cópias paralelas.
|
||||
- **Teste com Run e inspecione os Traces** antes do deploy para detectar problemas de integração ou de prompt com antecedência.
|
||||
|
||||
## Relacionados
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="Crew Studio" href="/pt-BR/enterprise/features/crew-studio" icon="pencil">
|
||||
Crie Crews no Studio.
|
||||
</Card>
|
||||
<Card title="Agent Repositories" href="/pt-BR/enterprise/features/agent-repositories" icon="people-group">
|
||||
Compartilhe e reutilize agentes em toda a sua organização.
|
||||
</Card>
|
||||
<Card title="Conceitos de Flows" href="/pt-BR/concepts/flows" icon="diagram-project">
|
||||
Saiba como os Flows funcionam no framework CrewAI.
|
||||
</Card>
|
||||
<Card title="Tools & Integrations" href="/pt-BR/enterprise/features/tools-and-integrations" icon="plug">
|
||||
Conecte os apps que seus agentes usam.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -21,11 +21,12 @@ CrewAI supports two log-ingestion paths to Datadog — both are first-class and
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Datadog Agent">
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. Each log event ships as a single billable line with structured attributes — see the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
The Datadog Agent runs alongside your CrewAI containers (typically as a DaemonSet on Kubernetes) and tails their stdout. With `CREWAI_LOG_FORMAT=json` set, each log event ships as a single billable line with structured attributes.
|
||||
|
||||
**Setup:**
|
||||
1. Run the Datadog Agent next to your CrewAI containers — see [Datadog's deployment docs](https://docs.datadoghq.com/agent/) for Kubernetes, ECS, or VM setup. Enable log collection (`logs_enabled: true`) and container log collection (`logs_config.container_collect_all: true`).
|
||||
2. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
2. Set `CREWAI_LOG_FORMAT=json` as an **automation environment variable** in CrewAI AMP (open your automation → **Settings → Environment Variables**) so each log event is a single line instead of a multi-line traceback. AMP propagates the value to every container in the deployment (API + workers) — don't set it on the container or host directly. See [Enabling JSON output](#enabling-json-output) below for the AMP UI walkthrough and the [log schema reference](#log-schema-reference) for the full field contract.
|
||||
3. Confirm logs arrive in Datadog Logs with the JSON fields parsed — see [Verify ingestion](#verify-ingestion).
|
||||
|
||||
**Pick this path if** you already operate Datadog Agents (e.g. for infrastructure metrics), or your log volume makes per-event ingestion cost a real concern — collapsing tracebacks into single events keeps Agent ingestion cheap at scale.
|
||||
</Tab>
|
||||
@@ -56,10 +57,10 @@ Either path lands the same structured facets in Datadog (`@automation_id`, `@kic
|
||||
## Log schema reference
|
||||
|
||||
<Info>
|
||||
This schema applies to the **Datadog Agent path** — structured stdout JSON logs emitted by every CrewAI worker container. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
This schema applies to the **Datadog Agent path** — stdout JSON logs produced when `CREWAI_LOG_FORMAT=json` is set. Logs delivered via the **Datadog OTLP intake** use OpenTelemetry attribute names and may differ; see [OpenTelemetry Export](./capture_telemetry_logs).
|
||||
</Info>
|
||||
|
||||
Every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
When `CREWAI_LOG_FORMAT=json` is set, every log event is emitted as a **single JSON object per line** to stdout, with internal newlines escaped. The format is plain JSON — Datadog parses it natively, and the same payload is also consumable by Splunk, Loki, Elasticsearch, and CloudWatch without custom log pipelines.
|
||||
|
||||
### Why JSON output
|
||||
|
||||
@@ -78,6 +79,20 @@ Every log event is emitted as a **single JSON object per line** to stdout, with
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Enabling JSON output
|
||||
|
||||
`CREWAI_LOG_FORMAT=json` must be set as an **automation environment variable** in CrewAI AMP — it is **not** a container, host, or Docker setting. Open your automation in AMP, click the **Settings** icon, and add the variable under the **Environment Variables** section. AMP applies the value to every container in the deployment (API + workers) on the next restart. See [Update Your Crew](./update-crew) for the full UI walkthrough with screenshots.
|
||||
|
||||
```shell
|
||||
CREWAI_LOG_FORMAT=json
|
||||
```
|
||||
|
||||
Restart the deployment to pick up the change. Every log line on stdout from that point on is a single JSON object.
|
||||
|
||||
<Note>
|
||||
The default value is `text`, which preserves the legacy human-readable line format byte-for-byte. Setting any value other than `json` falls back to text mode. There is no migration step — the variable is read at process start and the format switches immediately.
|
||||
</Note>
|
||||
|
||||
### Example events
|
||||
|
||||
A single info-level log inside an active automation kickoff:
|
||||
@@ -120,7 +135,7 @@ An error with a Python exception is collapsed into a single event with the trace
|
||||
}
|
||||
```
|
||||
|
||||
Without JSON output, that same error would produce ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
The same error in legacy text mode would have produced ~25 separate log events (one per traceback line) — all of which the backend would bill and index individually.
|
||||
|
||||
### Schema v1 fields
|
||||
|
||||
@@ -222,7 +237,7 @@ Open [Logs Explorer](https://app.datadoghq.com/logs) and run a query that matche
|
||||
<Tab title="Datadog Agent">
|
||||
Search `service:crewai* @schema:v1`. You should see structured logs with the JSON fields parsed into Datadog facets. Pick a recent event and verify it has `@automation_id`, `@kickoff_id`, `@execution_id`, `@crewai_version`, and (when running inside a span) `@trace_id` / `@span_id` populated.
|
||||
|
||||
If nothing appears, confirm the Datadog Agent is tailing container stdout and that the deployment is running a recent enough CrewAI Enterprise build.
|
||||
If nothing appears, confirm `CREWAI_LOG_FORMAT=json` is set under your automation's **Environment Variables** in AMP, the deployment was restarted after the change, and the Datadog Agent is tailing container stdout.
|
||||
</Tab>
|
||||
<Tab title="Datadog OTLP intake">
|
||||
Search `source:otlp service:crewai*`. OTLP attributes land with their OpenTelemetry names (`automation_id`, `crewai.kickoff.id`, etc.) rather than the stdout JSON keys, but they map to the same dashboard facets after [facet promotion](#prerequisite-promote-facets).
|
||||
@@ -265,7 +280,7 @@ The `$service` template variable defaults to `*` and will catch every CrewAI dep
|
||||
| All widgets show "No data" | Facets aren't promoted | Re-do the [Promote facets](#prerequisite-promote-facets) step. Datadog won't query against an un-promoted field. |
|
||||
| Error Rate widget shows `NaN` | No executions in the time window | Either no traffic, or `@execution_id` isn't faceted. Expand the time range and re-check facets. |
|
||||
| Throughput chart is flat at the same value | Logs aren't reaching Datadog | Search `service:crewai*` in Logs Explorer. If nothing shows, verify the Datadog Agent is running (Agent path) or the OTel collector endpoint is correct (OTLP path). |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments (pre-structured-logs AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| `crewai_version` shows fewer values than expected | Some containers predate the structured-logs work | The `crewai_version` field was added alongside JSON output. Older deployments running text mode (or older AMP builds) won't emit it. Upgrade those deployments to pick up the field. See the [log schema reference](#log-schema-reference) for the full field contract. |
|
||||
| Template variables don't filter widgets | The widget's filter line doesn't reference the template variable | Edit the widget and confirm the search includes `$automation $version $service`. |
|
||||
|
||||
## Next steps
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
---
|
||||
title: Contrato de Streaming do Runtime
|
||||
description: Transmita frames ordenados do runtime a partir de Flows, chamadas diretas de LLM e turnos conversacionais.
|
||||
icon: tower-broadcast
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## Visão geral
|
||||
|
||||
O CrewAI expõe um contrato de streaming baseado em frames para runtimes que precisam de mais do que chunks de texto simples. O contrato emite objetos `StreamFrame` ordenados para eventos de ciclo de vida de Flow, tokens de LLM diretos, atividade de ferramentas, mensagens de conversa e eventos personalizados.
|
||||
|
||||
Use esta API ao criar uma UI, ponte de serviço, aplicativo de terminal ou runtime de implantação que precise de um fluxo estável de eventos estruturados enquanto um Flow, turno de chat ou chamada direta de LLM está em execução.
|
||||
|
||||
## StreamFrame
|
||||
|
||||
Todo frame tem o mesmo envelope:
|
||||
|
||||
```python
|
||||
from crewai.types.streaming import StreamFrame
|
||||
|
||||
frame.id # id único do frame
|
||||
frame.seq # ordem local da execução, quando disponível
|
||||
frame.type # tipo do evento de origem, como "flow_started"
|
||||
frame.channel # "llm", "flow", "tools", "messages", "lifecycle" ou "custom"
|
||||
frame.namespace # namespace de origem/runtime
|
||||
frame.timestamp # timestamp do evento
|
||||
frame.parent_id # id do evento pai, quando disponível
|
||||
frame.previous_id # id do evento anterior, quando disponível
|
||||
frame.data # payload do evento
|
||||
frame.event # alias para frame.data
|
||||
frame.content # texto imprimível para frames de token, caso contrário ""
|
||||
```
|
||||
|
||||
O campo `channel` é a forma mais rápida de rotear frames em consumidores:
|
||||
|
||||
| Canal | Contém |
|
||||
|-------|--------|
|
||||
| `llm` | Tokens e chunks de raciocínio de eventos de streaming de LLM |
|
||||
| `flow` | Ciclo de vida do Flow, execução de métodos, roteamento e eventos de pausa/retomada |
|
||||
| `tools` | Eventos de uso de ferramentas |
|
||||
| `messages` | Eventos do transcript da conversa |
|
||||
| `lifecycle` | Eventos de ciclo de vida do runtime que não pertencem a outro canal |
|
||||
| `custom` | Eventos que não mapeiam para um canal integrado |
|
||||
|
||||
`frame.type` preserva o tipo do evento de origem, para que consumidores possam tratar eventos específicos dentro de um canal.
|
||||
|
||||
## Transmitir um Flow
|
||||
|
||||
Defina `stream=True` em um Flow para fazer `kickoff()` retornar uma sessão de stream:
|
||||
|
||||
```python
|
||||
from crewai.flow import Flow, start
|
||||
|
||||
|
||||
class ReportFlow(Flow):
|
||||
@start()
|
||||
def generate(self):
|
||||
return "done"
|
||||
|
||||
|
||||
flow = ReportFlow(stream=True)
|
||||
stream = flow.kickoff()
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
if chunk.type == "tool_usage_started":
|
||||
print(chunk.event["tool_name"])
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
Você deve consumir o stream antes de ler `stream.result`. Acessar o resultado cedo demais gera um `RuntimeError`, para que consumidores não tratem uma execução parcial como concluída.
|
||||
|
||||
Você também pode chamar `flow.stream_events(...)` diretamente quando quiser streaming para uma única invocação sem definir `stream=True` na instância do Flow.
|
||||
|
||||
## Filtrar por canal
|
||||
|
||||
`StreamSession` expõe projeções por canal que preservam a ordem global dos frames dentro do canal selecionado:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
with stream:
|
||||
for frame in stream.llm:
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
As projeções disponíveis são:
|
||||
|
||||
| Projeção | Frames |
|
||||
|----------|--------|
|
||||
| `stream.events` | Todos os frames |
|
||||
| `stream.llm` | Frames de LLM |
|
||||
| `stream.messages` | Frames de mensagens de conversa |
|
||||
| `stream.flow` | Frames de Flow |
|
||||
| `stream.tools` | Frames de ferramentas |
|
||||
| `stream.interleave([...])` | Um conjunto selecionado de canais |
|
||||
|
||||
Use `stream.interleave(["flow", "llm", "messages"])` quando um consumidor quiser apenas alguns canais, mas ainda precisar da ordem relativa entre eles.
|
||||
|
||||
## Streaming assíncrono
|
||||
|
||||
Use `astream()` para consumidores assíncronos:
|
||||
|
||||
```python
|
||||
flow = ReportFlow()
|
||||
stream = flow.astream()
|
||||
|
||||
async with stream:
|
||||
async for chunk in stream.events:
|
||||
print(chunk.channel, chunk.type, chunk.content)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
A sessão assíncrona tem as mesmas projeções da sessão síncrona.
|
||||
|
||||
## Transmitir uma chamada direta de LLM
|
||||
|
||||
`llm.call(...)` ainda retorna o resultado final montado. Use `llm.stream_events(...)` quando quiser iterar pelos chunks conforme eles chegam, mantendo o payload estruturado do evento:
|
||||
|
||||
```python
|
||||
from crewai import LLM
|
||||
|
||||
|
||||
llm = LLM(model="gpt-4o-mini")
|
||||
stream = llm.stream_events(
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Explain CrewAI streaming in two short sentences.",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
with stream:
|
||||
for chunk in stream:
|
||||
print(chunk.content, end="", flush=True)
|
||||
|
||||
result = stream.result
|
||||
```
|
||||
|
||||
`llm.stream_events(...)` ativa temporariamente o streaming para a chamada encapsulada e restaura a configuração anterior de `stream` do LLM depois. As integrações de provedores continuam emitindo os eventos de stream de LLM subjacentes; esse helper fornece uma API de iterador comum sobre esses eventos para todos os provedores de LLM.
|
||||
|
||||
## Turnos conversacionais
|
||||
|
||||
Flows conversacionais podem transmitir um turno de usuário com `stream_turn()`:
|
||||
|
||||
```python
|
||||
from crewai import Flow
|
||||
from crewai.experimental.conversational import ConversationConfig, ConversationState
|
||||
|
||||
|
||||
@ConversationConfig(llm="gpt-4o-mini", defer_trace_finalization=True)
|
||||
class ChatFlow(Flow[ConversationState]):
|
||||
conversational = True
|
||||
|
||||
|
||||
flow = ChatFlow()
|
||||
stream = flow.stream_turn("What can you help me with?", session_id="session-1")
|
||||
|
||||
with stream:
|
||||
for frame in stream.events:
|
||||
if frame.channel == "llm" and frame.type == "llm_stream_chunk":
|
||||
print(frame.content, end="", flush=True)
|
||||
|
||||
reply = stream.result
|
||||
```
|
||||
|
||||
Durante `stream_turn()`, o caminho de resposta conversacional integrado ativa o streaming de tokens de LLM para esse turno e restaura a configuração anterior de `stream` do LLM depois. Handlers de rota personalizados que criam seus próprios agentes ou instâncias de LLM devem configurar esses LLMs para streaming se precisarem de saída em nível de token.
|
||||
|
||||
## Limpeza
|
||||
|
||||
Use a sessão como gerenciador de contexto quando possível. Se um cliente se desconectar antes de o stream ser esgotado, feche a sessão explicitamente:
|
||||
|
||||
```python
|
||||
stream = flow.stream_events()
|
||||
|
||||
try:
|
||||
for frame in stream.events:
|
||||
print(frame.type)
|
||||
finally:
|
||||
if not stream.is_exhausted:
|
||||
stream.close()
|
||||
```
|
||||
|
||||
Para streams assíncronos, use `await stream.aclose()`.
|
||||
|
||||
## Streaming de chunks legado
|
||||
|
||||
O streaming de Crew com `stream=True` ainda retorna a API orientada a chunks `CrewStreamingOutput` descrita em [Streaming da Execução de Crew](/pt-BR/learn/streaming-crew-execution). Chamadas diretas `llm.call(...)` ainda retornam o resultado final do LLM. O contrato de frames é destinado a runtimes que precisam de um envelope de evento estável em Flows, chamadas diretas de LLM, turnos conversacionais, ferramentas e mensagens.
|
||||
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 365 KiB After Width: | Height: | Size: 327 KiB |
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 1.8 MiB |
130
docs/index.mdx
@@ -27,133 +27,9 @@ mode: "wide"
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, justifyContent: 'center' }}>
|
||||
<a
|
||||
href="/en/quickstart"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid #EB6658",
|
||||
background: "#EB6658",
|
||||
color: "#FFFFFF",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
Get started
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.36)",
|
||||
background: "rgba(235,102,88,0.08)",
|
||||
color: "#EB6658",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={async (event) => {
|
||||
const prompt = `Set up this environment so I can build with CrewAI.
|
||||
|
||||
First install the official CrewAI coding-agent skills if this environment supports npx:
|
||||
|
||||
npx skills add crewaiinc/skills
|
||||
|
||||
If npx is missing or the current agent cannot load skills, do not fail the whole setup. Report the exact issue and continue using the CrewAI docs directly.
|
||||
|
||||
Use these CrewAI docs as source of truth before making assumptions:
|
||||
- https://skills.crewai.com
|
||||
- https://docs.crewai.com/llms.txt
|
||||
- https://docs.crewai.com/en/installation
|
||||
- https://docs.crewai.com/en/guides/coding-tools/build-with-ai
|
||||
|
||||
Setup steps:
|
||||
1. Check python3 --version. CrewAI requires Python >=3.10 and <3.14.
|
||||
2. Install uv if missing:
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
3. Source the uv environment if needed:
|
||||
source "$HOME/.local/bin/env"
|
||||
4. Install the CrewAI CLI:
|
||||
uv tool install crewai
|
||||
5. Verify the CLI:
|
||||
crewai version
|
||||
crewai create --help
|
||||
6. Create a project:
|
||||
CREWAI_DMN=true crewai create
|
||||
7. After project creation, inspect the generated files before editing.
|
||||
8. Run:
|
||||
crewai install
|
||||
crewai run
|
||||
|
||||
Do not hardcode API keys. Use .env.
|
||||
Do not invent CLI flags. Validate with crewai --help or crewai create --help.
|
||||
If a command fails, show the exact command and error, explain the likely cause, fix what you can safely fix, and retry once.`;
|
||||
const button = event.currentTarget;
|
||||
const resetTimeout = button.dataset.resetTimeout;
|
||||
if (resetTimeout) {
|
||||
window.clearTimeout(Number(resetTimeout));
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(prompt);
|
||||
button.textContent = "Copied";
|
||||
} catch {
|
||||
button.textContent = "Copy failed";
|
||||
} finally {
|
||||
button.dataset.resetTimeout = String(window.setTimeout(() => {
|
||||
button.textContent = "Copy agent setup prompt";
|
||||
delete button.dataset.resetTimeout;
|
||||
}, 1600));
|
||||
}
|
||||
}}
|
||||
>
|
||||
Copy agent setup prompt
|
||||
</button>
|
||||
<a
|
||||
href="/guides/coding-tools/build-with-ai"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.28)",
|
||||
color: "#EB6658",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
Coding-agent guide
|
||||
</a>
|
||||
<a
|
||||
href="/en/api-reference/introduction"
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: 42,
|
||||
padding: "0 16px",
|
||||
borderRadius: 8,
|
||||
border: "1px solid rgba(235,102,88,0.18)",
|
||||
color: "var(--mint-text-2)",
|
||||
fontWeight: 700,
|
||||
lineHeight: 1,
|
||||
textDecoration: "none"
|
||||
}}
|
||||
>
|
||||
API Reference
|
||||
</a>
|
||||
<a className="button button-primary" href="/en/quickstart">Get started</a>
|
||||
<a className="button" href="/en/changelog">View changelog</a>
|
||||
<a className="button" href="/en/api-reference/introduction">API Reference</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
19
docs/v1.14.7/api/v1/platform-api/introduction.mdx
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "Platform API"
|
||||
description: "Build against the supported CrewAI Platform public API."
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
# CrewAI Platform API
|
||||
|
||||
The Platform API is the supported public API for CrewAI Platform. Use it when
|
||||
you need stable HTTP contracts for automation, integrations, and agent-facing
|
||||
workflows.
|
||||
|
||||
The current public contract is `v1`. Endpoints live under `/api/v1` on the
|
||||
CrewAI Platform app host:
|
||||
|
||||
```text
|
||||
https://app.crewai.com/api/v1
|
||||
```
|
||||
13
docs/v1.14.7/api/v1/problems.mdx
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "Problems"
|
||||
description: "Error responses returned by the CrewAI Platform API."
|
||||
---
|
||||
|
||||
# Problems
|
||||
|
||||
When a request fails, the Platform API returns an `errors` array. Each item
|
||||
includes a stable `code`, an HTTP `status`, and a `detail` message with
|
||||
request-specific context.
|
||||
|
||||
Use the pages in this section to understand what each error code means and what
|
||||
to change before retrying.
|
||||
17
docs/v1.14.7/api/v1/problems/bad_request.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: bad_request
|
||||
title: Bad request
|
||||
status: 400
|
||||
---
|
||||
|
||||
# Bad request
|
||||
|
||||
The request could not be processed because it was malformed or missing required request data.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This usually means the request body, query string, headers, or required parameters are invalid before endpoint-specific validation can run.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Review the endpoint contract, required parameters, request body shape, and content type before retrying.
|
||||
17
docs/v1.14.7/api/v1/problems/internal_error.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: internal_error
|
||||
title: Internal error
|
||||
status: 500
|
||||
---
|
||||
|
||||
# Internal error
|
||||
|
||||
An unexpected server-side failure prevented the request from completing.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This means the platform encountered an unexpected condition while processing a valid request.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Retry the request after a short delay. If the problem continues, contact support with the request details and timestamp.
|
||||
17
docs/v1.14.7/api/v1/problems/not_found.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: not_found
|
||||
title: Not found
|
||||
status: 404
|
||||
---
|
||||
|
||||
# Not found
|
||||
|
||||
The requested resource does not exist or is not available at the requested path.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This can happen when the URL is incorrect, the resource identifier does not exist, or the resource is not visible through the public API.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Check the endpoint path and resource identifier, then retry with a resource that exists and is available to the request.
|
||||
17
docs/v1.14.7/api/v1/problems/validation_error.mdx
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
code: validation_error
|
||||
title: Validation error
|
||||
status: 422
|
||||
---
|
||||
|
||||
# Validation error
|
||||
|
||||
The request was understood, but one or more submitted values failed validation.
|
||||
|
||||
## When It Happens
|
||||
|
||||
This usually means a submitted field is missing, malformed, out of range, duplicated, or conflicts with another value.
|
||||
|
||||
## How To Fix
|
||||
|
||||
Inspect the `detail` message for the field-specific issue, update the submitted values, and retry the request.
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**الإطلاق يوم الأربعاء 24 يونيو.** تنتقل لوحة Studio إلى بطاقة واحدة لكل خطوة بدلاً من عُقد منفصلة للمهمة والوكيل، وذلك لتبسيط اللوحة مع إضافتنا لوظائف جديدة قريبًا. تستمر أتمتتك الحالية في العمل دون أي تغييرات مطلوبة — تبقى جميع إعدادات المهمة والوكيل متاحة، ولكن منظّمة في بطاقة واحدة.
|
||||
</Note>
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
على لوحة Studio، تُمثَّل كل خطوة عمل بـ **بطاقة واحدة**. تجمع البطاقة بين عنصرين كانا في السابق في عُقد منفصلة:
|
||||
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**Rolling out Wednesday, June 24th.** The Studio canvas is moving to one card per step instead of separate task and agent nodes, to streamline the canvas as we add new functionality soon. Your existing automations keep working with no changes needed — every task and agent setting is still available, just organized onto a single card.
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
On the Studio canvas, each step of work is represented by a **single card**. The card combines two things that used to live in separate nodes:
|
||||
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**6월 24일 수요일 출시.** Studio 캔버스가 작업과 에이전트를 별도의 노드로 표시하는 대신 단계당 하나의 카드로 전환됩니다. 곧 추가될 새로운 기능을 위해 캔버스를 간소화하기 위한 변경입니다. 기존 자동화는 아무런 변경 없이 그대로 동작하며, 모든 작업 및 에이전트 설정은 단일 카드에 정리되어 그대로 사용할 수 있습니다.
|
||||
</Note>
|
||||
|
||||
## 개요
|
||||
|
||||
Studio 캔버스에서 각 작업 단계는 **하나의 카드**로 표현됩니다. 이 카드는 이전에 별도의 노드에 있던 두 가지를 결합합니다:
|
||||
|
||||
115
docs/v1.14.7/openapi/platform-v1.yaml
Normal file
@@ -0,0 +1,115 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: CrewAI Platform API
|
||||
version: v1
|
||||
description: Supported public API for CrewAI Platform.
|
||||
servers:
|
||||
- url: https://app.crewai.com
|
||||
description: CrewAI Platform
|
||||
security: []
|
||||
tags:
|
||||
- name: Status
|
||||
description: Platform health and API availability.
|
||||
paths:
|
||||
/api/v1/status:
|
||||
get:
|
||||
summary: Check API status
|
||||
operationId: getStatus
|
||||
tags:
|
||||
- Status
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
success:
|
||||
value:
|
||||
data:
|
||||
status: ok
|
||||
summary: API is available
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
additionalProperties: false
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
required:
|
||||
- status
|
||||
additionalProperties: false
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- ok
|
||||
example: ok
|
||||
components:
|
||||
schemas:
|
||||
SuccessEnvelope:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
additionalProperties: false
|
||||
properties:
|
||||
data:
|
||||
description: Endpoint-specific response payload.
|
||||
ErrorEnvelope:
|
||||
type: object
|
||||
required:
|
||||
- errors
|
||||
additionalProperties: false
|
||||
properties:
|
||||
errors:
|
||||
type: array
|
||||
minItems: 1
|
||||
items:
|
||||
$ref: '#/components/schemas/Error'
|
||||
Error:
|
||||
type: object
|
||||
description: Public API error object.
|
||||
required:
|
||||
- type
|
||||
- code
|
||||
- title
|
||||
- status
|
||||
- detail
|
||||
additionalProperties: false
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
format: uri
|
||||
enum:
|
||||
- https://docs.crewai.com/api/v1/problems/bad_request
|
||||
- https://docs.crewai.com/api/v1/problems/internal_error
|
||||
- https://docs.crewai.com/api/v1/problems/not_found
|
||||
- https://docs.crewai.com/api/v1/problems/validation_error
|
||||
example: https://docs.crewai.com/api/v1/problems/bad_request
|
||||
code:
|
||||
type: string
|
||||
enum:
|
||||
- bad_request
|
||||
- internal_error
|
||||
- not_found
|
||||
- validation_error
|
||||
example: bad_request
|
||||
title:
|
||||
type: string
|
||||
enum:
|
||||
- Bad request
|
||||
- Internal error
|
||||
- Not found
|
||||
- Validation error
|
||||
example: Bad request
|
||||
status:
|
||||
type: integer
|
||||
enum:
|
||||
- 400
|
||||
- 404
|
||||
- 422
|
||||
- 500
|
||||
example: 400
|
||||
detail:
|
||||
type: string
|
||||
example: The request is invalid.
|
||||
@@ -5,6 +5,11 @@ icon: "layer-group"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
{/* CLEANUP: This <Note> banner is the only time-bound content on the page. After the feature ships (Wednesday, June 24th 2026), delete the banner below — the rest of the page is evergreen present-tense docs and needs no other edits. */}
|
||||
<Note>
|
||||
**Lançamento na quarta-feira, 24 de junho.** O canvas do Studio passa a exibir um card por etapa, em vez de nós separados para tarefa e agente, para simplificar o canvas à medida que adicionamos novas funcionalidades em breve. Suas automações existentes continuam funcionando sem nenhuma alteração necessária — cada configuração de tarefa e de agente continua disponível, apenas organizada em um único card.
|
||||
</Note>
|
||||
|
||||
## Visão geral
|
||||
|
||||
No canvas do Studio, cada etapa de trabalho é representada por um **único card**. O card combina dois elementos que antes ficavam em nós separados:
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
title: "GET /inputs"
|
||||
description: "الحصول على المدخلات المطلوبة لطاقمك"
|
||||
openapi: "/v1.15.0/enterprise-api.en.yaml GET /inputs"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
---
|
||||
title: "مقدمة"
|
||||
description: "المرجع الكامل لواجهة برمجة تطبيقات CrewAI AMP REST"
|
||||
icon: "code"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
# واجهة برمجة تطبيقات CrewAI AMP
|
||||
|
||||
مرحبًا بك في مرجع واجهة برمجة تطبيقات CrewAI AMP. تتيح لك هذه الواجهة التفاعل برمجيًا مع الأطقم المنشورة، مما يمكّنك من دمجها مع تطبيقاتك وسير عملك وخدماتك.
|
||||
|
||||
## البدء السريع
|
||||
|
||||
<Steps>
|
||||
<Step title="الحصول على بيانات اعتماد API">
|
||||
انتقل إلى صفحة تفاصيل طاقمك في لوحة تحكم CrewAI AMP وانسخ رمز Bearer من علامة تبويب الحالة.
|
||||
</Step>
|
||||
|
||||
<Step title="اكتشاف المدخلات المطلوبة">
|
||||
استخدم نقطة النهاية `GET /inputs` لمعرفة المعاملات التي يتوقعها طاقمك.
|
||||
</Step>
|
||||
|
||||
<Step title="بدء تنفيذ الطاقم">
|
||||
استدعِ `POST /kickoff` مع مدخلاتك لبدء تنفيذ الطاقم واستلام
|
||||
`kickoff_id`.
|
||||
</Step>
|
||||
|
||||
<Step title="مراقبة التقدم">
|
||||
استخدم `GET /status/{kickoff_id}` للتحقق من حالة التنفيذ واسترجاع النتائج.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## المصادقة
|
||||
|
||||
تتطلب جميع طلبات API المصادقة باستخدام رمز Bearer. أدرج رمزك في ترويسة `Authorization`:
|
||||
|
||||
```bash
|
||||
curl -H "Authorization: Bearer YOUR_CREW_TOKEN" \
|
||||
https://your-crew-url.crewai.com/inputs
|
||||
```
|
||||
|
||||
### أنواع الرموز
|
||||
|
||||
| نوع الرمز | النطاق | حالة الاستخدام |
|
||||
| :-------------------- | :------------------------ | :----------------------------------------------------------- |
|
||||
| **Bearer Token** | وصول على مستوى المؤسسة | عمليات الطاقم الكاملة، مثالي للتكامل بين الخوادم |
|
||||
| **User Bearer Token** | وصول محدد بالمستخدم | صلاحيات محدودة، مناسب للعمليات الخاصة بالمستخدم |
|
||||
|
||||
<Tip>
|
||||
يمكنك العثور على كلا نوعي الرموز في علامة تبويب الحالة من صفحة تفاصيل طاقمك في
|
||||
لوحة تحكم CrewAI AMP.
|
||||
</Tip>
|
||||
|
||||
## عنوان URL الأساسي
|
||||
|
||||
لكل طاقم منشور نقطة نهاية API فريدة خاصة به:
|
||||
|
||||
```
|
||||
https://your-crew-name.crewai.com
|
||||
```
|
||||
|
||||
استبدل `your-crew-name` بعنوان URL الفعلي لطاقمك من لوحة التحكم.
|
||||
|
||||
## سير العمل النموذجي
|
||||
|
||||
1. **الاكتشاف**: استدعِ `GET /inputs` لفهم ما يحتاجه طاقمك
|
||||
2. **التنفيذ**: أرسل المدخلات عبر `POST /kickoff` لبدء المعالجة
|
||||
3. **المراقبة**: استعلم عن `GET /status/{kickoff_id}` حتى الاكتمال
|
||||
4. **النتائج**: استخرج المخرجات النهائية من الاستجابة المكتملة
|
||||
|
||||
## معالجة الأخطاء
|
||||
|
||||
تستخدم الواجهة أكواد حالة HTTP القياسية:
|
||||
|
||||
| الكود | المعنى |
|
||||
| ----- | :----------------------------------------- |
|
||||
| `200` | نجاح |
|
||||
| `400` | طلب غير صالح - تنسيق مدخلات غير صحيح |
|
||||
| `401` | غير مصرّح - رمز bearer غير صالح |
|
||||
| `404` | غير موجود - المورد غير موجود |
|
||||
| `422` | خطأ في التحقق - مدخلات مطلوبة مفقودة |
|
||||
| `500` | خطأ في الخادم - تواصل مع الدعم |
|
||||
|
||||
## الاختبار التفاعلي
|
||||
|
||||
<Info>
|
||||
**لماذا لا يوجد زر "إرسال"؟** نظرًا لأن كل مستخدم CrewAI AMP لديه عنوان URL
|
||||
فريد للطاقم، نستخدم **وضع المرجع** بدلاً من بيئة تفاعلية لتجنب
|
||||
الالتباس. يوضح لك هذا بالضبط كيف يجب أن تبدو الطلبات بدون
|
||||
أزرار إرسال غير فعالة.
|
||||
</Info>
|
||||
|
||||
تعرض لك كل صفحة نقطة نهاية:
|
||||
|
||||
- **تنسيق الطلب الدقيق** مع جميع المعاملات
|
||||
- **أمثلة الاستجابة** لحالات النجاح والخطأ
|
||||
- **عينات الكود** بلغات متعددة (cURL، Python، JavaScript، إلخ)
|
||||
- **أمثلة المصادقة** بتنسيق رمز Bearer الصحيح
|
||||
|
||||
### **لاختبار واجهتك الفعلية:**
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="نسخ أمثلة cURL" icon="terminal">
|
||||
انسخ أمثلة cURL واستبدل العنوان URL + الرمز بقيمك الحقيقية
|
||||
</Card>
|
||||
<Card title="استخدام Postman/Insomnia" icon="play">
|
||||
استورد الأمثلة في أداة اختبار API المفضلة لديك
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
**مثال على سير العمل:**
|
||||
|
||||
1. **انسخ مثال cURL هذا** من أي صفحة نقطة نهاية
|
||||
2. **استبدل `your-actual-crew-name.crewai.com`** بعنوان URL الحقيقي لطاقمك
|
||||
3. **استبدل رمز Bearer** برمزك الحقيقي من لوحة التحكم
|
||||
4. **نفّذ الطلب** في طرفيتك أو عميل API
|
||||
|
||||
## هل تحتاج مساعدة؟
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="دعم المؤسسات"
|
||||
icon="headset"
|
||||
href="mailto:support@crewai.com"
|
||||
>
|
||||
احصل على مساعدة في تكامل API واستكشاف الأخطاء وإصلاحها
|
||||
</Card>
|
||||
<Card
|
||||
title="لوحة تحكم المؤسسات"
|
||||
icon="chart-line"
|
||||
href="https://app.crewai.com"
|
||||
>
|
||||
إدارة أطقمك وعرض سجلات التنفيذ
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
title: "POST /kickoff"
|
||||
description: "بدء تنفيذ الطاقم"
|
||||
openapi: "/v1.15.0/enterprise-api.en.yaml POST /kickoff"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
title: "POST /resume"
|
||||
description: "استئناف تنفيذ الطاقم مع التغذية الراجعة البشرية"
|
||||
openapi: "/v1.15.0/enterprise-api.en.yaml POST /resume"
|
||||
mode: "wide"
|
||||
---
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
title: "GET /status/{kickoff_id}"
|
||||
description: "الحصول على حالة التنفيذ"
|
||||
openapi: "/v1.15.0/enterprise-api.en.yaml GET /status/{kickoff_id}"
|
||||
mode: "wide"
|
||||
---
|
||||
@@ -1,147 +0,0 @@
|
||||
---
|
||||
title: "قدرات الوكيل"
|
||||
description: "فهم الطرق الخمس لتوسيع وكلاء CrewAI: الأدوات، MCP، التطبيقات، المهارات، والمعرفة."
|
||||
icon: puzzle-piece
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
يمكن توسيع وكلاء CrewAI بـ **خمسة أنواع مميزة من القدرات**، كل منها يخدم غرضًا مختلفًا. فهم متى تستخدم كل نوع — وكيف يعملون معًا — هو المفتاح لبناء وكلاء فعّالين.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="الأدوات" icon="wrench" href="/ar/concepts/tools" color="#3B82F6">
|
||||
**دوال قابلة للاستدعاء** — تمنح الوكلاء القدرة على اتخاذ إجراءات. البحث على الويب، عمليات الملفات، استدعاءات API، تنفيذ الكود.
|
||||
</Card>
|
||||
<Card title="خوادم MCP" icon="plug" href="/ar/mcp/overview" color="#8B5CF6">
|
||||
**خوادم أدوات عن بُعد** — تربط الوكلاء بخوادم أدوات خارجية عبر Model Context Protocol. نفس تأثير الأدوات، لكن مستضافة خارجيًا.
|
||||
</Card>
|
||||
<Card title="التطبيقات" icon="grid-2" color="#EC4899">
|
||||
**تكاملات المنصة** — تربط الوكلاء بتطبيقات SaaS (Gmail، Slack، Jira، Salesforce) عبر منصة CrewAI. تعمل محليًا مع رمز تكامل المنصة.
|
||||
</Card>
|
||||
<Card title="المهارات" icon="bolt" href="/ar/concepts/skills" color="#F59E0B">
|
||||
**خبرة المجال** — تحقن التعليمات والإرشادات والمواد المرجعية في إرشادات الوكلاء. المهارات تخبر الوكلاء *كيف يفكرون*.
|
||||
</Card>
|
||||
<Card title="المعرفة" icon="book" href="/ar/concepts/knowledge" color="#10B981">
|
||||
**حقائق مُسترجعة** — توفر للوكلاء بيانات من المستندات والملفات وعناوين URL عبر البحث الدلالي (RAG). المعرفة تعطي الوكلاء *ما يحتاجون معرفته*.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
---
|
||||
|
||||
## التمييز الأساسي
|
||||
|
||||
أهم شيء يجب فهمه: **هذه القدرات تنقسم إلى فئتين**.
|
||||
|
||||
### قدرات الإجراء (الأدوات، MCP، التطبيقات)
|
||||
|
||||
تمنح الوكلاء القدرة على **فعل أشياء** — استدعاء APIs، قراءة الملفات، البحث على الويب، إرسال رسائل البريد الإلكتروني. عند التنفيذ، تتحول الأنواع الثلاثة إلى نفس التنسيق الداخلي (مثيلات `BaseTool`) وتظهر في قائمة أدوات موحدة يمكن للوكيل استدعاؤها.
|
||||
|
||||
```python
|
||||
from crewai import Agent
|
||||
from crewai_tools import SerperDevTool, FileReadTool
|
||||
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Find and compile market data",
|
||||
backstory="Expert market analyst",
|
||||
tools=[SerperDevTool(), FileReadTool()], # أدوات محلية
|
||||
mcps=["https://mcp.example.com/sse"], # أدوات خادم MCP عن بُعد
|
||||
apps=["gmail", "google_sheets"], # تكاملات المنصة
|
||||
)
|
||||
```
|
||||
|
||||
### قدرات السياق (المهارات، المعرفة)
|
||||
|
||||
تُعدّل **إرشادات** الوكيل — بحقن الخبرة أو التعليمات أو البيانات المُسترجعة قبل أن يبدأ الوكيل في التفكير. لا تمنح الوكلاء إجراءات جديدة؛ بل تُشكّل كيف يفكر الوكلاء وما هي المعلومات التي يمكنهم الوصول إليها.
|
||||
|
||||
```python
|
||||
from crewai import Agent
|
||||
|
||||
agent = Agent(
|
||||
role="Security Auditor",
|
||||
goal="Audit cloud infrastructure for vulnerabilities",
|
||||
backstory="Expert in cloud security with 10 years of experience",
|
||||
skills=["./skills/security-audit"], # تعليمات المجال
|
||||
knowledge_sources=[pdf_source, url_source], # حقائق مُسترجعة
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## متى تستخدم ماذا
|
||||
|
||||
| تحتاج إلى... | استخدم | مثال |
|
||||
| :------------------------------------------------------- | :---------------- | :--------------------------------------- |
|
||||
| الوكيل يبحث على الويب | **الأدوات** | `tools=[SerperDevTool()]` |
|
||||
| الوكيل يستدعي API عن بُعد عبر MCP | **MCP** | `mcps=["https://api.example.com/sse"]` |
|
||||
| الوكيل يرسل بريد إلكتروني عبر Gmail | **التطبيقات** | `apps=["gmail"]` |
|
||||
| الوكيل يتبع إجراءات محددة | **المهارات** | `skills=["./skills/code-review"]` |
|
||||
| الوكيل يرجع لمستندات الشركة | **المعرفة** | `knowledge_sources=[pdf_source]` |
|
||||
| الوكيل يبحث على الويب ويتبع إرشادات المراجعة | **الأدوات + المهارات** | استخدم كليهما معًا |
|
||||
|
||||
---
|
||||
|
||||
## دمج القدرات
|
||||
|
||||
في الممارسة العملية، غالبًا ما يستخدم الوكلاء **أنواعًا متعددة من القدرات معًا**. إليك مثال واقعي:
|
||||
|
||||
```python
|
||||
from crewai import Agent
|
||||
from crewai_tools import SerperDevTool, FileReadTool, CodeInterpreterTool
|
||||
|
||||
# وكيل بحث مجهز بالكامل
|
||||
researcher = Agent(
|
||||
role="Senior Research Analyst",
|
||||
goal="Produce comprehensive market analysis reports",
|
||||
backstory="Expert analyst with deep industry knowledge",
|
||||
|
||||
# الإجراء: ما يمكن للوكيل فعله
|
||||
tools=[
|
||||
SerperDevTool(), # البحث على الويب
|
||||
FileReadTool(), # قراءة الملفات المحلية
|
||||
CodeInterpreterTool(), # تشغيل كود Python للتحليل
|
||||
],
|
||||
mcps=["https://data-api.example.com/sse"], # الوصول لـ API بيانات عن بُعد
|
||||
apps=["google_sheets"], # الكتابة في Google Sheets
|
||||
|
||||
# السياق: ما يعرفه الوكيل
|
||||
skills=["./skills/research-methodology"], # كيفية إجراء البحث
|
||||
knowledge_sources=[company_docs], # بيانات خاصة بالشركة
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## جدول المقارنة
|
||||
|
||||
| الميزة | الأدوات | MCP | التطبيقات | المهارات | المعرفة |
|
||||
| :--- | :---: | :---: | :---: | :---: | :---: |
|
||||
| **يمنح الوكيل إجراءات** | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| **يُعدّل الإرشادات** | ❌ | ❌ | ❌ | ✅ | ✅ |
|
||||
| **يتطلب كود** | نعم | إعداد فقط | إعداد فقط | Markdown فقط | إعداد فقط |
|
||||
| **يعمل محليًا** | نعم | يعتمد | نعم (مع متغير بيئة) | غير متاح | نعم |
|
||||
| **يحتاج مفاتيح API** | لكل أداة | لكل خادم | رمز التكامل | لا | المُضمّن فقط |
|
||||
| **يُعيَّن على Agent** | `tools=[]` | `mcps=[]` | `apps=[]` | `skills=[]` | `knowledge_sources=[]` |
|
||||
| **يُعيَّن على Crew** | ❌ | ❌ | ❌ | `skills=[]` | `knowledge_sources=[]` |
|
||||
|
||||
---
|
||||
|
||||
## تعمّق أكثر
|
||||
|
||||
هل أنت مستعد لمعرفة المزيد عن كل نوع من أنواع القدرات؟
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="الأدوات" icon="wrench" href="/ar/concepts/tools">
|
||||
إنشاء أدوات مخصصة، استخدام كتالوج OSS مع أكثر من 75 خيارًا، تكوين التخزين المؤقت والتنفيذ غير المتزامن.
|
||||
</Card>
|
||||
<Card title="تكامل MCP" icon="plug" href="/ar/mcp/overview">
|
||||
الاتصال بخوادم MCP عبر stdio أو SSE أو HTTP. تصفية الأدوات، تكوين المصادقة.
|
||||
</Card>
|
||||
<Card title="المهارات" icon="bolt" href="/ar/concepts/skills">
|
||||
بناء حزم المهارات مع SKILL.md، حقن خبرة المجال، استخدام الكشف التدريجي.
|
||||
</Card>
|
||||
<Card title="المعرفة" icon="book" href="/ar/concepts/knowledge">
|
||||
إضافة المعرفة من ملفات PDF وCSV وعناوين URL والمزيد. تكوين المُضمّنات والاسترجاع.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -1,383 +0,0 @@
|
||||
---
|
||||
title: الوكلاء
|
||||
description: دليل تفصيلي حول إنشاء وإدارة الوكلاء ضمن إطار عمل CrewAI.
|
||||
icon: robot
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
## نظرة عامة على الوكيل
|
||||
|
||||
في إطار عمل CrewAI، الـ `Agent` هو وحدة مستقلة يمكنها:
|
||||
|
||||
- أداء مهام محددة
|
||||
- اتخاذ قرارات بناءً على دوره وهدفه
|
||||
- استخدام الأدوات لتحقيق الأهداف
|
||||
- التواصل والتعاون مع وكلاء آخرين
|
||||
- الاحتفاظ بذاكرة التفاعلات
|
||||
- تفويض المهام عند السماح بذلك
|
||||
|
||||
<Tip>
|
||||
فكّر في الوكيل كعضو فريق متخصص بمهارات وخبرات ومسؤوليات محددة.
|
||||
على سبيل المثال، قد يتفوق وكيل `Researcher` في جمع وتحليل المعلومات،
|
||||
بينما قد يكون وكيل `Writer` أفضل في إنشاء المحتوى.
|
||||
</Tip>
|
||||
|
||||
<Note type="info" title="تحسين المؤسسات: منشئ الوكلاء المرئي">
|
||||
يتضمن CrewAI AMP منشئ وكلاء مرئي يبسّط إنشاء وتهيئة الوكلاء بدون كتابة كود. صمم وكلاءك بصريًا واختبرهم في الوقت الفعلي.
|
||||
|
||||

|
||||
|
||||
يُمكّن منشئ الوكلاء المرئي من:
|
||||
|
||||
- تهيئة وكلاء بديهية بواجهات نماذج
|
||||
- اختبار والتحقق في الوقت الفعلي
|
||||
- مكتبة قوالب مع أنواع وكلاء مهيأة مسبقًا
|
||||
- تخصيص سهل لخصائص وسلوكيات الوكيل
|
||||
</Note>
|
||||
|
||||
## خصائص الوكيل
|
||||
|
||||
| الخاصية | المعامل | النوع | الوصف |
|
||||
| :-------------------------------------- | :----------------------- | :------------------------------------ | :------------------------------------------------------------------------------------------------------- |
|
||||
| **الدور** | `role` | `str` | يحدد وظيفة الوكيل وخبرته ضمن الطاقم. |
|
||||
| **الهدف** | `goal` | `str` | الهدف الفردي الذي يوجه عملية اتخاذ القرار لدى الوكيل. |
|
||||
| **الخلفية** | `backstory` | `str` | يوفر سياقًا وشخصية للوكيل، مما يثري التفاعلات. |
|
||||
| **LLM** _(اختياري)_ | `llm` | `Union[str, LLM, Any]` | نموذج اللغة الذي يشغّل الوكيل. افتراضيًا النموذج المحدد في `OPENAI_MODEL_NAME` أو "gpt-4". |
|
||||
| **الأدوات** _(اختياري)_ | `tools` | `List[BaseTool]` | القدرات أو الوظائف المتاحة للوكيل. افتراضيًا قائمة فارغة. |
|
||||
| **LLM استدعاء الدوال** _(اختياري)_ | `function_calling_llm` | `Optional[Any]` | نموذج لغة لاستدعاء الأدوات، يتجاوز LLM الطاقم إذا حُدد. |
|
||||
| **الحد الأقصى للتكرارات** _(اختياري)_ | `max_iter` | `int` | الحد الأقصى للتكرارات قبل أن يقدم الوكيل أفضل إجابته. الافتراضي 20. |
|
||||
| **الحد الأقصى لـ RPM** _(اختياري)_ | `max_rpm` | `Optional[int]` | الحد الأقصى للطلبات في الدقيقة لتجنب حدود المعدل. |
|
||||
| **الحد الأقصى لوقت التنفيذ** _(اختياري)_ | `max_execution_time` | `Optional[int]` | الحد الأقصى للوقت (بالثواني) لتنفيذ المهمة. |
|
||||
| **الوضع المفصل** _(اختياري)_ | `verbose` | `bool` | تفعيل سجلات التنفيذ المفصلة للتصحيح. الافتراضي False. |
|
||||
| **السماح بالتفويض** _(اختياري)_ | `allow_delegation` | `bool` | السماح للوكيل بتفويض المهام لوكلاء آخرين. الافتراضي False. |
|
||||
| **دالة الخطوة** _(اختياري)_ | `step_callback` | `Optional[Any]` | دالة تُستدعى بعد كل خطوة للوكيل، تتجاوز دالة الطاقم. |
|
||||
| **التخزين المؤقت** _(اختياري)_ | `cache` | `bool` | تفعيل التخزين المؤقت لاستخدام الأدوات. الافتراضي True. |
|
||||
| **قالب النظام** _(اختياري)_ | `system_template` | `Optional[str]` | قالب أمر نظام مخصص للوكيل. |
|
||||
| **قالب الأمر** _(اختياري)_ | `prompt_template` | `Optional[str]` | قالب أمر مخصص للوكيل. |
|
||||
| **قالب الاستجابة** _(اختياري)_ | `response_template` | `Optional[str]` | قالب استجابة مخصص للوكيل. |
|
||||
| **السماح بتنفيذ الكود** _(اختياري)_ | `allow_code_execution` | `Optional[bool]` | تفعيل تنفيذ الكود للوكيل. الافتراضي False. |
|
||||
| **الحد الأقصى لإعادة المحاولة** _(اختياري)_ | `max_retry_limit` | `int` | الحد الأقصى لإعادات المحاولة عند حدوث خطأ. الافتراضي 2. |
|
||||
| **احترام نافذة السياق** _(اختياري)_ | `respect_context_window` | `bool` | إبقاء الرسائل تحت حجم نافذة السياق عبر التلخيص. الافتراضي True. |
|
||||
| **وضع تنفيذ الكود** _(اختياري)_ | `code_execution_mode` | `Literal["safe", "unsafe"]` | وضع تنفيذ الكود: 'safe' (باستخدام Docker) أو 'unsafe' (مباشر). الافتراضي 'safe'. |
|
||||
| **متعدد الوسائط** _(اختياري)_ | `multimodal` | `bool` | ما إذا كان الوكيل يدعم القدرات متعددة الوسائط. الافتراضي False. |
|
||||
| **حقن التاريخ** _(اختياري)_ | `inject_date` | `bool` | ما إذا كان يتم حقن التاريخ الحالي تلقائيًا في المهام. الافتراضي False. |
|
||||
| **تنسيق التاريخ** _(اختياري)_ | `date_format` | `str` | سلسلة تنسيق التاريخ عند تفعيل inject_date. الافتراضي "%Y-%m-%d" (تنسيق ISO). |
|
||||
| **الاستدلال** _(اختياري)_ | `reasoning` | `bool` | ما إذا كان يجب على الوكيل التأمل وإنشاء خطة قبل تنفيذ المهمة. الافتراضي False. |
|
||||
| **الحد الأقصى لمحاولات الاستدلال** _(اختياري)_ | `max_reasoning_attempts` | `Optional[int]` | الحد الأقصى لمحاولات الاستدلال قبل تنفيذ المهمة. إذا None، سيحاول حتى الاستعداد. |
|
||||
| **المُضمّن** _(اختياري)_ | `embedder` | `Optional[Dict[str, Any]]` | تهيئة المُضمّن المستخدم من قبل الوكيل. |
|
||||
| **مصادر المعرفة** _(اختياري)_ | `knowledge_sources` | `Optional[List[BaseKnowledgeSource]]` | مصادر المعرفة المتاحة للوكيل. |
|
||||
| **استخدام أمر النظام** _(اختياري)_ | `use_system_prompt` | `Optional[bool]` | ما إذا كان يُستخدم أمر النظام (لدعم نموذج o1). الافتراضي True. |
|
||||
|
||||
## إنشاء الوكلاء
|
||||
|
||||
هناك طريقتان شائعتان لإنشاء الوكلاء في CrewAI: باستخدام **تهيئة JSONC (الموصى بها للـ crews الجديدة)** أو تعريفهم **مباشرة في الكود**.
|
||||
|
||||
### تهيئة JSONC (موصى بها)
|
||||
|
||||
المشاريع الجديدة التي تُنشأ عبر `crewai create crew <name>` تستخدم تهيئة JSON-first. يُعرّف كل Agent في `agents/<agent_name>.jsonc`، ويحدد `crew.jsonc` أي Agents تدخل في الـ crew.
|
||||
|
||||
```jsonc agents/researcher.jsonc
|
||||
{
|
||||
"role": "{topic} Senior Data Researcher",
|
||||
"goal": "Uncover cutting-edge developments in {topic}",
|
||||
"backstory": "You find the most relevant information and present it clearly.",
|
||||
"llm": "openai/gpt-4o",
|
||||
"tools": ["SerperDevTool"],
|
||||
"settings": {
|
||||
"verbose": true,
|
||||
"allow_delegation": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
استخدم `{placeholder}` داخل `role` أو `goal` أو `backstory`. ضع القيم الافتراضية في `inputs` داخل `crew.jsonc`؛ وسيطلب `crewai run` أي قيم ناقصة. يمكن وضع حقول السلوك مثل `verbose` و `allow_delegation` و `max_iter` و `memory` و `cache` و `planning_config` في المستوى الأعلى أو داخل `settings`.
|
||||
|
||||
<Note>
|
||||
يدعم JSONC التعليقات والفواصل النهائية. إذا وُجد `agents/<name>.jsonc` و `agents/<name>.json` معًا، يستخدم CrewAI ملف JSONC.
|
||||
</Note>
|
||||
|
||||
### تهيئة YAML الكلاسيكية
|
||||
|
||||
المشاريع الكلاسيكية التي تُنشأ عبر `crewai create crew <name> --classic` تستخدم `config/agents.yaml` وفئة `@CrewBase` في `crew.py`.
|
||||
|
||||
تظل تهيئة YAML مدعومة للمشاريع الحالية المبنية بـ Python/YAML وللفِرق التي تفضل تعريف الوكلاء من خلال فئة `@CrewBase`.
|
||||
|
||||
بعد إنشاء مشروع كلاسيكي، انتقل إلى ملف `src/<project_name>/config/agents.yaml` وعدّل القالب ليتوافق مع متطلباتك.
|
||||
|
||||
<Note>
|
||||
ستُستبدل المتغيرات في ملفات YAML (مثل `{topic}`) بقيم من مدخلاتك عند تشغيل الطاقم:
|
||||
```python Code
|
||||
crew.kickoff(inputs={'topic': 'AI Agents'})
|
||||
```
|
||||
</Note>
|
||||
|
||||
إليك مثالًا على كيفية تهيئة الوكلاء باستخدام YAML:
|
||||
|
||||
```yaml agents.yaml
|
||||
# src/<project_name>/config/agents.yaml
|
||||
researcher:
|
||||
role: >
|
||||
{topic} Senior Data Researcher
|
||||
goal: >
|
||||
Uncover cutting-edge developments in {topic}
|
||||
backstory: >
|
||||
You're a seasoned researcher with a knack for uncovering the latest
|
||||
developments in {topic}. Known for your ability to find the most relevant
|
||||
information and present it in a clear and concise manner.
|
||||
|
||||
reporting_analyst:
|
||||
role: >
|
||||
{topic} Reporting Analyst
|
||||
goal: >
|
||||
Create detailed reports based on {topic} data analysis and research findings
|
||||
backstory: >
|
||||
You're a meticulous analyst with a keen eye for detail. You're known for
|
||||
your ability to turn complex data into clear and concise reports, making
|
||||
it easy for others to understand and act on the information you provide.
|
||||
```
|
||||
|
||||
لاستخدام تهيئة YAML في الكود، أنشئ فئة طاقم ترث من `CrewBase`:
|
||||
|
||||
```python Code
|
||||
# src/<project_name>/crew.py
|
||||
from crewai import Agent, Crew, Process
|
||||
from crewai.project import CrewBase, agent, crew
|
||||
from crewai_tools import SerperDevTool
|
||||
|
||||
@CrewBase
|
||||
class LatestAiDevelopmentCrew():
|
||||
"""LatestAiDevelopment crew"""
|
||||
|
||||
agents_config = "config/agents.yaml"
|
||||
|
||||
@agent
|
||||
def researcher(self) -> Agent:
|
||||
return Agent(
|
||||
config=self.agents_config['researcher'], # type: ignore[index]
|
||||
verbose=True,
|
||||
tools=[SerperDevTool()]
|
||||
)
|
||||
|
||||
@agent
|
||||
def reporting_analyst(self) -> Agent:
|
||||
return Agent(
|
||||
config=self.agents_config['reporting_analyst'], # type: ignore[index]
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
<Note>
|
||||
يجب أن تتطابق الأسماء المستخدمة في ملفات YAML (`agents.yaml`) مع أسماء
|
||||
الطرق في كود Python.
|
||||
</Note>
|
||||
|
||||
### تعريف مباشر في الكود
|
||||
|
||||
يمكنك إنشاء الوكلاء مباشرة في الكود بإنشاء فئة `Agent`. إليك مثالًا شاملًا يوضح جميع المعاملات المتاحة:
|
||||
|
||||
```python Code
|
||||
from crewai import Agent
|
||||
from crewai_tools import SerperDevTool
|
||||
|
||||
# إنشاء وكيل بجميع المعاملات المتاحة
|
||||
agent = Agent(
|
||||
role="Senior Data Scientist",
|
||||
goal="Analyze and interpret complex datasets to provide actionable insights",
|
||||
backstory="With over 10 years of experience in data science and machine learning, "
|
||||
"you excel at finding patterns in complex datasets.",
|
||||
llm="gpt-4",
|
||||
function_calling_llm=None,
|
||||
verbose=False,
|
||||
allow_delegation=False,
|
||||
max_iter=20,
|
||||
max_rpm=None,
|
||||
max_execution_time=None,
|
||||
max_retry_limit=2,
|
||||
allow_code_execution=False,
|
||||
code_execution_mode="safe",
|
||||
respect_context_window=True,
|
||||
use_system_prompt=True,
|
||||
multimodal=False,
|
||||
inject_date=False,
|
||||
date_format="%Y-%m-%d",
|
||||
reasoning=False,
|
||||
max_reasoning_attempts=None,
|
||||
tools=[SerperDevTool()],
|
||||
knowledge_sources=None,
|
||||
embedder=None,
|
||||
system_template=None,
|
||||
prompt_template=None,
|
||||
response_template=None,
|
||||
step_callback=None,
|
||||
)
|
||||
```
|
||||
|
||||
دعنا نستعرض بعض تركيبات المعاملات الرئيسية لحالات الاستخدام الشائعة:
|
||||
|
||||
#### وكيل بحث أساسي
|
||||
|
||||
```python Code
|
||||
research_agent = Agent(
|
||||
role="Research Analyst",
|
||||
goal="Find and summarize information about specific topics",
|
||||
backstory="You are an experienced researcher with attention to detail",
|
||||
tools=[SerperDevTool()],
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
#### وكيل تطوير الكود
|
||||
|
||||
```python Code
|
||||
dev_agent = Agent(
|
||||
role="Senior Python Developer",
|
||||
goal="Write and debug Python code",
|
||||
backstory="Expert Python developer with 10 years of experience",
|
||||
allow_code_execution=True,
|
||||
code_execution_mode="safe",
|
||||
max_execution_time=300,
|
||||
max_retry_limit=3
|
||||
)
|
||||
```
|
||||
|
||||
#### وكيل تحليل طويل المدى
|
||||
|
||||
```python Code
|
||||
analysis_agent = Agent(
|
||||
role="Data Analyst",
|
||||
goal="Perform deep analysis of large datasets",
|
||||
backstory="Specialized in big data analysis and pattern recognition",
|
||||
memory=True,
|
||||
respect_context_window=True,
|
||||
max_rpm=10,
|
||||
function_calling_llm="gpt-4o-mini"
|
||||
)
|
||||
```
|
||||
|
||||
### تفاصيل المعاملات
|
||||
|
||||
#### المعاملات الحرجة
|
||||
|
||||
- `role` و `goal` و `backstory` مطلوبة وتشكّل سلوك الوكيل
|
||||
- `llm` يحدد نموذج اللغة المستخدم (افتراضي: GPT-4 من OpenAI)
|
||||
|
||||
#### الذاكرة والسياق
|
||||
|
||||
- `memory`: تفعيل للحفاظ على سجل المحادثة
|
||||
- `respect_context_window`: يمنع مشاكل حد الرموز
|
||||
- `knowledge_sources`: إضافة قواعد معرفة خاصة بالمجال
|
||||
|
||||
#### التحكم في التنفيذ
|
||||
|
||||
- `max_iter`: الحد الأقصى للمحاولات قبل تقديم أفضل إجابة
|
||||
- `max_execution_time`: المهلة بالثواني
|
||||
- `max_rpm`: تحديد معدل استدعاءات API
|
||||
- `max_retry_limit`: إعادات المحاولة عند الخطأ
|
||||
|
||||
#### تنفيذ الكود
|
||||
|
||||
<Warning>
|
||||
`allow_code_execution` و`code_execution_mode` مهجوران. تمت إزالة `CodeInterpreterTool` من `crewai-tools`. استخدم خدمة بيئة معزولة مخصصة مثل [E2B](https://e2b.dev) أو [Modal](https://modal.com) لتنفيذ الكود بأمان.
|
||||
</Warning>
|
||||
|
||||
- `allow_code_execution` _(مهجور)_: كان يُمكّن تنفيذ الكود المدمج عبر `CodeInterpreterTool`.
|
||||
- `code_execution_mode` _(مهجور)_: كان يتحكم في وضع التنفيذ (`"safe"` لـ Docker، `"unsafe"` للتنفيذ المباشر).
|
||||
|
||||
#### الميزات المتقدمة
|
||||
|
||||
- `multimodal`: تفعيل القدرات متعددة الوسائط لمعالجة النص والمحتوى المرئي
|
||||
- `reasoning`: تمكين الوكيل من التأمل وإنشاء خطط قبل تنفيذ المهام
|
||||
- `inject_date`: حقن التاريخ الحالي تلقائيًا في أوصاف المهام
|
||||
|
||||
#### القوالب
|
||||
|
||||
- `system_template`: يحدد السلوك الأساسي للوكيل
|
||||
- `prompt_template`: ينظم تنسيق الإدخال
|
||||
- `response_template`: ينسّق استجابات الوكيل
|
||||
|
||||
<Note>
|
||||
عند استخدام القوالب المخصصة، تأكد من تعريف كل من `system_template` و
|
||||
`prompt_template`. `response_template` اختياري لكن يُوصى به
|
||||
لتنسيق مخرجات متسق.
|
||||
</Note>
|
||||
|
||||
## أدوات الوكيل
|
||||
|
||||
يمكن تجهيز الوكلاء بأدوات متنوعة لتعزيز قدراتهم. يدعم CrewAI أدوات من:
|
||||
|
||||
- [مجموعة أدوات CrewAI](https://github.com/joaomdmoura/crewai-tools)
|
||||
- [أدوات LangChain](https://python.langchain.com/docs/integrations/tools)
|
||||
|
||||
إليك كيفية إضافة أدوات لوكيل:
|
||||
|
||||
```python Code
|
||||
from crewai import Agent
|
||||
from crewai_tools import SerperDevTool, WikipediaTools
|
||||
|
||||
# إنشاء الأدوات
|
||||
search_tool = SerperDevTool()
|
||||
wiki_tool = WikipediaTools()
|
||||
|
||||
# إضافة أدوات للوكيل
|
||||
researcher = Agent(
|
||||
role="AI Technology Researcher",
|
||||
goal="Research the latest AI developments",
|
||||
tools=[search_tool, wiki_tool],
|
||||
verbose=True
|
||||
)
|
||||
```
|
||||
|
||||
## التفاعل المباشر مع الوكيل عبر `kickoff()`
|
||||
|
||||
يمكن استخدام الوكلاء مباشرة بدون المرور بمهمة أو سير عمل طاقم باستخدام طريقة `kickoff()`. يوفر هذا طريقة أبسط للتفاعل مع وكيل عندما لا تحتاج إلى إمكانيات تنسيق الطاقم الكاملة.
|
||||
|
||||
```python Code
|
||||
from crewai import Agent
|
||||
from crewai_tools import SerperDevTool
|
||||
|
||||
# إنشاء وكيل
|
||||
researcher = Agent(
|
||||
role="AI Technology Researcher",
|
||||
goal="Research the latest AI developments",
|
||||
tools=[SerperDevTool()],
|
||||
verbose=True
|
||||
)
|
||||
|
||||
# استخدام kickoff() للتفاعل مباشرة مع الوكيل
|
||||
result = researcher.kickoff("What are the latest developments in language models?")
|
||||
|
||||
# الوصول إلى الاستجابة الخام
|
||||
print(result.raw)
|
||||
```
|
||||
|
||||
## اعتبارات مهمة وأفضل الممارسات
|
||||
|
||||
### الأمان وتنفيذ الكود
|
||||
|
||||
<Warning>
|
||||
`allow_code_execution` و`code_execution_mode` مهجوران وتمت إزالة `CodeInterpreterTool`. استخدم خدمة بيئة معزولة مخصصة مثل [E2B](https://e2b.dev) أو [Modal](https://modal.com) لتنفيذ الكود بأمان.
|
||||
</Warning>
|
||||
|
||||
### تحسين الأداء
|
||||
|
||||
- استخدم `respect_context_window: true` لمنع مشاكل حد الرموز
|
||||
- عيّن `max_rpm` مناسبًا لتجنب تحديد المعدل
|
||||
- فعّل `cache: true` لتحسين الأداء للمهام المتكررة
|
||||
- اضبط `max_iter` و `max_retry_limit` بناءً على تعقيد المهمة
|
||||
|
||||
### إدارة الذاكرة والسياق
|
||||
|
||||
- استفد من `knowledge_sources` للمعلومات الخاصة بالمجال
|
||||
- هيّئ `embedder` عند استخدام نماذج تضمين مخصصة
|
||||
- استخدم القوالب المخصصة للتحكم الدقيق في سلوك الوكيل
|
||||
|
||||
### التعاون بين الوكلاء
|
||||
|
||||
- فعّل `allow_delegation: true` عندما يحتاج الوكلاء للعمل معًا
|
||||
- استخدم `step_callback` لمراقبة وتسجيل تفاعلات الوكلاء
|
||||
- فكّر في استخدام نماذج LLM مختلفة لأغراض مختلفة
|
||||
|
||||
### توافق النموذج
|
||||
|
||||
- عيّن `use_system_prompt: false` للنماذج القديمة التي لا تدعم رسائل النظام
|
||||
- تأكد من أن `llm` المختار يدعم الميزات التي تحتاجها
|
||||
@@ -1,423 +0,0 @@
|
||||
---
|
||||
title: Checkpointing
|
||||
description: حفظ حالة التنفيذ تلقائيا حتى تتمكن الطواقم والتدفقات والوكلاء من الاستئناف بعد الفشل.
|
||||
icon: floppy-disk
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
الـ Checkpointing يحفظ لقطة من حالة التنفيذ أثناء التشغيل بحيث يمكن لطاقم أو تدفق أو وكيل الاستئناف بعد الفشل أو التفرع إلى فرع بديل.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="الشرح" icon="lightbulb" href="#الشرح">
|
||||
كيف يعمل الـ Checkpointing: الأحداث والتخزين والوراثة.
|
||||
</Card>
|
||||
<Card title="درس تطبيقي" icon="graduation-cap" href="#درس-تطبيقي-استئناف-طاقم-فاشل">
|
||||
دليل 5 دقائق: تشغيل، إيقاف، استئناف.
|
||||
</Card>
|
||||
<Card title="ادلة عملية" icon="screwdriver-wrench" href="#ادلة-عملية">
|
||||
وصفات مركزة على المهام لسير العمل الشائع.
|
||||
</Card>
|
||||
<Card title="المرجع" icon="book" href="#المرجع">
|
||||
`CheckpointConfig` والأحداث والمزودات وسطر الأوامر.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## الشرح
|
||||
|
||||
### ما هي نقطة الحفظ
|
||||
|
||||
تلتقط نقطة الحفظ كل ما يحتاجه CrewAI لإعادة إنشاء تشغيل أثناء سيره: الحالة الكاملة للطاقم أو التدفق أو الوكيل — التكوين، وذاكرة الوكلاء ومصادر المعرفة، وتقدم المهام، والمخرجات الوسيطة، والحالة الداخلية والسمات — إلى جانب مدخلات الـ kickoff، وسجل الأحداث حتى تلك النقطة، ومعرف نسب يربط نقطة الحفظ بالتشغيل الذي جاءت منه.
|
||||
|
||||
الاستعادة تعيد بناء تلك الحالة وتستمر. تتخطى المهام المكتملة، وتعاد ترطيب الذاكرة والمعرفة، ويعمل العمل التابع على نفس المخرجات التي أنتجها التشغيل الأصلي. التفرع يجري نفس الاستعادة تحت نسب جديد، بحيث يكتب الفرع الجديد والتشغيل الأصلي نقاط الحفظ جنبا إلى جنب دون أن يطمس أحدهما الآخر.
|
||||
|
||||
### متى تكتب نقاط الحفظ
|
||||
|
||||
الـ Checkpointing مدفوع بالأحداث. يشترك وقت التشغيل في الأحداث التي تحددها عبر `on_events` ويكتب نقطة حفظ عند إطلاق أحدها. الافتراضي `task_completed` ينتج نقطة حفظ لكل مهمة منتهية — توازن معقول بين الدقة واستخدام القرص. الأحداث عالية التردد مثل `llm_call_completed` متاحة للاستعادة الدقيقة لكنها تكتب ملفات أكثر بكثير.
|
||||
|
||||
### التخزين
|
||||
|
||||
يتضمن CrewAI مزودين:
|
||||
|
||||
- `JsonProvider` يكتب ملفا لكل نقطة حفظ. قابل للقراءة وسهل التفقد.
|
||||
- `SqliteProvider` يكتب إلى قاعدة بيانات SQLite واحدة. أفضل لنقاط الحفظ عالية التردد.
|
||||
|
||||
كلاهما يحذف أقدم نقاط الحفظ عند تحديد `max_checkpoints`.
|
||||
|
||||
<Note>
|
||||
كتابة نقاط الحفظ بأفضل جهد. فشل نقطة حفظ يسجل لكنه لا يقاطع التشغيل.
|
||||
</Note>
|
||||
|
||||
### نموذج الوراثة
|
||||
|
||||
`Crew` و`Flow` و`Agent` كلها تقبل وسيط `checkpoint`. يرث الأبناء من الأب ما لم يحددوا قيمتهم الخاصة أو يمرروا `False` للانسحاب. فعل الـ Checkpointing مرة واحدة على الطاقم وتشارك كل الوكلاء، أو استبعد وكيلا واحدا بشكل انتقائي.
|
||||
|
||||
## درس تطبيقي: استئناف طاقم فاشل
|
||||
|
||||
هذا الدليل يستغرق حوالي 5 دقائق. ستشغل طاقما بمهمتين، توقفه في المنتصف، ثم تستأنف من نقطة الحفظ المحفوظة.
|
||||
|
||||
<Steps>
|
||||
<Step title="أنشئ الطاقم مع تفعيل الـ Checkpointing">
|
||||
```python
|
||||
from crewai import Agent, Crew, Task
|
||||
|
||||
researcher = Agent(role="Researcher", goal="Research", backstory="Expert")
|
||||
writer = Agent(role="Writer", goal="Write", backstory="Expert")
|
||||
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[
|
||||
Task(description="Research AI trends", agent=researcher, expected_output="bullets"),
|
||||
Task(description="Write a summary", agent=writer, expected_output="paragraph"),
|
||||
],
|
||||
checkpoint=True,
|
||||
)
|
||||
```
|
||||
</Step>
|
||||
<Step title="شغله وأوقفه بعد المهمة الأولى">
|
||||
```python
|
||||
result = crew.kickoff()
|
||||
```
|
||||
|
||||
اضغط `Ctrl+C` بعد انتهاء المهمة الأولى. في `./.checkpoints/`، الملف بصيغة `<timestamp>_<uuid>.json` هو نقطة الحفظ.
|
||||
</Step>
|
||||
<Step title="استأنف من نقطة الحفظ">
|
||||
```python
|
||||
from crewai import CheckpointConfig
|
||||
|
||||
result = crew.kickoff(
|
||||
from_checkpoint=CheckpointConfig(
|
||||
restore_from="./.checkpoints/<timestamp>_<uuid>.json",
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
يتم تخطي مهمة البحث، ويعمل الكاتب على مخرجات البحث المحفوظة، وينتهي الطاقم.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## ادلة عملية
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="تفعيل الـ Checkpointing بالإعدادات الافتراضية" icon="play">
|
||||
```python
|
||||
crew = Crew(agents=[...], tasks=[...], checkpoint=True)
|
||||
```
|
||||
|
||||
يكتب إلى `./.checkpoints/` عند كل `task_completed`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="تخصيص التخزين والتردد" icon="sliders">
|
||||
```python
|
||||
from crewai import Crew, CheckpointConfig
|
||||
|
||||
crew = Crew(
|
||||
agents=[...],
|
||||
tasks=[...],
|
||||
checkpoint=CheckpointConfig(
|
||||
location="./my_checkpoints",
|
||||
on_events=["task_completed", "crew_kickoff_completed"],
|
||||
max_checkpoints=5,
|
||||
),
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="اختيار مزود التخزين" icon="database">
|
||||
<CodeGroup>
|
||||
```python JsonProvider
|
||||
from crewai import Crew, CheckpointConfig
|
||||
from crewai.state import JsonProvider
|
||||
|
||||
crew = Crew(
|
||||
agents=[...],
|
||||
tasks=[...],
|
||||
checkpoint=CheckpointConfig(
|
||||
location="./my_checkpoints",
|
||||
provider=JsonProvider(),
|
||||
max_checkpoints=5,
|
||||
),
|
||||
)
|
||||
```
|
||||
```python SqliteProvider
|
||||
from crewai import Crew, CheckpointConfig
|
||||
from crewai.state import SqliteProvider
|
||||
|
||||
crew = Crew(
|
||||
agents=[...],
|
||||
tasks=[...],
|
||||
checkpoint=CheckpointConfig(
|
||||
location="./.checkpoints.db",
|
||||
provider=SqliteProvider(),
|
||||
max_checkpoints=50,
|
||||
),
|
||||
)
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Tip>
|
||||
SQLite يفعل وضع journal WAL للقراءات المتزامنة. يفضل لنقاط الحفظ عالية التردد.
|
||||
</Tip>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="استبعاد وكيل واحد" icon="user-slash">
|
||||
```python
|
||||
crew = Crew(
|
||||
agents=[
|
||||
Agent(role="Researcher", ...),
|
||||
Agent(role="Writer", ..., checkpoint=False),
|
||||
],
|
||||
tasks=[...],
|
||||
checkpoint=True,
|
||||
)
|
||||
```
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="التفرع إلى فرع جديد" icon="code-branch">
|
||||
`fork()` يستعيد نقطة حفظ تحت نسب جديد بحيث لا يتصادم التشغيل الجديد مع الأصلي.
|
||||
|
||||
```python
|
||||
config = CheckpointConfig(restore_from="./my_checkpoints/<file>.json")
|
||||
crew = Crew.fork(config, branch="experiment-a")
|
||||
result = crew.kickoff(inputs={"strategy": "aggressive"})
|
||||
```
|
||||
|
||||
تسمية `branch` اختيارية؛ يتم إنشاء واحدة إذا أغفلت.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Checkpointing لـ Crew أو Flow أو Agent" icon="cubes">
|
||||
<Tabs>
|
||||
<Tab title="Crew">
|
||||
```python
|
||||
crew = Crew(
|
||||
agents=[researcher, writer],
|
||||
tasks=[research_task, write_task, review_task],
|
||||
checkpoint=CheckpointConfig(location="./crew_cp"),
|
||||
)
|
||||
```
|
||||
|
||||
المشغل الافتراضي: `task_completed`.
|
||||
</Tab>
|
||||
<Tab title="Flow">
|
||||
```python
|
||||
from crewai.flow.flow import Flow, start, listen
|
||||
from crewai import CheckpointConfig
|
||||
|
||||
class MyFlow(Flow):
|
||||
@start()
|
||||
def step_one(self):
|
||||
return "data"
|
||||
|
||||
@listen(step_one)
|
||||
def step_two(self, data):
|
||||
return process(data)
|
||||
|
||||
flow = MyFlow(
|
||||
checkpoint=CheckpointConfig(
|
||||
location="./flow_cp",
|
||||
on_events=["method_execution_finished"],
|
||||
),
|
||||
)
|
||||
result = flow.kickoff()
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Agent">
|
||||
```python
|
||||
agent = Agent(
|
||||
role="Researcher",
|
||||
goal="Research topics",
|
||||
backstory="Expert researcher",
|
||||
checkpoint=CheckpointConfig(
|
||||
location="./agent_cp",
|
||||
on_events=["lite_agent_execution_completed"],
|
||||
),
|
||||
)
|
||||
result = agent.kickoff(messages=[{"role": "user", "content": "Research AI trends"}])
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="كتابة نقطة حفظ يدويا" icon="code">
|
||||
سجل معالجا على أي حدث واستدع `state.checkpoint()`.
|
||||
|
||||
<CodeGroup>
|
||||
```python Sync
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from crewai.events.event_bus import crewai_event_bus
|
||||
from crewai.events.types.llm_events import LLMCallCompletedEvent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from crewai.state.runtime import RuntimeState
|
||||
|
||||
|
||||
@crewai_event_bus.on(LLMCallCompletedEvent)
|
||||
def on_llm_done(source: Any, event: LLMCallCompletedEvent, state: RuntimeState) -> None:
|
||||
path = state.checkpoint("./my_checkpoints")
|
||||
print(f"تم حفظ نقطة الحفظ: {path}")
|
||||
```
|
||||
```python Async
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from crewai.events.event_bus import crewai_event_bus
|
||||
from crewai.events.types.llm_events import LLMCallCompletedEvent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from crewai.state.runtime import RuntimeState
|
||||
|
||||
|
||||
@crewai_event_bus.on(LLMCallCompletedEvent)
|
||||
async def on_llm_done_async(source: Any, event: LLMCallCompletedEvent, state: RuntimeState) -> None:
|
||||
path = await state.acheckpoint("./my_checkpoints")
|
||||
print(f"تم حفظ نقطة الحفظ: {path}")
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
يتم تمرير وسيط `state` تلقائيا عندما يقبل المعالج ثلاثة معاملات. راجع [Event Listeners](/ar/concepts/event-listener) لقائمة الأحداث الكاملة.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="التصفح والاستئناف والتفرع من سطر الأوامر" icon="terminal">
|
||||
```bash
|
||||
crewai checkpoint
|
||||
crewai checkpoint --location ./my_checkpoints
|
||||
crewai checkpoint --location ./.checkpoints.db
|
||||
```
|
||||
|
||||
<Frame caption="شجرة نقاط الحفظ — الفروع والتفرعات تتداخل تحت أبيها.">
|
||||
<img src="/images/checkpoint-tui-tree.png" alt="Checkpoint TUI tree view" />
|
||||
</Frame>
|
||||
|
||||
اللوحة اليسرى تجمع نقاط الحفظ حسب الفرع؛ التفرعات تتداخل تحت أبيها. اختيار نقطة حفظ يفتح لوحة التفاصيل مع بياناتها الوصفية وحالة الكيان وتقدم المهام. **Resume** يكمل التشغيل؛ **Fork** يبدأ فرعا جديدا.
|
||||
|
||||
<Frame caption="تبويب النظرة العامة — البيانات الوصفية وحالة الكيان وملخص التشغيل.">
|
||||
<img src="/images/checkpoint-tui-detail-overview.png" alt="Checkpoint detail overview tab" />
|
||||
</Frame>
|
||||
|
||||
لوحة التفاصيل تعرض منطقتين قابلتين للتحرير:
|
||||
|
||||
- **Inputs** — مدخلات الـ kickoff الأصلية، معبأة مسبقا وقابلة للتحرير.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/checkpoint-tui-detail-inputs.png" alt="Editable kickoff inputs" />
|
||||
</Frame>
|
||||
|
||||
- **مخرجات المهام** — مخرجات المهام المكتملة. تحرير مخرج والضغط على **Fork** يبطل المهام التابعة لتعاد بالسياق المعدل.
|
||||
|
||||
<Frame>
|
||||
<img src="/images/checkpoint-tui-detail-tasks.png" alt="Editable task outputs" />
|
||||
</Frame>
|
||||
|
||||
<Frame caption="عرض التفرع — تأكيد فرع جديد من نقطة الحفظ المختارة.">
|
||||
<img src="/images/checkpoint-tui-details-fork.png" alt="Fork confirmation panel" />
|
||||
</Frame>
|
||||
|
||||
<Tip>
|
||||
مفيد لاستكشاف "ماذا لو": تفرع، عدل، راقب.
|
||||
</Tip>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="تفقد نقاط الحفظ بدون TUI" icon="magnifying-glass">
|
||||
```bash
|
||||
crewai checkpoint list ./my_checkpoints
|
||||
crewai checkpoint info ./my_checkpoints/<file>.json
|
||||
crewai checkpoint info ./.checkpoints.db
|
||||
```
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## المرجع
|
||||
|
||||
### `CheckpointConfig`
|
||||
|
||||
<ParamField path="location" type="str" default='"./.checkpoints"'>
|
||||
وجهة التخزين. مجلد لـ `JsonProvider`، مسار ملف قاعدة بيانات لـ `SqliteProvider`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="on_events" type='list[CheckpointEventType | Literal["*"]]' default='["task_completed"]'>
|
||||
أنواع الأحداث التي تطلق نقطة حفظ. `CheckpointEventType` هو `Literal` — مدقق الأنواع يكمل تلقائيا ويرفض القيم غير المدعومة. راجع [أنواع الأحداث](#أنواع-الأحداث) للقائمة الكاملة.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="provider" type="BaseProvider" default="JsonProvider()">
|
||||
واجهة التخزين. `JsonProvider` أو `SqliteProvider`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="max_checkpoints" type="int | None" default="None">
|
||||
الحد الاقصى لنقاط الحفظ المحتفظ بها. الأقدم تحذف بعد كل كتابة.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="restore_from" type="Path | str | None" default="None">
|
||||
نقطة الحفظ المراد استعادتها عند تمريرها عبر `from_checkpoint`.
|
||||
</ParamField>
|
||||
|
||||
### قيم حقل `checkpoint`
|
||||
|
||||
مقبولة في `Crew` و`Flow` و`Agent`.
|
||||
|
||||
<ParamField path="None" type="افتراضي">
|
||||
يرث من الأب.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="True" type="bool">
|
||||
تفعيل بالإعدادات الافتراضية.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="False" type="bool">
|
||||
انسحاب صريح. يوقف الوراثة.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="CheckpointConfig(...)" type="CheckpointConfig">
|
||||
إعدادات مخصصة.
|
||||
</ParamField>
|
||||
|
||||
### أنواع الأحداث
|
||||
|
||||
يقبل `on_events` أي مجموعة من قيم `CheckpointEventType`. الافتراضي `["task_completed"]` يكتب نقطة حفظ لكل مهمة منتهية، و`["*"]` يطابق جميع الأحداث.
|
||||
|
||||
<Warning>
|
||||
`["*"]` والأحداث عالية التردد مثل `llm_call_completed` تكتب نقاط حفظ كثيرة وقد تضر بالاداء. استخدمها مع `max_checkpoints`.
|
||||
</Warning>
|
||||
|
||||
<Expandable title="جميع الأحداث المدعومة">
|
||||
|
||||
- **Task** — `task_started`, `task_completed`, `task_failed`, `task_evaluation`
|
||||
- **Crew** — `crew_kickoff_started`, `crew_kickoff_completed`, `crew_kickoff_failed`, `crew_train_started`, `crew_train_completed`, `crew_train_failed`, `crew_test_started`, `crew_test_completed`, `crew_test_failed`, `crew_test_result`
|
||||
- **Agent** — `agent_execution_started`, `agent_execution_completed`, `agent_execution_error`, `lite_agent_execution_started`, `lite_agent_execution_completed`, `lite_agent_execution_error`, `agent_evaluation_started`, `agent_evaluation_completed`, `agent_evaluation_failed`
|
||||
- **Flow** — `flow_created`, `flow_started`, `flow_finished`, `flow_paused`, `method_execution_started`, `method_execution_finished`, `method_execution_failed`, `method_execution_paused`, `human_feedback_requested`, `human_feedback_received`, `flow_input_requested`, `flow_input_received`
|
||||
- **LLM** — `llm_call_started`, `llm_call_completed`, `llm_call_failed`, `llm_stream_chunk`, `llm_thinking_chunk`
|
||||
- **LLM Guardrail** — `llm_guardrail_started`, `llm_guardrail_completed`, `llm_guardrail_failed`
|
||||
- **Tool** — `tool_usage_started`, `tool_usage_finished`, `tool_usage_error`, `tool_validate_input_error`, `tool_selection_error`, `tool_execution_error`
|
||||
- **Memory** — `memory_save_started`, `memory_save_completed`, `memory_save_failed`, `memory_query_started`, `memory_query_completed`, `memory_query_failed`, `memory_retrieval_started`, `memory_retrieval_completed`, `memory_retrieval_failed`
|
||||
- **Knowledge** — `knowledge_search_query_started`, `knowledge_search_query_completed`, `knowledge_query_started`, `knowledge_query_completed`, `knowledge_query_failed`, `knowledge_search_query_failed`
|
||||
- **Reasoning** — `agent_reasoning_started`, `agent_reasoning_completed`, `agent_reasoning_failed`
|
||||
- **MCP** — `mcp_connection_started`, `mcp_connection_completed`, `mcp_connection_failed`, `mcp_tool_execution_started`, `mcp_tool_execution_completed`, `mcp_tool_execution_failed`, `mcp_config_fetch_failed`
|
||||
- **Observation** — `step_observation_started`, `step_observation_completed`, `step_observation_failed`, `plan_refinement`, `plan_replan_triggered`, `goal_achieved_early`
|
||||
- **Skill** — `skill_discovery_started`, `skill_discovery_completed`, `skill_loaded`, `skill_activated`, `skill_load_failed`
|
||||
- **Logging** — `agent_logs_started`, `agent_logs_execution`
|
||||
- **A2A** — `a2a_delegation_started`, `a2a_delegation_completed`, `a2a_conversation_started`, `a2a_conversation_completed`, `a2a_message_sent`, `a2a_response_received`, `a2a_polling_started`, `a2a_polling_status`, `a2a_push_notification_registered`, `a2a_push_notification_received`, `a2a_push_notification_sent`, `a2a_push_notification_timeout`, `a2a_streaming_started`, `a2a_streaming_chunk`, `a2a_agent_card_fetched`, `a2a_authentication_failed`, `a2a_artifact_received`, `a2a_connection_error`, `a2a_server_task_started`, `a2a_server_task_completed`, `a2a_server_task_canceled`, `a2a_server_task_failed`, `a2a_parallel_delegation_started`, `a2a_parallel_delegation_completed`, `a2a_transport_negotiated`, `a2a_content_type_negotiated`, `a2a_context_created`, `a2a_context_expired`, `a2a_context_idle`, `a2a_context_completed`, `a2a_context_pruned`
|
||||
- **إشارات النظام** — `SIGTERM`, `SIGINT`, `SIGHUP`, `SIGTSTP`, `SIGCONT`
|
||||
- **حرف بدل** — `"*"` يطابق جميع الأحداث.
|
||||
|
||||
</Expandable>
|
||||
|
||||
### مزودات التخزين
|
||||
|
||||
<ParamField path="JsonProvider" type="provider">
|
||||
ملف واحد لكل نقطة حفظ بصيغة `<timestamp>_<uuid>.json` داخل `location`.
|
||||
</ParamField>
|
||||
|
||||
<ParamField path="SqliteProvider" type="provider">
|
||||
ملف قاعدة بيانات واحد في `location` مع journaling WAL.
|
||||
</ParamField>
|
||||
|
||||
### سطر الأوامر
|
||||
|
||||
| الامر | الغرض |
|
||||
|:------|:------|
|
||||
| `crewai checkpoint` | تشغيل TUI؛ كشف التخزين تلقائيا. |
|
||||
| `crewai checkpoint --location <path>` | تشغيل TUI على موقع محدد. |
|
||||
| `crewai checkpoint list <path>` | سرد نقاط الحفظ. |
|
||||
| `crewai checkpoint info <path>` | تفقد ملف نقطة حفظ أو آخر مدخل في قاعدة بيانات SQLite. |
|
||||