Compare commits

...

12 Commits

Author SHA1 Message Date
lorenzejay
86e78701f1 return message list for liteagent kickoff response 2025-10-09 09:14:57 -07:00
Lorenze Jay
13a514f8be chore: update crewAI and crewAI-tools dependencies to version 0.203.0 and 0.76.0 respectively (#3674)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
- Updated the `crewai-tools` dependency in `pyproject.toml` and `uv.lock` to version 0.76.0.
- Updated the `crewai` version in `__init__.py` to 0.203.0.
- Updated the dependency versions in the crew, flow, and tool templates to reflect the new `crewai` version.
2025-10-08 14:34:51 -07:00
Lorenze Jay
316b1cea69 docs: add guide for capturing telemetry logs in CrewAI AMP (#3673)
- Introduced a new documentation page detailing how to capture telemetry logs from CrewAI AMP deployments.
- Updated the main documentation to include the new guide in the enterprise section.
- Added prerequisites and step-by-step instructions for configuring OTEL collector setup.
- Included an example image for OTEL log collection capture to Datadog.
2025-10-08 14:06:10 -07:00
Lorenze Jay
6f2e39c0dd feat: enhance knowledge and guardrail event handling in Agent class (#3672)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Update Test Durations / update-durations (3.10) (push) Has been cancelled
Update Test Durations / update-durations (3.11) (push) Has been cancelled
Update Test Durations / update-durations (3.12) (push) Has been cancelled
Update Test Durations / update-durations (3.13) (push) Has been cancelled
* feat: enhance knowledge event handling in Agent class

- Updated the Agent class to include task context in knowledge retrieval events.
- Emitted new events for knowledge retrieval and query processes, capturing task and agent details.
- Refactored knowledge event classes to inherit from a base class for better structure and maintainability.
- Added tracing for knowledge events in the TraceCollectionListener to improve observability.

This change improves the tracking and management of knowledge queries and retrievals, facilitating better debugging and performance monitoring.

* refactor: remove task_id from knowledge event emissions in Agent class

- Removed the task_id parameter from various knowledge event emissions in the Agent class to streamline event handling.
- This change simplifies the event structure and focuses on the essential context of knowledge retrieval and query processes.

This refactor enhances the clarity of knowledge events and aligns with the recent improvements in event handling.

* surface association for guardrail events

* fix: improve LLM selection logic in converter

- Updated the logic for selecting the LLM in the convert_with_instructions function to handle cases where the agent may not have a function_calling_llm attribute.
- This change ensures that the converter can still function correctly by falling back to the standard LLM if necessary, enhancing robustness and preventing potential errors.

This fix improves the reliability of the conversion process when working with different agent configurations.

* fix test

* fix: enforce valid LLM instance requirement in converter

- Updated the convert_with_instructions function to ensure that a valid LLM instance is provided by the agent.
- If neither function_calling_llm nor the standard llm is available, a ValueError is raised, enhancing error handling and robustness.
- Improved error messaging for conversion failures to provide clearer feedback on issues encountered during the conversion process.

This change strengthens the reliability of the conversion process by ensuring that agents are properly configured with a valid LLM.
2025-10-08 11:53:13 -07:00
Lucas Gomide
8d93361cb3 docs: add missing /resume files (#3661)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-10-07 12:21:27 -04:00
Lucas Gomide
54ec245d84 docs: clarify webhook URL parameter in HITL workflows (#3660) 2025-10-07 12:06:11 -04:00
Vidit Ostwal
f589ab9b80 chore: load json tool input before console output
Co-authored-by: Greyson LaLonde <greyson.r.lalonde@gmail.com>
2025-10-07 10:18:28 -04:00
Greyson LaLonde
fadb59e0f0 chore: add scheduled cache rebuild to prevent expiration
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-10-06 11:45:28 -04:00
Greyson LaLonde
1a60848425 chore: remove crewAI.excalidraw file 2025-10-06 11:03:55 -04:00
Greyson LaLonde
0135163040 chore: remove mkdocs cache directory
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Remove obsolete .cache directory from mkdocs-material social plugin as the project no longer uses mkdocs for documentation.
2025-10-05 21:41:09 -04:00
Greyson LaLonde
dac5d6d664 fix: use system PATH for Docker binary instead of hardcoded path 2025-10-05 21:36:05 -04:00
Rip&Tear
f0f94f2540 fix: add CodeQL configuration to properly exclude template directories (#3641) 2025-10-06 08:21:51 +08:00
115 changed files with 7291 additions and 1818 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

21
.github/codeql/codeql-config.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: "CodeQL Config"
paths-ignore:
# Ignore template files - these are boilerplate code that shouldn't be analyzed
- "src/crewai/cli/templates/**"
# Ignore test cassettes - these are test fixtures/recordings
- "tests/cassettes/**"
# Ignore cache and build artifacts
- ".cache/**"
# Ignore documentation build artifacts
- "docs/.cache/**"
paths:
# Include all Python source code
- "src/**"
# Include tests (but exclude cassettes)
- "tests/**"
# Configure specific queries or packs if needed
# queries:
# - uses: security-and-quality

View File

@@ -7,6 +7,8 @@ on:
paths:
- "uv.lock"
- "pyproject.toml"
schedule:
- cron: "0 0 */5 * *" # Run every 5 days at midnight UTC to prevent cache expiration
workflow_dispatch:
permissions:

View File

@@ -73,6 +73,7 @@ jobs:
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config-file: ./.github/codeql/codeql-config.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

File diff suppressed because it is too large Load Diff

View File

@@ -397,6 +397,7 @@
"en/enterprise/guides/kickoff-crew",
"en/enterprise/guides/update-crew",
"en/enterprise/guides/enable-crew-studio",
"en/enterprise/guides/capture_telemetry_logs",
"en/enterprise/guides/azure-openai-setup",
"en/enterprise/guides/tool-repository",
"en/enterprise/guides/react-component-export",
@@ -421,6 +422,7 @@
"en/api-reference/introduction",
"en/api-reference/inputs",
"en/api-reference/kickoff",
"en/api-reference/resume",
"en/api-reference/status"
]
}
@@ -827,6 +829,7 @@
"pt-BR/api-reference/introduction",
"pt-BR/api-reference/inputs",
"pt-BR/api-reference/kickoff",
"pt-BR/api-reference/resume",
"pt-BR/api-reference/status"
]
}
@@ -1239,6 +1242,7 @@
"ko/api-reference/introduction",
"ko/api-reference/inputs",
"ko/api-reference/kickoff",
"ko/api-reference/resume",
"ko/api-reference/status"
]
}

View File

@@ -0,0 +1,6 @@
---
title: "POST /resume"
description: "Resume crew execution with human feedback"
openapi: "/enterprise-api.en.yaml POST /resume"
mode: "wide"
---

View File

@@ -0,0 +1,35 @@
---
title: "Open Telemetry Logs"
description: "Understand how to capture telemetry logs from your CrewAI AMP deployments"
icon: "magnifying-glass-chart"
mode: "wide"
---
CrewAI AMP provides a powerful way to capture telemetry logs from your deployments. This allows you to monitor the performance of your agents and workflows, and to debug issues that may arise.
## Prerequisites
<CardGroup cols={2}>
<Card title="ENTERPRISE OTEL SETUP enabled" icon="users">
Your organization should have ENTERPRISE OTEL SETUP enabled
</Card>
<Card title="OTEL collector setup" icon="server">
Your organization should have an OTEL collector setup or a provider like Datadog log intake setup
</Card>
</CardGroup>
## How to capture telemetry logs
1. Go to settings/organization tab
2. Configure your OTEL collector setup
3. Save
Example to setup OTEL log collection capture to Datadog.
<Frame>
![Capture Telemetry Logs](/images/crewai-otel-export.png)
</Frame>

View File

@@ -40,6 +40,28 @@ Human-In-The-Loop (HITL) is a powerful approach that combines artificial intelli
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Crew Resume Endpoint" />
</Frame>
<Warning>
**Critical: Webhook URLs Must Be Provided Again**:
You **must** provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) in the resume call that you used in the kickoff call. Webhook configurations are **NOT** automatically carried over from kickoff - they must be explicitly included in the resume request to continue receiving notifications for task completion, agent steps, and crew completion.
</Warning>
Example resume call with webhooks:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "Great work! Please add more details.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**Feedback Impact on Task Execution**:
It's crucial to exercise care when providing feedback, as the entire feedback content will be incorporated as additional context for further task executions.
@@ -76,4 +98,4 @@ HITL workflows are particularly valuable for:
- Complex decision-making scenarios
- Sensitive or high-stakes operations
- Creative tasks requiring human judgment
- Compliance and regulatory reviews
- Compliance and regulatory reviews

View File

@@ -79,6 +79,28 @@ Human-in-the-Loop (HITL) is a powerful approach that combines artificial intelli
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Crew Resume Endpoint" />
</Frame>
<Warning>
**Critical: Webhook URLs Must Be Provided Again**:
You **must** provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) in the resume call that you used in the kickoff call. Webhook configurations are **NOT** automatically carried over from kickoff - they must be explicitly included in the resume request to continue receiving notifications for task completion, agent steps, and crew completion.
</Warning>
Example resume call with webhooks:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "Great work! Please add more details.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**Feedback Impact on Task Execution**:
It's crucial to exercise care when providing feedback, as the entire feedback content will be incorporated as additional context for further task executions.

View File

@@ -276,6 +276,134 @@ paths:
'500':
$ref: '#/components/responses/ServerError'
/resume:
post:
summary: Resume Crew Execution with Human Feedback
description: |
**📋 Reference Example Only** - *This shows the request format. To test with your actual crew, copy the cURL example and replace the URL + token with your real values.*
Resume a paused crew execution with human feedback for Human-in-the-Loop (HITL) workflows.
When a task with `human_input=True` completes, the crew execution pauses and waits for human feedback.
**IMPORTANT**: You must provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)
that were used in the original kickoff call. Webhook configurations are NOT automatically carried over -
they must be explicitly provided in the resume request to continue receiving notifications.
operationId: resumeCrewExecution
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- execution_id
- task_id
- human_feedback
- is_approve
properties:
execution_id:
type: string
format: uuid
description: The unique identifier for the crew execution (from kickoff)
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id:
type: string
description: The ID of the task that requires human feedback
example: "research_task"
human_feedback:
type: string
description: Your feedback on the task output. This will be incorporated as additional context for subsequent task executions.
example: "Great research! Please add more details about recent developments in the field."
is_approve:
type: boolean
description: "Whether you approve the task output: true = positive feedback (continue), false = negative feedback (retry task)"
example: true
taskWebhookUrl:
type: string
format: uri
description: Callback URL executed after each task completion. MUST be provided to continue receiving task notifications.
example: "https://your-server.com/webhooks/task"
stepWebhookUrl:
type: string
format: uri
description: Callback URL executed after each agent thought/action. MUST be provided to continue receiving step notifications.
example: "https://your-server.com/webhooks/step"
crewWebhookUrl:
type: string
format: uri
description: Callback URL executed when the crew execution completes. MUST be provided to receive completion notification.
example: "https://your-server.com/webhooks/crew"
examples:
approve_and_continue:
summary: Approve task and continue execution
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "research_task"
human_feedback: "Excellent research! Proceed to the next task."
is_approve: true
taskWebhookUrl: "https://api.example.com/webhooks/task"
stepWebhookUrl: "https://api.example.com/webhooks/step"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
request_revision:
summary: Request task revision with feedback
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "analysis_task"
human_feedback: "Please include more quantitative data and cite your sources."
is_approve: false
taskWebhookUrl: "https://api.example.com/webhooks/task"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
responses:
'200':
description: Execution resumed successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: ["resumed", "retrying", "completed"]
description: Status of the resumed execution
example: "resumed"
message:
type: string
description: Human-readable message about the resume operation
example: "Execution resumed successfully"
examples:
resumed:
summary: Execution resumed with positive feedback
value:
status: "resumed"
message: "Execution resumed successfully"
retrying:
summary: Task will be retried with negative feedback
value:
status: "retrying"
message: "Task will be retried with your feedback"
'400':
description: Invalid request body or execution not in pending state
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Invalid Request"
message: "Execution is not in pending human input state"
'401':
$ref: '#/components/responses/UnauthorizedError'
'404':
description: Execution ID or Task ID not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Not Found"
message: "Execution ID not found"
'500':
$ref: '#/components/responses/ServerError'
components:
securitySchemes:
BearerAuth:

View File

@@ -276,6 +276,134 @@ paths:
'500':
$ref: '#/components/responses/ServerError'
/resume:
post:
summary: Resume Crew Execution with Human Feedback
description: |
**📋 Reference Example Only** - *This shows the request format. To test with your actual crew, copy the cURL example and replace the URL + token with your real values.*
Resume a paused crew execution with human feedback for Human-in-the-Loop (HITL) workflows.
When a task with `human_input=True` completes, the crew execution pauses and waits for human feedback.
**IMPORTANT**: You must provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)
that were used in the original kickoff call. Webhook configurations are NOT automatically carried over -
they must be explicitly provided in the resume request to continue receiving notifications.
operationId: resumeCrewExecution
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- execution_id
- task_id
- human_feedback
- is_approve
properties:
execution_id:
type: string
format: uuid
description: The unique identifier for the crew execution (from kickoff)
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id:
type: string
description: The ID of the task that requires human feedback
example: "research_task"
human_feedback:
type: string
description: Your feedback on the task output. This will be incorporated as additional context for subsequent task executions.
example: "Great research! Please add more details about recent developments in the field."
is_approve:
type: boolean
description: "Whether you approve the task output: true = positive feedback (continue), false = negative feedback (retry task)"
example: true
taskWebhookUrl:
type: string
format: uri
description: Callback URL executed after each task completion. MUST be provided to continue receiving task notifications.
example: "https://your-server.com/webhooks/task"
stepWebhookUrl:
type: string
format: uri
description: Callback URL executed after each agent thought/action. MUST be provided to continue receiving step notifications.
example: "https://your-server.com/webhooks/step"
crewWebhookUrl:
type: string
format: uri
description: Callback URL executed when the crew execution completes. MUST be provided to receive completion notification.
example: "https://your-server.com/webhooks/crew"
examples:
approve_and_continue:
summary: Approve task and continue execution
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "research_task"
human_feedback: "Excellent research! Proceed to the next task."
is_approve: true
taskWebhookUrl: "https://api.example.com/webhooks/task"
stepWebhookUrl: "https://api.example.com/webhooks/step"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
request_revision:
summary: Request task revision with feedback
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "analysis_task"
human_feedback: "Please include more quantitative data and cite your sources."
is_approve: false
taskWebhookUrl: "https://api.example.com/webhooks/task"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
responses:
'200':
description: Execution resumed successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: ["resumed", "retrying", "completed"]
description: Status of the resumed execution
example: "resumed"
message:
type: string
description: Human-readable message about the resume operation
example: "Execution resumed successfully"
examples:
resumed:
summary: Execution resumed with positive feedback
value:
status: "resumed"
message: "Execution resumed successfully"
retrying:
summary: Task will be retried with negative feedback
value:
status: "retrying"
message: "Task will be retried with your feedback"
'400':
description: Invalid request body or execution not in pending state
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Invalid Request"
message: "Execution is not in pending human input state"
'401':
$ref: '#/components/responses/UnauthorizedError'
'404':
description: Execution ID or Task ID not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Not Found"
message: "Execution ID not found"
'500':
$ref: '#/components/responses/ServerError'
components:
securitySchemes:
BearerAuth:

View File

@@ -120,6 +120,134 @@ paths:
'500':
$ref: '#/components/responses/ServerError'
/resume:
post:
summary: Resume Crew Execution with Human Feedback
description: |
**📋 Reference Example Only** - *This shows the request format. To test with your actual crew, copy the cURL example and replace the URL + token with your real values.*
Resume a paused crew execution with human feedback for Human-in-the-Loop (HITL) workflows.
When a task with `human_input=True` completes, the crew execution pauses and waits for human feedback.
**IMPORTANT**: You must provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)
that were used in the original kickoff call. Webhook configurations are NOT automatically carried over -
they must be explicitly provided in the resume request to continue receiving notifications.
operationId: resumeCrewExecution
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- execution_id
- task_id
- human_feedback
- is_approve
properties:
execution_id:
type: string
format: uuid
description: The unique identifier for the crew execution (from kickoff)
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id:
type: string
description: The ID of the task that requires human feedback
example: "research_task"
human_feedback:
type: string
description: Your feedback on the task output. This will be incorporated as additional context for subsequent task executions.
example: "Great research! Please add more details about recent developments in the field."
is_approve:
type: boolean
description: "Whether you approve the task output: true = positive feedback (continue), false = negative feedback (retry task)"
example: true
taskWebhookUrl:
type: string
format: uri
description: Callback URL executed after each task completion. MUST be provided to continue receiving task notifications.
example: "https://your-server.com/webhooks/task"
stepWebhookUrl:
type: string
format: uri
description: Callback URL executed after each agent thought/action. MUST be provided to continue receiving step notifications.
example: "https://your-server.com/webhooks/step"
crewWebhookUrl:
type: string
format: uri
description: Callback URL executed when the crew execution completes. MUST be provided to receive completion notification.
example: "https://your-server.com/webhooks/crew"
examples:
approve_and_continue:
summary: Approve task and continue execution
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "research_task"
human_feedback: "Excellent research! Proceed to the next task."
is_approve: true
taskWebhookUrl: "https://api.example.com/webhooks/task"
stepWebhookUrl: "https://api.example.com/webhooks/step"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
request_revision:
summary: Request task revision with feedback
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "analysis_task"
human_feedback: "Please include more quantitative data and cite your sources."
is_approve: false
taskWebhookUrl: "https://api.example.com/webhooks/task"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
responses:
'200':
description: Execution resumed successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: ["resumed", "retrying", "completed"]
description: Status of the resumed execution
example: "resumed"
message:
type: string
description: Human-readable message about the resume operation
example: "Execution resumed successfully"
examples:
resumed:
summary: Execution resumed with positive feedback
value:
status: "resumed"
message: "Execution resumed successfully"
retrying:
summary: Task will be retried with negative feedback
value:
status: "retrying"
message: "Task will be retried with your feedback"
'400':
description: Invalid request body or execution not in pending state
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Invalid Request"
message: "Execution is not in pending human input state"
'401':
$ref: '#/components/responses/UnauthorizedError'
'404':
description: Execution ID or Task ID not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Not Found"
message: "Execution ID not found"
'500':
$ref: '#/components/responses/ServerError'
components:
securitySchemes:
BearerAuth:

View File

@@ -156,6 +156,134 @@ paths:
'500':
$ref: '#/components/responses/ServerError'
/resume:
post:
summary: Resume Crew Execution with Human Feedback
description: |
**📋 Reference Example Only** - *This shows the request format. To test with your actual crew, copy the cURL example and replace the URL + token with your real values.*
Resume a paused crew execution with human feedback for Human-in-the-Loop (HITL) workflows.
When a task with `human_input=True` completes, the crew execution pauses and waits for human feedback.
**IMPORTANT**: You must provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)
that were used in the original kickoff call. Webhook configurations are NOT automatically carried over -
they must be explicitly provided in the resume request to continue receiving notifications.
operationId: resumeCrewExecution
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- execution_id
- task_id
- human_feedback
- is_approve
properties:
execution_id:
type: string
format: uuid
description: The unique identifier for the crew execution (from kickoff)
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id:
type: string
description: The ID of the task that requires human feedback
example: "research_task"
human_feedback:
type: string
description: Your feedback on the task output. This will be incorporated as additional context for subsequent task executions.
example: "Great research! Please add more details about recent developments in the field."
is_approve:
type: boolean
description: "Whether you approve the task output: true = positive feedback (continue), false = negative feedback (retry task)"
example: true
taskWebhookUrl:
type: string
format: uri
description: Callback URL executed after each task completion. MUST be provided to continue receiving task notifications.
example: "https://your-server.com/webhooks/task"
stepWebhookUrl:
type: string
format: uri
description: Callback URL executed after each agent thought/action. MUST be provided to continue receiving step notifications.
example: "https://your-server.com/webhooks/step"
crewWebhookUrl:
type: string
format: uri
description: Callback URL executed when the crew execution completes. MUST be provided to receive completion notification.
example: "https://your-server.com/webhooks/crew"
examples:
approve_and_continue:
summary: Approve task and continue execution
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "research_task"
human_feedback: "Excellent research! Proceed to the next task."
is_approve: true
taskWebhookUrl: "https://api.example.com/webhooks/task"
stepWebhookUrl: "https://api.example.com/webhooks/step"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
request_revision:
summary: Request task revision with feedback
value:
execution_id: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
task_id: "analysis_task"
human_feedback: "Please include more quantitative data and cite your sources."
is_approve: false
taskWebhookUrl: "https://api.example.com/webhooks/task"
crewWebhookUrl: "https://api.example.com/webhooks/crew"
responses:
'200':
description: Execution resumed successfully
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum: ["resumed", "retrying", "completed"]
description: Status of the resumed execution
example: "resumed"
message:
type: string
description: Human-readable message about the resume operation
example: "Execution resumed successfully"
examples:
resumed:
summary: Execution resumed with positive feedback
value:
status: "resumed"
message: "Execution resumed successfully"
retrying:
summary: Task will be retried with negative feedback
value:
status: "retrying"
message: "Task will be retried with your feedback"
'400':
description: Invalid request body or execution not in pending state
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Invalid Request"
message: "Execution is not in pending human input state"
'401':
$ref: '#/components/responses/UnauthorizedError'
'404':
description: Execution ID or Task ID not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: "Not Found"
message: "Execution ID not found"
'500':
$ref: '#/components/responses/ServerError'
components:
securitySchemes:
BearerAuth:

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

View File

@@ -0,0 +1,6 @@
---
title: "POST /resume"
description: "인간 피드백으로 crew 실행 재개"
openapi: "/enterprise-api.ko.yaml POST /resume"
mode: "wide"
---

View File

@@ -40,6 +40,28 @@ mode: "wide"
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Crew Resume Endpoint" />
</Frame>
<Warning>
**중요: Webhook URL을 다시 제공해야 합니다**:
kickoff 호출에서 사용한 것과 동일한 webhook URL(`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)을 resume 호출에서 **반드시** 제공해야 합니다. Webhook 설정은 kickoff에서 자동으로 전달되지 **않으므로**, 작업 완료, 에이전트 단계, crew 완료에 대한 알림을 계속 받으려면 resume 요청에 명시적으로 포함해야 합니다.
</Warning>
Webhook을 포함한 resume 호출 예시:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "훌륭한 작업입니다! 더 자세한 내용을 추가해주세요.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**피드백이 작업 실행에 미치는 영향**:
피드백 전체 내용이 이후 작업 실행을 위한 추가 컨텍스트로 통합되므로 피드백 제공 시 신중함이 매우 중요합니다.
@@ -76,4 +98,4 @@ HITL 워크플로우는 특히 다음과 같은 경우에 유용합니다:
- 복잡한 의사 결정 시나리오
- 민감하거나 위험도가 높은 작업
- 인간의 판단이 필요한 창의적 작업
- 준수 및 규제 검토
- 준수 및 규제 검토

View File

@@ -40,6 +40,28 @@ mode: "wide"
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Crew Resume Endpoint" />
</Frame>
<Warning>
**중요: Webhook URL을 다시 제공해야 합니다**:
kickoff 호출에서 사용한 것과 동일한 webhook URL(`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`)을 resume 호출에서 **반드시** 제공해야 합니다. Webhook 설정은 kickoff에서 자동으로 전달되지 **않으므로**, 작업 완료, 에이전트 단계, crew 완료에 대한 알림을 계속 받으려면 resume 요청에 명시적으로 포함해야 합니다.
</Warning>
Webhook을 포함한 resume 호출 예시:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "훌륭한 작업입니다! 더 자세한 내용을 추가해주세요.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**피드백이 작업 실행에 미치는 영향**:
피드백의 전체 내용이 추가 컨텍스트로서 이후 작업 실행에 통합되므로, 피드백 제공 시 신중을 기하는 것이 매우 중요합니다.
@@ -76,4 +98,4 @@ HITL 워크플로우는 다음과 같은 경우에 특히 유용합니다:
- 복잡한 의사결정 시나리오
- 민감하거나 고위험 작업
- 인간의 판단이 필요한 창의적 과제
- 컴플라이언스 및 규제 검토
- 컴플라이언스 및 규제 검토

View File

@@ -0,0 +1,6 @@
---
title: "POST /resume"
description: "Retomar execução do crew com feedback humano"
openapi: "/enterprise-api.pt-BR.yaml POST /resume"
mode: "wide"
---

View File

@@ -40,6 +40,28 @@ Human-In-The-Loop (HITL) é uma abordagem poderosa que combina inteligência art
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Crew Resume Endpoint" />
</Frame>
<Warning>
**Crítico: URLs de Webhook Devem Ser Fornecidas Novamente**:
Você **deve** fornecer as mesmas URLs de webhook (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) na chamada de resume que você usou na chamada de kickoff. As configurações de webhook **NÃO** são automaticamente transferidas do kickoff - elas devem ser explicitamente incluídas na solicitação de resume para continuar recebendo notificações de conclusão de tarefa, etapas do agente e conclusão do crew.
</Warning>
Exemplo de chamada resume com webhooks:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "Ótimo trabalho! Por favor, adicione mais detalhes.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**Impacto do Feedback na Execução da Tarefa**:
É crucial ter cuidado ao fornecer o feedback, pois todo o conteúdo do feedback será incorporado como contexto adicional para as próximas execuções da tarefa.
@@ -76,4 +98,4 @@ Workflows HITL são particularmente valiosos para:
- Cenários de tomada de decisão complexa
- Operações sensíveis ou de alto risco
- Tarefas criativas que exigem julgamento humano
- Revisões de conformidade e regulatórias
- Revisões de conformidade e regulatórias

View File

@@ -40,6 +40,28 @@ Human-in-the-Loop (HITL) é uma abordagem poderosa que combina a inteligência a
<Frame>
<img src="/images/enterprise/crew-resume-endpoint.png" alt="Endpoint de Retomada Crew" />
</Frame>
<Warning>
**Crítico: URLs de Webhook Devem Ser Fornecidas Novamente**:
Você **deve** fornecer as mesmas URLs de webhook (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) na chamada de resume que você usou na chamada de kickoff. As configurações de webhook **NÃO** são automaticamente transferidas do kickoff - elas devem ser explicitamente incluídas na solicitação de resume para continuar recebendo notificações de conclusão de tarefa, etapas do agente e conclusão do crew.
</Warning>
Exemplo de chamada resume com webhooks:
```bash
curl -X POST {BASE_URL}/resume \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
"task_id": "research_task",
"human_feedback": "Ótimo trabalho! Por favor, adicione mais detalhes.",
"is_approve": true,
"taskWebhookUrl": "https://your-server.com/webhooks/task",
"stepWebhookUrl": "https://your-server.com/webhooks/step",
"crewWebhookUrl": "https://your-server.com/webhooks/crew"
}'
```
<Warning>
**Impacto do Feedback na Execução da Tarefa**:
É fundamental ter cuidado ao fornecer feedback, pois todo o conteúdo do feedback será incorporado como contexto adicional para execuções futuras da tarefa.
@@ -76,4 +98,4 @@ Workflows HITL são particularmente valiosos para:
- Cenários de tomada de decisão complexa
- Operações sensíveis ou de alto risco
- Tarefas criativas que requerem julgamento humano
- Revisões de conformidade e regulamentação
- Revisões de conformidade e regulamentação

View File

@@ -49,7 +49,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
[project.optional-dependencies]
tools = [
"crewai-tools>=0.74.0",
"crewai-tools>=0.76.0",
]
embeddings = [
"tiktoken~=0.8.0"

View File

@@ -40,7 +40,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
_suppress_pydantic_deprecation_warnings()
__version__ = "0.201.1"
__version__ = "0.203.0"
_telemetry_submitted = False

View File

@@ -53,6 +53,7 @@ from crewai.utilities.converter import generate_model_description
from crewai.utilities.llm_utils import create_llm
from crewai.utilities.token_counter_callback import TokenCalcHandler
from crewai.utilities.training_handler import CrewTrainingHandler
from crewai.utilities.types import LLMMessage
class Agent(BaseAgent):
@@ -174,7 +175,7 @@ class Agent(BaseAgent):
)
@model_validator(mode="before")
def validate_from_repository(cls, v): # noqa: N805
def validate_from_repository(cls, v): # noqa: N805
if v is not None and (from_repository := v.get("from_repository")):
return load_agent_from_repository(from_repository) | v
return v
@@ -347,15 +348,16 @@ class Agent(BaseAgent):
)
if self.knowledge or (self.crew and self.crew.knowledge):
crewai_event_bus.emit(
self,
event=KnowledgeRetrievalStartedEvent(
agent=self,
),
)
try:
self.knowledge_search_query = self._get_knowledge_search_query(
task_prompt
task_prompt, task
)
crewai_event_bus.emit(
self,
event=KnowledgeRetrievalStartedEvent(
from_task=task,
from_agent=self,
),
)
if self.knowledge_search_query:
# Quering agent specific knowledge
@@ -385,7 +387,8 @@ class Agent(BaseAgent):
self,
event=KnowledgeRetrievalCompletedEvent(
query=self.knowledge_search_query,
agent=self,
from_task=task,
from_agent=self,
retrieved_knowledge=(
(self.agent_knowledge_context or "")
+ (
@@ -403,8 +406,9 @@ class Agent(BaseAgent):
self,
event=KnowledgeSearchQueryFailedEvent(
query=self.knowledge_search_query or "",
agent=self,
error=str(e),
from_task=task,
from_agent=self,
),
)
@@ -702,7 +706,7 @@ class Agent(BaseAgent):
try:
subprocess.run(
["/usr/bin/docker", "info"],
["docker", "info"], # noqa: S607
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -728,13 +732,14 @@ class Agent(BaseAgent):
def set_fingerprint(self, fingerprint: Fingerprint):
self.security_config.fingerprint = fingerprint
def _get_knowledge_search_query(self, task_prompt: str) -> str | None:
def _get_knowledge_search_query(self, task_prompt: str, task: Task) -> str | None:
"""Generate a search query for the knowledge base based on the task description."""
crewai_event_bus.emit(
self,
event=KnowledgeQueryStartedEvent(
task_prompt=task_prompt,
agent=self,
from_task=task,
from_agent=self,
),
)
query = self.i18n.slice("knowledge_search_query").format(
@@ -749,8 +754,9 @@ class Agent(BaseAgent):
crewai_event_bus.emit(
self,
event=KnowledgeQueryFailedEvent(
agent=self,
error="LLM is not compatible with knowledge search queries",
from_task=task,
from_agent=self,
),
)
return None
@@ -769,7 +775,8 @@ class Agent(BaseAgent):
self,
event=KnowledgeQueryCompletedEvent(
query=query,
agent=self,
from_task=task,
from_agent=self,
),
)
return rewritten_query
@@ -777,15 +784,16 @@ class Agent(BaseAgent):
crewai_event_bus.emit(
self,
event=KnowledgeQueryFailedEvent(
agent=self,
error=str(e),
from_task=task,
from_agent=self,
),
)
return None
def kickoff(
self,
messages: str | list[dict[str, str]],
messages: str | list[LLMMessage],
response_format: type[Any] | None = None,
) -> LiteAgentOutput:
"""
@@ -825,7 +833,7 @@ class Agent(BaseAgent):
async def kickoff_async(
self,
messages: str | list[dict[str, str]],
messages: str | list[LLMMessage],
response_format: type[Any] | None = None,
) -> LiteAgentOutput:
"""
@@ -855,6 +863,7 @@ class Agent(BaseAgent):
response_format=response_format,
i18n=self.i18n,
original_agent=self,
guardrail=self.guardrail,
)
return await lite_agent.kickoff_async(messages)

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]>=0.201.1,<1.0.0"
"crewai[tools]>=0.203.0,<1.0.0"
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]>=0.201.1,<1.0.0",
"crewai[tools]>=0.203.0,<1.0.0",
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.14"
dependencies = [
"crewai[tools]>=0.201.1"
"crewai[tools]>=0.203.0"
]
[tool.crewai]

View File

@@ -32,6 +32,13 @@ from crewai.events.types.flow_events import (
MethodExecutionFinishedEvent,
MethodExecutionStartedEvent,
)
from crewai.events.types.knowledge_events import (
KnowledgeQueryCompletedEvent,
KnowledgeQueryFailedEvent,
KnowledgeQueryStartedEvent,
KnowledgeRetrievalCompletedEvent,
KnowledgeRetrievalStartedEvent,
)
from crewai.events.types.llm_events import (
LLMCallCompletedEvent,
LLMCallFailedEvent,
@@ -310,6 +317,26 @@ class TraceCollectionListener(BaseEventListener):
def on_agent_reasoning_failed(source, event):
self._handle_action_event("agent_reasoning_failed", source, event)
@event_bus.on(KnowledgeRetrievalStartedEvent)
def on_knowledge_retrieval_started(source, event):
self._handle_action_event("knowledge_retrieval_started", source, event)
@event_bus.on(KnowledgeRetrievalCompletedEvent)
def on_knowledge_retrieval_completed(source, event):
self._handle_action_event("knowledge_retrieval_completed", source, event)
@event_bus.on(KnowledgeQueryStartedEvent)
def on_knowledge_query_started(source, event):
self._handle_action_event("knowledge_query_started", source, event)
@event_bus.on(KnowledgeQueryCompletedEvent)
def on_knowledge_query_completed(source, event):
self._handle_action_event("knowledge_query_completed", source, event)
@event_bus.on(KnowledgeQueryFailedEvent)
def on_knowledge_query_failed(source, event):
self._handle_action_event("knowledge_query_failed", source, event)
def _initialize_crew_batch(self, source: Any, event: Any):
"""Initialize trace batch"""
user_context = self._get_user_context()

View File

@@ -1,51 +1,60 @@
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import Any
from crewai.events.base_events import BaseEvent
class KnowledgeRetrievalStartedEvent(BaseEvent):
class KnowledgeEventBase(BaseEvent):
task_id: str | None = None
task_name: str | None = None
from_task: Any | None = None
from_agent: Any | None = None
agent_role: str | None = None
agent_id: str | None = None
def __init__(self, **data):
super().__init__(**data)
self._set_agent_params(data)
self._set_task_params(data)
class KnowledgeRetrievalStartedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge retrieval is started."""
type: str = "knowledge_search_query_started"
agent: BaseAgent
class KnowledgeRetrievalCompletedEvent(BaseEvent):
class KnowledgeRetrievalCompletedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge retrieval is completed."""
query: str
type: str = "knowledge_search_query_completed"
agent: BaseAgent
retrieved_knowledge: str
class KnowledgeQueryStartedEvent(BaseEvent):
class KnowledgeQueryStartedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge query is started."""
task_prompt: str
type: str = "knowledge_query_started"
agent: BaseAgent
class KnowledgeQueryFailedEvent(BaseEvent):
class KnowledgeQueryFailedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge query fails."""
type: str = "knowledge_query_failed"
agent: BaseAgent
error: str
class KnowledgeQueryCompletedEvent(BaseEvent):
class KnowledgeQueryCompletedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge query is completed."""
query: str
type: str = "knowledge_query_completed"
agent: BaseAgent
class KnowledgeSearchQueryFailedEvent(BaseEvent):
class KnowledgeSearchQueryFailedEvent(KnowledgeEventBase):
"""Event emitted when a knowledge search query fails."""
query: str
type: str = "knowledge_search_query_failed"
agent: BaseAgent
error: str

View File

@@ -5,7 +5,21 @@ from typing import Any
from crewai.events.base_events import BaseEvent
class LLMGuardrailStartedEvent(BaseEvent):
class LLMGuardrailBaseEvent(BaseEvent):
task_id: str | None = None
task_name: str | None = None
from_task: Any | None = None
from_agent: Any | None = None
agent_role: str | None = None
agent_id: str | None = None
def __init__(self, **data):
super().__init__(**data)
self._set_agent_params(data)
self._set_task_params(data)
class LLMGuardrailStartedEvent(LLMGuardrailBaseEvent):
"""Event emitted when a guardrail task starts
Attributes:
@@ -29,7 +43,7 @@ class LLMGuardrailStartedEvent(BaseEvent):
self.guardrail = getsource(self.guardrail).strip()
class LLMGuardrailCompletedEvent(BaseEvent):
class LLMGuardrailCompletedEvent(LLMGuardrailBaseEvent):
"""Event emitted when a guardrail task completes
Attributes:
@@ -44,3 +58,16 @@ class LLMGuardrailCompletedEvent(BaseEvent):
result: Any
error: str | None = None
retry_count: int
class LLMGuardrailFailedEvent(LLMGuardrailBaseEvent):
"""Event emitted when a guardrail task fails
Attributes:
error: The error message
retry_count: The number of times the guardrail has been retried
"""
type: str = "llm_guardrail_failed"
error: str
retry_count: int

View File

@@ -1377,7 +1377,7 @@ class ConsoleFormatter:
if isinstance(formatted_answer, AgentAction):
thought = re.sub(r"\n+", "\n", formatted_answer.thought)
formatted_json = json.dumps(
formatted_answer.tool_input,
json.loads(formatted_answer.tool_input),
indent=2,
ensure_ascii=False,
)

View File

@@ -4,6 +4,7 @@ import uuid
from collections.abc import Callable
from typing import (
Any,
Literal,
cast,
get_args,
get_origin,
@@ -62,6 +63,7 @@ from crewai.utilities.llm_utils import create_llm
from crewai.utilities.printer import Printer
from crewai.utilities.token_counter_callback import TokenCalcHandler
from crewai.utilities.tool_utils import execute_tool_and_check_finality
from crewai.utilities.types import LLMMessage
class LiteAgentOutput(BaseModel):
@@ -77,6 +79,7 @@ class LiteAgentOutput(BaseModel):
usage_metrics: dict[str, Any] | None = Field(
description="Token usage metrics for this execution", default=None
)
messages: list[LLMMessage] = Field(description="Messages of the agent", default=[])
def to_dict(self) -> dict[str, Any]:
"""Convert pydantic_output to a dictionary."""
@@ -180,7 +183,7 @@ class LiteAgent(FlowTrackable, BaseModel):
_token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess)
_cache_handler: CacheHandler = PrivateAttr(default_factory=CacheHandler)
_key: str = PrivateAttr(default_factory=lambda: str(uuid.uuid4()))
_messages: list[dict[str, str]] = PrivateAttr(default_factory=list)
_messages: list[LLMMessage] = PrivateAttr(default_factory=list)
_iterations: int = PrivateAttr(default=0)
_printer: Printer = PrivateAttr(default_factory=Printer)
_guardrail: Callable | None = PrivateAttr(default=None)
@@ -219,7 +222,6 @@ class LiteAgent(FlowTrackable, BaseModel):
raise TypeError(
f"Guardrail requires LLM instance of type BaseLLM, got {type(self.llm).__name__}"
)
self._guardrail = LLMGuardrail(description=self.guardrail, llm=self.llm)
return self
@@ -276,7 +278,7 @@ class LiteAgent(FlowTrackable, BaseModel):
"""Return the original role for compatibility with tool interfaces."""
return self.role
def kickoff(self, messages: str | list[dict[str, str]]) -> LiteAgentOutput:
def kickoff(self, messages: str | list[LLMMessage]) -> LiteAgentOutput:
"""
Execute the agent with the given messages.
@@ -359,6 +361,7 @@ class LiteAgent(FlowTrackable, BaseModel):
pydantic=formatted_result,
agent_role=self.role,
usage_metrics=usage_metrics.model_dump() if usage_metrics else None,
messages=self._messages,
)
# Process guardrail if set
@@ -368,6 +371,7 @@ class LiteAgent(FlowTrackable, BaseModel):
guardrail=self._guardrail,
retry_count=self._guardrail_retry_count,
event_source=self,
from_agent=self,
)
if not guardrail_result.success:
@@ -414,9 +418,7 @@ class LiteAgent(FlowTrackable, BaseModel):
return output
async def kickoff_async(
self, messages: str | list[dict[str, str]]
) -> LiteAgentOutput:
async def kickoff_async(self, messages: str | list[LLMMessage]) -> LiteAgentOutput:
"""
Execute the agent asynchronously with the given messages.
@@ -461,9 +463,7 @@ class LiteAgent(FlowTrackable, BaseModel):
return base_prompt
def _format_messages(
self, messages: str | list[dict[str, str]]
) -> list[dict[str, str]]:
def _format_messages(self, messages: str | list[LLMMessage]) -> list[LLMMessage]:
"""Format messages for the LLM."""
if isinstance(messages, str):
messages = [{"role": "user", "content": messages}]
@@ -471,7 +471,9 @@ class LiteAgent(FlowTrackable, BaseModel):
system_prompt = self._get_default_system_prompt()
# Add system message at the beginning
formatted_messages = [{"role": "system", "content": system_prompt}]
formatted_messages: list[LLMMessage] = [
{"role": "system", "content": system_prompt}
]
# Add the rest of the messages
formatted_messages.extend(messages)
@@ -583,6 +585,8 @@ class LiteAgent(FlowTrackable, BaseModel):
),
)
def _append_message(self, text: str, role: str = "assistant") -> None:
def _append_message(
self, text: str, role: Literal["user", "assistant", "system"] = "assistant"
) -> None:
"""Append a message to the message list with the given role."""
self._messages.append(format_message_for_llm(text, role=role))
self._messages.append(cast(LLMMessage, format_message_for_llm(text, role=role)))

View File

@@ -462,6 +462,8 @@ class Task(BaseModel):
guardrail=self._guardrail,
retry_count=self.retry_count,
event_source=self,
from_task=self,
from_agent=agent,
)
if not guardrail_result.success:
if self.retry_count >= self.guardrail_max_retries:

View File

@@ -31,6 +31,7 @@ from crewai.utilities.types import LLMMessage
if TYPE_CHECKING:
from crewai.agent import Agent
from crewai.lite_agent import LiteAgent
from crewai.task import Task
@@ -222,7 +223,7 @@ def get_llm_response(
callbacks: list[Callable[..., Any]],
printer: Printer,
from_task: Task | None = None,
from_agent: Agent | None = None,
from_agent: Agent | LiteAgent | None = None,
) -> str:
"""Call the LLM and return the response, handling any invalid responses.

View File

@@ -14,6 +14,7 @@ from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
if TYPE_CHECKING:
from crewai.agent import Agent
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.llm import LLM
from crewai.llms.base_llm import BaseLLM
@@ -143,7 +144,7 @@ def convert_to_model(
result: str,
output_pydantic: type[BaseModel] | None,
output_json: type[BaseModel] | None,
agent: Agent | None = None,
agent: Agent | BaseAgent | None = None,
converter_cls: type[Converter] | None = None,
) -> dict[str, Any] | BaseModel | str:
"""Convert a result string to a Pydantic model or JSON.
@@ -215,7 +216,7 @@ def handle_partial_json(
result: str,
model: type[BaseModel],
is_json_output: bool,
agent: Agent | None,
agent: Agent | BaseAgent | None,
converter_cls: type[Converter] | None = None,
) -> dict[str, Any] | BaseModel | str:
"""Handle partial JSON in a result string and convert to Pydantic model or dict.
@@ -260,7 +261,7 @@ def convert_with_instructions(
result: str,
model: type[BaseModel],
is_json_output: bool,
agent: Agent | None,
agent: Agent | BaseAgent | None,
converter_cls: type[Converter] | None = None,
) -> dict | BaseModel | str:
"""Convert a result string to a Pydantic model or JSON using instructions.
@@ -283,7 +284,12 @@ def convert_with_instructions(
"""
if agent is None:
raise TypeError("Agent must be provided if converter_cls is not specified.")
llm = agent.function_calling_llm or agent.llm
llm = getattr(agent, "function_calling_llm", None) or agent.llm
if llm is None:
raise ValueError("Agent must have a valid LLM instance for conversion")
instructions = get_conversion_instructions(model=model, llm=llm)
converter = create_converter(
agent=agent,
@@ -299,7 +305,7 @@ def convert_with_instructions(
if isinstance(exported_result, ConverterError):
Printer().print(
content=f"{exported_result.message} Using raw output instead.",
content=f"Failed to convert result to model: {exported_result}",
color="red",
)
return result
@@ -308,7 +314,7 @@ def convert_with_instructions(
def get_conversion_instructions(
model: type[BaseModel], llm: BaseLLM | LLM | str
model: type[BaseModel], llm: BaseLLM | LLM | str | Any
) -> str:
"""Generate conversion instructions based on the model and LLM capabilities.
@@ -357,7 +363,7 @@ class CreateConverterKwargs(TypedDict, total=False):
def create_converter(
agent: Agent | None = None,
agent: Agent | BaseAgent | None = None,
converter_cls: type[Converter] | None = None,
*args: Any,
**kwargs: Unpack[CreateConverterKwargs],

View File

@@ -7,7 +7,9 @@ from pydantic import BaseModel, Field, field_validator
from typing_extensions import Self
if TYPE_CHECKING:
from crewai.lite_agent import LiteAgentOutput
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.lite_agent import LiteAgent, LiteAgentOutput
from crewai.task import Task
from crewai.tasks.task_output import TaskOutput
@@ -79,6 +81,8 @@ def process_guardrail(
guardrail: Callable[[Any], tuple[bool, Any | str]],
retry_count: int,
event_source: Any | None = None,
from_agent: BaseAgent | LiteAgent | None = None,
from_task: Task | None = None,
) -> GuardrailResult:
"""Process the guardrail for the agent output.
@@ -95,14 +99,6 @@ def process_guardrail(
TypeError: If output is not a TaskOutput or LiteAgentOutput
ValueError: If guardrail is None
"""
from crewai.lite_agent import LiteAgentOutput
from crewai.tasks.task_output import TaskOutput
if not isinstance(output, (TaskOutput, LiteAgentOutput)):
raise TypeError("Output must be a TaskOutput or LiteAgentOutput")
if guardrail is None:
raise ValueError("Guardrail must not be None")
from crewai.events.event_bus import crewai_event_bus
from crewai.events.types.llm_guardrail_events import (
LLMGuardrailCompletedEvent,
@@ -111,7 +107,12 @@ def process_guardrail(
crewai_event_bus.emit(
event_source,
LLMGuardrailStartedEvent(guardrail=guardrail, retry_count=retry_count),
LLMGuardrailStartedEvent(
guardrail=guardrail,
retry_count=retry_count,
from_agent=from_agent,
from_task=from_task,
),
)
result = guardrail(output)
@@ -124,6 +125,8 @@ def process_guardrail(
result=guardrail_result.result,
error=guardrail_result.error,
retry_count=retry_count,
from_agent=from_agent,
from_task=from_task,
),
)

View File

@@ -12,6 +12,7 @@ from crewai.utilities.i18n import I18N
if TYPE_CHECKING:
from crewai.agent import Agent
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.llm import LLM
from crewai.llms.base_llm import BaseLLM
from crewai.task import Task
@@ -25,7 +26,7 @@ def execute_tool_and_check_finality(
agent_role: str | None = None,
tools_handler: ToolsHandler | None = None,
task: Task | None = None,
agent: Agent | None = None,
agent: Agent | BaseAgent | None = None,
function_calling_llm: BaseLLM | LLM | None = None,
fingerprint_context: dict[str, str] | None = None,
) -> ToolResult:

View File

@@ -2299,10 +2299,10 @@ def test_get_knowledge_search_query():
crew = Crew(agents=[agent], tasks=[task])
crew.kickoff()
mock_get_query.assert_called_once_with(task_prompt)
mock_get_query.assert_called_once_with(task_prompt, task)
with patch.object(agent.llm, "call") as mock_llm_call:
agent._get_knowledge_search_query(task_prompt)
agent._get_knowledge_search_query(task_prompt, task)
mock_llm_call.assert_called_once_with(
[

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More