Compare commits

..

13 Commits

Author SHA1 Message Date
Devin AI
196c86dbb2 Add API cross-references and finalize documentation improvements
Co-Authored-By: João <joao@crewai.com>
2025-06-21 21:14:31 +00:00
Devin AI
1df9b1b166 Add negative test cases and improve test coverage
- Add test for malformed template handling
- Add test for missing required parameters with proper error handling
- Improve test documentation and edge case coverage

Addresses GitHub review feedback from joaomdmoura and mplachta

Co-Authored-By: João <joao@crewai.com>
2025-06-21 21:01:12 +00:00
Devin AI
80e2c34b7f Address comprehensive GitHub review feedback
- Add explicit security warnings about prompt injection and stop sequence pitfalls
- Enhance troubleshooting section with additional actionable guidance
- Improve default parameter behavior documentation
- Add cross-references for better navigation
- Clean up duplicate warnings from previous commits

Addresses feedback from joaomdmoura and mplachta reviews

Co-Authored-By: João <joao@crewai.com>
2025-06-21 20:54:54 +00:00
Devin AI
16110623b5 Fix failing CI test by correcting Task API usage
- Replace non-existent 'output_format' attribute with 'output_json'
- Update test_custom_format_instructions to use correct Pydantic model approach
- Enhance test_stop_words_configuration to properly test agent executor creation
- Update documentation example to use correct API (output_json instead of output_format)
- Validated API corrections work with local test script

Co-Authored-By: João <joao@crewai.com>
2025-06-21 20:45:55 +00:00
Devin AI
a6d9741d18 Fix failing tests and address comprehensive GitHub review feedback
- Fix undefined i18n variable error in test_i18n_slice_access method
- Replace Mock tools with proper BaseTool instances to fix validation errors
- Add comprehensive docstrings to all test methods explaining validation purpose
- Add pytest fixtures for test isolation with @pytest.fixture(autouse=True)
- Add parametrized tests for agent initialization patterns using @pytest.mark.parametrize
- Add negative test cases for default template behavior and incomplete templates
- Remove unused Mock and patch imports to fix lint errors
- Improve test organization by moving Pydantic models to top of file
- Add metadata (title, description, categoryId, priority) to documentation frontmatter
- Add showLineNumbers to all Python code blocks for better readability
- Add explicit security warnings about stop sequence pitfalls and template injection
- Improve header hierarchy consistency using #### for subsections
- Add cross-references between troubleshooting sections
- Document default parameter behaviors explicitly
- Add additional troubleshooting steps for debugging prompts

Addresses all actionable feedback from GitHub reviews by joaomdmoura and mplachta.
Fixes failing CI tests by using proper CrewAI API patterns and BaseTool instances.

Co-Authored-By: João <joao@crewai.com>
2025-06-21 20:37:04 +00:00
Devin AI
f341d25fe6 Fix lint and import issues in test file
- Remove unused imports (pytest, Crew) to fix lint errors
- Fix LiteAgent import path from crewai.lite_agent
- Resolves CI test collection error for Python 3.10

Co-Authored-By: João <joao@crewai.com>
2025-06-21 20:24:09 +00:00
Devin AI
ba052dc7f3 Add comprehensive prompt customization documentation
- Create detailed guide explaining CrewAI's prompt generation system
- Document template system stored in translations/en.json
- Explain prompt assembly process using Prompts class
- Document LiteAgent prompt generation methods
- Show how to customize system/user prompts with templates
- Explain format parameter and structured output control
- Document stop words configuration through response_template
- Add practical examples for common customization scenarios
- Include test file validating all documentation examples

Addresses issue #3045: How system and user prompts are generated

Co-Authored-By: João <joao@crewai.com>
2025-06-21 20:20:16 +00:00
Lucas Gomide
59032817c7 docs: update recommendation filters for MCP and Enterprise tools (#3041)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-06-20 13:35:26 -04:00
Lucas Gomide
e9d8a853ea feat: support to initialize a tool from defined Tool attributes (#3023)
* feat: support to initialize a tool from defined Tool attributes

* fix: ensure Agent is able to load a list of Tools dynamically
2025-06-20 10:53:37 -04:00
Vidit Ostwal
463ea2b97f Fixed type annotation in task (#3021)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* Added Union of List of Task, None, NotSpecified

* Seems like a flaky test

* Fixed run time issue

* Fixed Linting issues

* fix pydantic error

* aesthetic changes

---------

Co-authored-by: Lucas Gomide <lucaslg200@gmail.com>
2025-06-19 14:37:46 -04:00
Jannik Maierhöfer
ec2903e5ee fix: upgrade langfuse code examples to langfuse python sdk v3 (#3030)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Co-authored-by: Tony Kipkemboi <iamtonykipkemboi@gmail.com>
2025-06-19 12:18:33 -04:00
Daniel Barreto
4364585ebc Remove mkdocs from project dependencies (#3036)
CrewAI has been using https://mintlify.com/
to serve its docs
2025-06-19 11:21:08 -04:00
Lorenze Jay
0a6b7c655b docs: add comprehensive integration documentation for various services (#2999)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
- Introduced detailed documentation for integrations including Asana, Box, ClickUp, GitHub, Gmail, Google Calendar, Google Sheets, HubSpot, Jira, Linear, Notion, Salesforce, Shopify, Slack, Stripe, and Zendesk.
- Updated main docs.json to include a new "Integration Docs" section, organizing the documentation for easy access.
- Each integration includes setup instructions, available actions, and example tasks to streamline user onboarding and usage.
2025-06-18 10:21:18 -04:00
13 changed files with 934 additions and 543 deletions

View File

@@ -1,45 +0,0 @@
name: Deploy MkDocs
on:
release:
types: [published]
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Calculate requirements hash
id: req-hash
run: echo "::set-output name=hash::$(sha256sum requirements-doc.txt | awk '{print $1}')"
- name: Setup cache
uses: actions/cache@v4
with:
key: mkdocs-material-${{ steps.req-hash.outputs.hash }}
path: .cache
restore-keys: |
mkdocs-material-
- name: Install Requirements
run: |
sudo apt-get update &&
sudo apt-get install pngquant &&
pip install mkdocs-material mkdocs-material-extensions pillow cairosvg
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Build and deploy MkDocs
run: mkdocs gh-deploy --force

View File

@@ -124,7 +124,7 @@ from crewai_tools import CrewaiEnterpriseTools
enterprise_tools = CrewaiEnterpriseTools(
actions_list=["gmail_find_email"] # only gmail_find_email tool will be available
)
gmail_tool = enterprise_tools[0]
gmail_tool = enterprise_tools["gmail_find_email"]
gmail_agent = Agent(
role="Gmail Manager",

View File

@@ -0,0 +1,343 @@
---
title: "Customize Agent Prompts"
description: "Learn how to customize system and user prompts in CrewAI agents for precise control over agent behavior and output formatting."
categoryId: "how-to-guides"
priority: 1
---
# Customize Agent Prompts
CrewAI provides fine-grained control over how agents generate and format their responses through a sophisticated prompt generation system. This guide explains how system and user prompts are constructed and how you can customize them for your specific use cases.
## Understanding Prompt Generation
CrewAI uses a template-based system to generate prompts, combining different components based on agent configuration:
### Core Prompt Components
All prompt templates are stored in the internationalization system and include:
- **Role Playing**: `"You are {role}. {backstory}\nYour personal goal is: {goal}"`
- **Tools**: Instructions for agents with access to tools
- **No Tools**: Instructions for agents without tools
- **Task**: The specific task execution prompt
- **Format Instructions**: Output formatting requirements
### Prompt Assembly Process
CrewAI assembles prompts differently based on agent type:
1. **Regular Agents**: Use the `Prompts` class to combine template slices
2. **LiteAgents**: Use dedicated system prompt methods with specific templates
3. **System/User Split**: When `use_system_prompt=True`, prompts are split into system and user components
## Basic Prompt Customization
### Custom System and Prompt Templates
You can override the default prompt structure using custom templates:
```python showLineNumbers
from crewai import Agent, Task, Crew
# Define custom templates
system_template = """{{ .System }}
Additional context: You are working in a production environment.
Always prioritize accuracy and provide detailed explanations."""
prompt_template = """{{ .Prompt }}
Remember to validate your approach before proceeding."""
response_template = """Please format your response as follows:
{{ .Response }}
End of response."""
# Create agent with custom templates
agent = Agent(
role="Data Analyst",
goal="Analyze data with precision and accuracy",
backstory="You are an experienced data analyst with expertise in statistical analysis.",
system_template=system_template,
prompt_template=prompt_template,
response_template=response_template,
use_system_prompt=True
)
```
### Template Placeholders
Custom templates support these placeholders:
- `{{ .System }}`: Replaced with the assembled system prompt components
- `{{ .Prompt }}`: Replaced with the task-specific prompt
- `{{ .Response }}`: Placeholder for the agent's response (used in response_template)
## System/User Prompt Split
Enable system/user prompt separation for better LLM compatibility:
```python showLineNumbers
agent = Agent(
role="Research Assistant",
goal="Conduct thorough research on given topics",
backstory="You are a meticulous researcher with access to various information sources.",
use_system_prompt=True # Enables system/user split
)
```
When `use_system_prompt=True`:
- **System Prompt**: Contains role, backstory, goal, and tool instructions
- **User Prompt**: Contains the specific task and expected output format
## Output Format Customization
### Structured Output with Pydantic Models
Control output formatting using Pydantic models:
```python showLineNumbers
from pydantic import BaseModel
from typing import List
class ResearchOutput(BaseModel):
summary: str
key_findings: List[str]
confidence_score: float
task = Task(
description="Research the latest trends in AI development",
expected_output="A structured research report",
output_pydantic=ResearchOutput,
agent=agent
)
```
### Custom Format Instructions
Add specific formatting requirements using Pydantic models:
```python showLineNumbers
from pydantic import BaseModel
from typing import List
class SalesAnalysisOutput(BaseModel):
total_sales: float
growth_rate: str
top_products: List[str]
recommendations: str
task = Task(
description="Analyze the quarterly sales data",
expected_output="Analysis in JSON format with specific fields",
output_json=SalesAnalysisOutput
)
```
## Stop Words Configuration
### Default Stop Words
CrewAI automatically configures stop words based on agent setup:
```python showLineNumbers
# Default stop word is "\nObservation:" for tool-enabled agents
agent = Agent(
role="Analyst",
goal="Perform analysis tasks",
backstory="You are a skilled analyst.",
tools=[some_tool] # Stop words include "\nObservation:"
)
```
> **Note:** If `system_template`, `prompt_template`, or `response_template` are not provided, the default templates from `translations/en.json` are used. The default system template includes role-playing instructions, tool descriptions (if applicable), and task formatting guidelines.
### Custom Stop Words via Response Template
Modify stop words by customizing the response template:
```python showLineNumbers
response_template = """Provide your analysis:
{{ .Response }}
---END---"""
agent = Agent(
role="Analyst",
goal="Perform detailed analysis",
backstory="You are an expert analyst.",
response_template=response_template # Stop words will include "---END---"
)
```
> ⚠️ **Warning:** If your stop sequence (e.g., `---END---`) can appear naturally within the model's response, this may cause premature output truncation. Always select distinctive, unlikely-to-occur sequences for stopping generation.
## LiteAgent Prompt Customization
LiteAgents use a simplified prompt system with direct customization:
```python showLineNumbers
from crewai import LiteAgent
# LiteAgent with tools
lite_agent = LiteAgent(
role="Code Reviewer",
goal="Review code for quality and security",
backstory="You are an experienced software engineer specializing in code review.",
tools=[code_analysis_tool],
response_format=CodeReviewOutput # Pydantic model for structured output
)
# The system prompt will automatically include tool instructions and format requirements
```
## Advanced Customization Examples
### Example 1: Multi-Language Support
```python showLineNumbers
# Custom templates for different languages
spanish_system_template = """{{ .System }}
Instrucciones adicionales: Responde siempre en español y proporciona explicaciones detalladas."""
agent = Agent(
role="Asistente de Investigación",
goal="Realizar investigación exhaustiva en español",
backstory="Eres un investigador experimentado que trabaja en español.",
system_template=spanish_system_template,
use_system_prompt=True
)
```
### Example 2: Domain-Specific Formatting
```python showLineNumbers
# Medical report formatting
medical_response_template = """MEDICAL ANALYSIS REPORT
{{ .Response }}
DISCLAIMER: This analysis is for informational purposes only."""
medical_agent = Agent(
role="Medical Data Analyst",
goal="Analyze medical data with clinical precision",
backstory="You are a certified medical data analyst with 10 years of experience.",
response_template=medical_response_template,
use_system_prompt=True
)
```
### Example 3: Complex Workflow Integration
```python showLineNumbers
from crewai import Flow
class CustomPromptFlow(Flow):
@start()
def research_phase(self):
# Agent with research-specific prompts
researcher = Agent(
role="Senior Researcher",
goal="Gather comprehensive information",
backstory="You are a senior researcher with expertise in data collection.",
system_template="""{{ .System }}
Research Guidelines:
- Verify all sources
- Provide confidence ratings
- Include methodology notes""",
use_system_prompt=True
)
task = Task(
description="Research the given topic thoroughly",
expected_output="Detailed research report with sources",
agent=researcher
)
return task.execute()
@listen(research_phase)
def analysis_phase(self, research_result):
# Agent with analysis-specific prompts
analyst = Agent(
role="Data Analyst",
goal="Provide actionable insights",
backstory="You are an expert data analyst specializing in trend analysis.",
response_template="""ANALYSIS RESULTS:
{{ .Response }}
CONFIDENCE LEVEL: [Specify confidence level]
NEXT STEPS: [Recommend next actions]""",
use_system_prompt=True
)
return f"Analysis based on: {research_result}"
```
## Best Practices
#### Precision and Accuracy
- Use specific role definitions and detailed backstories for consistent behavior
- Include validation requirements in custom templates
- Test prompt variations to ensure predictable outputs
#### Security Considerations
- Validate all user inputs before including them in prompts
- Use structured output formats to prevent prompt injection
- Implement guardrails for sensitive operations
> 🛡️ **Security Warning:** Never inject raw or untrusted user inputs directly into prompt templates without proper validation and sanitization. This can lead to prompt injection attacks where malicious users manipulate agent behavior. Always validate inputs, use parameterized templates, and consider implementing input filtering for production systems. Additionally, be cautious with custom stop sequences - if they can appear naturally in model responses, they may cause premature truncation of legitimate outputs.
#### Performance Optimization
- Keep system prompts concise while maintaining necessary context
- Use appropriate stop words to prevent unnecessary token generation
- Test prompt efficiency with your target LLM models
#### Complexity Handling
- Break complex requirements into multiple template components
- Use conditional prompt assembly for different scenarios
- Implement fallback templates for error handling
## Troubleshooting
### Common Issues
**Prompt Not Applied**: Ensure you're using the correct template parameter names and that `use_system_prompt` is set appropriately. See the [Basic Prompt Customization](#basic-prompt-customization) section for examples.
**Format Not Working**: Verify that your `output_json` or `output_pydantic` model matches the expected structure. Refer to [Output Format Customization](#output-format-customization) for details.
**Stop Words Not Effective**: Check that your `response_template` includes the desired stop sequence after the `{{ .Response }}` placeholder. See [Stop Words Configuration](#stop-words-configuration) for guidance.
**Template Injection Concerns**: Review the [Security Considerations](#security-considerations) section for guidance on preventing prompt injection attacks.
For complete API details, see the [Agent API Reference](../reference/agent) and [Task API Reference](../reference/task) documentation.
### Debugging Prompts
Enable verbose mode to see the actual prompts being sent to the LLM:
```python showLineNumbers
agent = Agent(
role="Debug Agent",
goal="Help debug prompt issues",
backstory="You are a debugging specialist.",
verbose=True # Shows detailed prompt information
)
```
### Additional Troubleshooting Steps
- **Verify prompt payloads**: Use verbose mode to inspect the actual prompts sent to the LLM
- **Test stop word effects**: Carefully verify that stop sequences don't cause premature truncation
- **Check template syntax**: Ensure placeholders like `{{ .System }}` are correctly formatted
- **Validate security**: Review custom templates for potential injection vulnerabilities as described in [Security Considerations](#security-considerations)
- **Revert to defaults**: If custom templates aren't working, temporarily remove them to isolate the issue
- **Test incrementally**: Add one custom template at a time to identify which component is causing problems
- **Validate template parameters**: Ensure all required parameters (role, goal, backstory) are provided when using custom templates
For more troubleshooting guidance, see the sections above on [Best Practices](#best-practices) and [Security Considerations](#security-considerations).
This comprehensive prompt customization system gives you precise control over agent behavior while maintaining the reliability and consistency that CrewAI is known for in production environments.

View File

@@ -85,6 +85,22 @@ with MCPServerAdapter(server_params) as mcp_tools:
```
This general pattern shows how to integrate tools. For specific examples tailored to each transport, refer to the detailed guides below.
## Filtering Tools
```python
with MCPServerAdapter(server_params) as mcp_tools:
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
my_agent = Agent(
role="MCP Tool User",
goal="Utilize tools from an MCP server.",
backstory="I can connect to MCP servers and use their tools.",
tools=mcp_tools["tool_name"], # Pass the loaded tools to your agent
reasoning=True,
verbose=True
)
# ... rest of your crew setup ...
```
## Explore MCP Integrations
<CardGroup cols={2}>

View File

@@ -30,18 +30,29 @@ Set your Langfuse API keys and configure OpenTelemetry export settings to send t
```python
import os
import base64
# Get keys for your project from the project settings page: https://cloud.langfuse.com
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..."
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..."
os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region
# os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region
# Your OpenAI key
os.environ["OPENAI_API_KEY"] = "sk-proj-..."
```
With the environment variables set, we can now initialize the Langfuse client. get_client() initializes the Langfuse client using the credentials provided in the environment variables.
LANGFUSE_PUBLIC_KEY="pk-lf-..."
LANGFUSE_SECRET_KEY="sk-lf-..."
LANGFUSE_AUTH=base64.b64encode(f"{LANGFUSE_PUBLIC_KEY}:{LANGFUSE_SECRET_KEY}".encode()).decode()
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://cloud.langfuse.com/api/public/otel" # EU data region
# os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://us.cloud.langfuse.com/api/public/otel" # US data region
os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = f"Authorization=Basic {LANGFUSE_AUTH}"
# your openai key
os.environ["OPENAI_API_KEY"] = "sk-..."
```python
from langfuse import get_client
langfuse = get_client()
# Verify connection
if langfuse.auth_check():
print("Langfuse client is authenticated and ready!")
else:
print("Authentication failed. Please check your credentials and host.")
```
### Step 3: Initialize OpenLit

View File

@@ -1,216 +0,0 @@
site_name: crewAI
site_author: crewAI, Inc
site_description: Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks.
repo_name: crewAI
repo_url: https://github.com/crewAIInc/crewAI
site_url: https://docs.crewai.com
edit_uri: edit/main/docs/
copyright: Copyright &copy; 2024 crewAI, Inc
markdown_extensions:
- abbr
- admonition
- pymdownx.details
- attr_list
- def_list
- footnotes
- md_in_html
- toc:
permalink: true
- pymdownx.arithmatex:
generic: true
- pymdownx.betterem:
smart_enable: all
- pymdownx.caret
- pymdownx.emoji:
emoji_generator: !!python/name:material.extensions.emoji.to_svg
emoji_index: !!python/name:material.extensions.emoji.twemoji
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.keys
- pymdownx.magiclink:
normalize_issue_symbols: true
repo_url_shorthand: true
user: joaomdmoura
repo: crewAI
- pymdownx.mark
- pymdownx.smartsymbols
- pymdownx.snippets:
auto_append:
- includes/mkdocs.md
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format
- pymdownx.tabbed:
alternate_style: true
combine_header_slug: true
slugify: !!python/object/apply:pymdownx.slugs.slugify
kwds:
case: lower
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tilde
theme:
name: material
language: en
icon:
repo: fontawesome/brands/github
edit: material/pencil
view: material/eye
admonition:
note: octicons/light-bulb-16
abstract: octicons/checklist-16
info: octicons/info-16
tip: octicons/squirrel-16
success: octicons/check-16
question: octicons/question-16
warning: octicons/alert-16
failure: octicons/x-circle-16
danger: octicons/zap-16
bug: octicons/bug-16
example: octicons/beaker-16
quote: octicons/quote-16
palette:
- scheme: default
primary: deep orange
accent: deep orange
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: slate
primary: deep orange
accent: deep orange
toggle:
icon: material/brightness-4
name: Switch to light mode
features:
- announce.dismiss
- content.action.edit
- content.action.view
- content.code.annotate
- content.code.copy
- content.code.select
- content.tabs.link
- content.tooltips
- header.autohide
- navigation.footer
- navigation.indexes
# - navigation.prune
# - navigation.sections
# - navigation.tabs
- search.suggest
- navigation.instant
- navigation.instant.progress
- navigation.instant.prefetch
- navigation.tracking
# - navigation.expand
- navigation.path
- navigation.top
- toc.follow
- toc.integrate
- search.highlight
- search.share
nav:
- Home: '/'
- Getting Started:
- Installing CrewAI: 'getting-started/Installing-CrewAI.md'
- Starting a new CrewAI project: 'getting-started/Start-a-New-CrewAI-Project-Template-Method.md'
- Core Concepts:
- Agents: 'core-concepts/Agents.md'
- Tasks: 'core-concepts/Tasks.md'
- Tools: 'core-concepts/Tools.md'
- Processes: 'core-concepts/Processes.md'
- Crews: 'core-concepts/Crews.md'
- Collaboration: 'core-concepts/Collaboration.md'
- Training: 'core-concepts/Training-Crew.md'
- Memory: 'core-concepts/Memory.md'
- Planning: 'core-concepts/Planning.md'
- Testing: 'core-concepts/Testing.md'
- Using LangChain Tools: 'core-concepts/Using-LangChain-Tools.md'
- Using LlamaIndex Tools: 'core-concepts/Using-LlamaIndex-Tools.md'
- How to Guides:
- Create Custom Tools: 'how-to/Create-Custom-Tools.md'
- Using Sequential Process: 'how-to/Sequential.md'
- Using Hierarchical Process: 'how-to/Hierarchical.md'
- Create your own Manager Agent: 'how-to/Your-Own-Manager-Agent.md'
- Connecting to any LLM: 'how-to/LLM-Connections.md'
- Customizing Agents: 'how-to/Customizing-Agents.md'
- Coding Agents: 'how-to/Coding-Agents.md'
- Forcing Tool Output as Result: 'how-to/Force-Tool-Ouput-as-Result.md'
- Human Input on Execution: 'how-to/Human-Input-on-Execution.md'
- Kickoff a Crew Asynchronously: 'how-to/Kickoff-async.md'
- Kickoff a Crew for a List: 'how-to/Kickoff-for-each.md'
- Replay from a specific task from a kickoff: 'how-to/Replay-tasks-from-latest-Crew-Kickoff.md'
- Conditional Tasks: 'how-to/Conditional-Tasks.md'
- Agent Monitoring with AgentOps: 'how-to/AgentOps-Observability.md'
- Agent Monitoring with LangTrace: 'how-to/Langtrace-Observability.md'
- Agent Monitoring with OpenLIT: 'how-to/openlit-Observability.md'
- Agent Monitoring with MLflow: 'how-to/mlflow-Observability.md'
- Tools Docs:
- Browserbase Web Loader: 'tools/BrowserbaseLoadTool.md'
- Code Docs RAG Search: 'tools/CodeDocsSearchTool.md'
- Code Interpreter: 'tools/CodeInterpreterTool.md'
- Composio Tools: 'tools/ComposioTool.md'
- CSV RAG Search: 'tools/CSVSearchTool.md'
- DALL-E Tool: 'tools/DALL-ETool.md'
- Directory RAG Search: 'tools/DirectorySearchTool.md'
- Directory Read: 'tools/DirectoryReadTool.md'
- Docx Rag Search: 'tools/DOCXSearchTool.md'
- EXA Search Web Loader: 'tools/EXASearchTool.md'
- File Read: 'tools/FileReadTool.md'
- File Write: 'tools/FileWriteTool.md'
- Firecrawl Crawl Website Tool: 'tools/FirecrawlCrawlWebsiteTool.md'
- Firecrawl Scrape Website Tool: 'tools/FirecrawlScrapeWebsiteTool.md'
- Firecrawl Search Tool: 'tools/FirecrgstawlSearchTool.md'
- Github RAG Search: 'tools/GitHubSearchTool.md'
- Google Serper Search: 'tools/SerperDevTool.md'
- JSON RAG Search: 'tools/JSONSearchTool.md'
- MDX RAG Search: 'tools/MDXSearchTool.md'
- MySQL Tool: 'tools/MySQLTool.md'
- NL2SQL Tool: 'tools/NL2SQLTool.md'
- PDF RAG Search: 'tools/PDFSearchTool.md'
- PG RAG Search: 'tools/PGSearchTool.md'
- Scrape Website: 'tools/ScrapeWebsiteTool.md'
- Selenium Scraper: 'tools/SeleniumScrapingTool.md'
- Spider Scraper: 'tools/SpiderTool.md'
- TXT RAG Search: 'tools/TXTSearchTool.md'
- Vision Tool: 'tools/VisionTool.md'
- Website RAG Search: 'tools/WebsiteSearchTool.md'
- XML RAG Search: 'tools/XMLSearchTool.md'
- Youtube Channel RAG Search: 'tools/YoutubeChannelSearchTool.md'
- Youtube Video RAG Search: 'tools/YoutubeVideoSearchTool.md'
- Examples:
- Trip Planner Crew: https://github.com/joaomdmoura/crewAI-examples/tree/main/trip_planner"
- Create Instagram Post: https://github.com/joaomdmoura/crewAI-examples/tree/main/instagram_post"
- Stock Analysis: https://github.com/joaomdmoura/crewAI-examples/tree/main/stock_analysis"
- Game Generator: https://github.com/joaomdmoura/crewAI-examples/tree/main/game-builder-crew"
- Drafting emails with LangGraph: https://github.com/joaomdmoura/crewAI-examples/tree/main/CrewAI-LangGraph"
- Landing Page Generator: https://github.com/joaomdmoura/crewAI-examples/tree/main/landing_page_generator"
- Prepare for meetings: https://github.com/joaomdmoura/crewAI-examples/tree/main/prep-for-a-meeting"
- Telemetry: 'telemetry/Telemetry.md'
- Change Log: 'https://github.com/crewAIInc/crewAI/releases'
extra_css:
- stylesheets/output.css
- stylesheets/extra.css
plugins:
- social
- search
extra:
analytics:
provider: google
property: G-N3Q505TMQ6
social:
- icon: fontawesome/brands/x-twitter
link: https://x.com/crewAIInc
- icon: fontawesome/brands/github
link: https://github.com/crewAIInc/crewAI

View File

@@ -74,11 +74,6 @@ dev-dependencies = [
"ruff>=0.8.2",
"mypy>=1.10.0",
"pre-commit>=3.6.0",
"mkdocs>=1.4.3",
"mkdocstrings>=0.22.0",
"mkdocstrings-python>=1.1.2",
"mkdocs-material>=9.5.7",
"mkdocs-material-extensions>=1.3.1",
"pillow>=10.2.0",
"cairosvg>=2.7.1",
"pytest>=8.0.0",

View File

@@ -39,7 +39,7 @@ from crewai.tasks.output_format import OutputFormat
from crewai.tasks.task_output import TaskOutput
from crewai.tools.base_tool import BaseTool
from crewai.utilities.config import process_config
from crewai.utilities.constants import NOT_SPECIFIED
from crewai.utilities.constants import NOT_SPECIFIED, _NotSpecified
from crewai.utilities.guardrail import process_guardrail, GuardrailResult
from crewai.utilities.converter import Converter, convert_to_model
from crewai.utilities.events import (
@@ -95,9 +95,9 @@ class Task(BaseModel):
agent: Optional[BaseAgent] = Field(
description="Agent responsible for execution the task.", default=None
)
context: Optional[List["Task"]] = Field(
context: Union[List["Task"], None, _NotSpecified] = Field(
description="Other tasks that will have their output used as context for this task.",
default=NOT_SPECIFIED,
default=NOT_SPECIFIED
)
async_execution: Optional[bool] = Field(
description="Whether the task should be executed asynchronously or not.",
@@ -158,6 +158,9 @@ class Task(BaseModel):
end_time: Optional[datetime.datetime] = Field(
default=None, description="End time of the task execution"
)
model_config = {
"arbitrary_types_allowed": True
}
@field_validator("guardrail")
@classmethod

View File

@@ -476,7 +476,14 @@ def load_agent_from_repository(from_repository: str) -> Dict[str, Any]:
try:
module = importlib.import_module(tool["module"])
tool_class = getattr(module, tool["name"])
attributes[key].append(tool_class())
tool_value = tool_class(**tool["init_params"])
if isinstance(tool_value, list):
attributes[key].extend(tool_value)
else:
attributes[key].append(tool_value)
except Exception as e:
raise AgentRepositoryError(
f"Tool {tool['name']} could not be loaded: {e}"

View File

@@ -1,5 +1,5 @@
from typing import TYPE_CHECKING, List
from typing import TYPE_CHECKING, List, Union
from crewai.utilities.constants import _NotSpecified
if TYPE_CHECKING:
from crewai.task import Task
@@ -15,7 +15,7 @@ def aggregate_raw_outputs_from_task_outputs(task_outputs: List["TaskOutput"]) ->
return context
def aggregate_raw_outputs_from_tasks(tasks: List["Task"]) -> str:
def aggregate_raw_outputs_from_tasks(tasks: Union[List["Task"],_NotSpecified]) -> str:
"""Generate string context from the tasks."""
task_outputs = (

View File

@@ -2099,7 +2099,7 @@ def mock_get_auth_token():
@patch("crewai.cli.plus_api.PlusAPI.get_agent")
def test_agent_from_repository(mock_get_agent, mock_get_auth_token):
from crewai_tools import SerperDevTool, XMLSearchTool
from crewai_tools import SerperDevTool, XMLSearchTool, CSVSearchTool, EnterpriseActionTool
mock_get_response = MagicMock()
mock_get_response.status_code = 200
@@ -2108,19 +2108,42 @@ def test_agent_from_repository(mock_get_agent, mock_get_auth_token):
"goal": "test goal",
"backstory": "test backstory",
"tools": [
{"module": "crewai_tools", "name": "SerperDevTool"},
{"module": "crewai_tools", "name": "XMLSearchTool"},
{"module": "crewai_tools", "name": "SerperDevTool", "init_params": {"n_results": 30}},
{"module": "crewai_tools", "name": "XMLSearchTool", "init_params": {"summarize": True}},
{"module": "crewai_tools", "name": "CSVSearchTool", "init_params": {}},
# using a tools that returns a list of BaseTools
{"module": "crewai_tools", "name": "CrewaiEnterpriseTools", "init_params": {"actions_list": [], "enterprise_token": "test_key"}},
],
}
mock_get_agent.return_value = mock_get_response
agent = Agent(from_repository="test_agent")
tool_action = EnterpriseActionTool(
name="test_name",
description="test_description",
enterprise_action_token="test_token",
action_name="test_action_name",
action_schema={"test": "test"},
)
with patch("crewai_tools.CrewaiEnterpriseTools", return_value=[tool_action]):
agent = Agent(from_repository="test_agent")
assert agent.role == "test role"
assert agent.goal == "test goal"
assert agent.backstory == "test backstory"
assert len(agent.tools) == 2
assert len(agent.tools) == 4
assert isinstance(agent.tools[0], SerperDevTool)
assert agent.tools[0].n_results == 30
assert isinstance(agent.tools[1], XMLSearchTool)
assert agent.tools[1].summarize
assert isinstance(agent.tools[2], CSVSearchTool)
assert not agent.tools[2].summarize
assert isinstance(agent.tools[3], EnterpriseActionTool)
assert agent.tools[3].name == "test_name"
@patch("crewai.cli.plus_api.PlusAPI.get_agent")
@@ -2133,7 +2156,7 @@ def test_agent_from_repository_override_attributes(mock_get_agent, mock_get_auth
"role": "test role",
"goal": "test goal",
"backstory": "test backstory",
"tools": [{"name": "SerperDevTool", "module": "crewai_tools"}],
"tools": [{"name": "SerperDevTool", "module": "crewai_tools", "init_params": {}}],
}
mock_get_agent.return_value = mock_get_response
agent = Agent(from_repository="test_agent", role="Custom Role")

View File

@@ -0,0 +1,506 @@
import pytest
from pydantic import BaseModel
from typing import List
from crewai import Agent, Task
from crewai.lite_agent import LiteAgent
from crewai.utilities.prompts import Prompts
from crewai.utilities import I18N
from crewai.tools import BaseTool
class ResearchOutput(BaseModel):
summary: str
key_findings: List[str]
confidence_score: float
class CodeReviewOutput(BaseModel):
issues: List[str]
recommendations: List[str]
class MockTool(BaseTool):
name: str = "mock_tool"
description: str = "A mock tool for testing"
def _run(self, query: str) -> str:
return f"Mock result for: {query}"
class TestPromptCustomizationDocs:
"""Test suite for prompt customization documentation examples."""
@pytest.fixture(autouse=True)
def setup(self):
"""Set up test fixtures for isolation."""
self.i18n = I18N()
def test_custom_system_and_prompt_templates(self):
"""Test basic custom template functionality.
Validates:
- Custom system template assignment
- Custom prompt template assignment
- Custom response template assignment
- System prompt flag configuration
"""
system_template = """{{ .System }}
Additional context: You are working in a production environment.
Always prioritize accuracy and provide detailed explanations."""
prompt_template = """{{ .Prompt }}
Remember to validate your approach before proceeding."""
response_template = """Please format your response as follows:
{{ .Response }}
End of response."""
agent = Agent(
role="Data Analyst",
goal="Analyze data with precision and accuracy",
backstory="You are an experienced data analyst with expertise in statistical analysis.",
system_template=system_template,
prompt_template=prompt_template,
response_template=response_template,
use_system_prompt=True,
llm="gpt-4o-mini"
)
assert agent.system_template == system_template
assert agent.prompt_template == prompt_template
assert agent.response_template == response_template
assert agent.use_system_prompt is True
def test_system_user_prompt_split(self):
"""Test system/user prompt separation."""
agent = Agent(
role="Research Assistant",
goal="Conduct thorough research on given topics",
backstory="You are a meticulous researcher with access to various information sources.",
use_system_prompt=True,
llm="gpt-4o-mini"
)
prompts = Prompts(
i18n=I18N(),
has_tools=False,
use_system_prompt=True,
agent=agent
)
prompt_dict = prompts.task_execution()
assert "system" in prompt_dict
assert "user" in prompt_dict
assert "You are Research Assistant" in prompt_dict["system"]
assert agent.goal in prompt_dict["system"]
def test_structured_output_with_pydantic(self):
"""Test structured output using Pydantic models."""
class ResearchOutput(BaseModel):
summary: str
key_findings: List[str]
confidence_score: float
agent = Agent(
role="Research Assistant",
goal="Conduct thorough research",
backstory="You are a meticulous researcher.",
llm="gpt-4o-mini"
)
task = Task(
description="Research the latest trends in AI development",
expected_output="A structured research report",
output_pydantic=ResearchOutput,
agent=agent
)
assert task.output_pydantic == ResearchOutput
assert task.expected_output == "A structured research report"
def test_custom_format_instructions(self):
"""Test custom output format instructions using output_json.
Validates:
- Task can be configured with structured JSON output using Pydantic models
- Output format is properly stored and accessible via _get_output_format method
"""
class SalesAnalysisOutput(BaseModel):
total_sales: float
growth_rate: str
top_products: List[str]
recommendations: str
task = Task(
description="Analyze the quarterly sales data",
expected_output="Analysis in JSON format with specific fields",
output_json=SalesAnalysisOutput,
agent=Agent(
role="Sales Analyst",
goal="Analyze sales data",
backstory="You are a sales data expert.",
llm="gpt-4o-mini"
)
)
assert task.output_json == SalesAnalysisOutput
assert task._get_output_format().value == "json"
def test_stop_words_configuration(self):
"""Test stop words configuration through response template.
Validates:
- Response template is properly stored on agent
- Agent has create_agent_executor method for setting up execution
- Stop words are configured based on response template content
"""
response_template = """Provide your analysis:
{{ .Response }}
---END---"""
agent = Agent(
role="Analyst",
goal="Perform detailed analysis",
backstory="You are an expert analyst.",
response_template=response_template,
llm="gpt-4o-mini"
)
assert agent.response_template == response_template
assert hasattr(agent, 'create_agent_executor')
assert callable(getattr(agent, 'create_agent_executor'))
agent.create_agent_executor()
assert agent.agent_executor is not None
def test_lite_agent_prompt_customization(self):
"""Test LiteAgent prompt customization."""
class CodeReviewOutput(BaseModel):
issues_found: List[str]
severity: str
recommendations: List[str]
lite_agent = LiteAgent(
role="Code Reviewer",
goal="Review code for quality and security",
backstory="You are an experienced software engineer specializing in code review.",
response_format=CodeReviewOutput,
llm="gpt-4o-mini"
)
system_prompt = lite_agent._get_default_system_prompt()
assert "Code Reviewer" in system_prompt
assert "Review code for quality and security" in system_prompt
assert "experienced software engineer" in system_prompt
def test_multi_language_support(self):
"""Test custom templates for different languages."""
spanish_system_template = """{{ .System }}
Instrucciones adicionales: Responde siempre en español y proporciona explicaciones detalladas."""
agent = Agent(
role="Asistente de Investigación",
goal="Realizar investigación exhaustiva en español",
backstory="Eres un investigador experimentado que trabaja en español.",
system_template=spanish_system_template,
use_system_prompt=True,
llm="gpt-4o-mini"
)
assert agent.system_template == spanish_system_template
assert "español" in agent.system_template
def test_domain_specific_formatting(self):
"""Test domain-specific response formatting.
Validates:
- Domain-specific templates can be applied
- Response templates support specialized formatting
"""
medical_response_template = """MEDICAL ANALYSIS REPORT
{{ .Response }}
DISCLAIMER: This analysis is for informational purposes only."""
medical_agent = Agent(
role="Medical Data Analyst",
goal="Analyze medical data with clinical precision",
backstory="You are a certified medical data analyst with 10 years of experience.",
response_template=medical_response_template,
use_system_prompt=True,
llm="gpt-4o-mini"
)
assert "MEDICAL ANALYSIS REPORT" in medical_agent.response_template
assert "DISCLAIMER" in medical_agent.response_template
def test_prompt_components_assembly(self):
"""Test how prompt components are assembled."""
agent = Agent(
role="Test Agent",
goal="Test goal",
backstory="Test backstory",
llm="gpt-4o-mini"
)
prompts = Prompts(
i18n=I18N(),
has_tools=False,
agent=agent
)
prompt_dict = prompts.task_execution()
assert "prompt" in prompt_dict
assert "Test Agent" in prompt_dict["prompt"]
assert "Test goal" in prompt_dict["prompt"]
assert "Test backstory" in prompt_dict["prompt"]
def test_tools_vs_no_tools_prompts(self):
"""Test prompt generation differences between agents with and without tools.
Validates:
- Agents without tools use 'no_tools' template slice
- Agents with tools use 'tools' template slice
- Prompt generation differs based on tool availability
"""
agent_no_tools = Agent(
role="Analyst",
goal="Analyze data",
backstory="Expert analyst",
llm="gpt-4o-mini"
)
mock_tool = MockTool()
agent_with_tools = Agent(
role="Analyst",
goal="Analyze data",
backstory="Expert analyst",
tools=[mock_tool],
llm="gpt-4o-mini"
)
assert len(agent_with_tools.tools) == 1
assert agent_with_tools.tools[0].name == "mock_tool"
prompts_no_tools = Prompts(i18n=I18N(), has_tools=False, agent=agent_no_tools)
prompts_with_tools = Prompts(i18n=I18N(), has_tools=True, agent=agent_with_tools)
prompt_dict_no_tools = prompts_no_tools.task_execution()
prompt_dict_with_tools = prompts_with_tools.task_execution()
assert isinstance(prompt_dict_no_tools, dict)
assert isinstance(prompt_dict_with_tools, dict)
assert prompt_dict_no_tools != prompt_dict_with_tools
def test_template_placeholder_replacement(self):
"""Test that template placeholders are properly replaced."""
system_template = "SYSTEM: {{ .System }} - Custom addition"
prompt_template = "PROMPT: {{ .Prompt }} - Custom addition"
response_template = "RESPONSE: {{ .Response }} - Custom addition"
agent = Agent(
role="Template Tester",
goal="Test template replacement",
backstory="You test templates.",
system_template=system_template,
prompt_template=prompt_template,
response_template=response_template,
llm="gpt-4o-mini"
)
prompts = Prompts(
i18n=I18N(),
has_tools=False,
system_template=system_template,
prompt_template=prompt_template,
response_template=response_template,
agent=agent
)
prompt_dict = prompts.task_execution()
assert "SYSTEM:" in prompt_dict["prompt"]
assert "PROMPT:" in prompt_dict["prompt"]
assert "RESPONSE:" in prompt_dict["prompt"]
assert "Custom addition" in prompt_dict["prompt"]
def test_verbose_mode_configuration(self):
"""Test verbose mode for debugging prompts.
Validates:
- verbose=True parameter can be set on agents
- Verbose mode configuration is properly stored
"""
agent = Agent(
role="Debug Agent",
goal="Help debug prompt issues",
backstory="You are a debugging specialist.",
verbose=True,
llm="gpt-4o-mini"
)
assert agent.verbose is True
def test_i18n_slice_access(self):
"""Test internationalization slice access.
Validates:
- I18N class provides access to template slices
- Template slices contain expected prompt components
"""
i18n = I18N()
role_playing_slice = i18n.slice("role_playing")
observation_slice = i18n.slice("observation")
tools_slice = i18n.slice("tools")
no_tools_slice = i18n.slice("no_tools")
assert "You are {role}" in role_playing_slice
assert "Your personal goal is: {goal}" in role_playing_slice
assert "\nObservation:" == observation_slice
assert "Action:" in tools_slice
assert "Final Answer:" in no_tools_slice
@pytest.mark.parametrize("role,goal,backstory", [
("Analyst", "Analyze data", "Expert analyst"),
("Researcher", "Find facts", "Experienced researcher"),
("Writer", "Create content", "Professional writer"),
])
def test_agent_initialization_parametrized(self, role, goal, backstory):
"""Test agent initialization with different role combinations.
Validates:
- Agents can be created with various role/goal/backstory combinations
- All parameters are properly stored
"""
agent = Agent(role=role, goal=goal, backstory=backstory, llm="gpt-4o-mini")
assert agent.role == role
assert agent.goal == goal
assert agent.backstory == backstory
def test_default_template_behavior(self):
"""Test behavior when no custom templates are provided.
Validates:
- Agents work correctly with default templates
- Default templates from translations/en.json are used
"""
agent = Agent(
role="Default Agent",
goal="Test default behavior",
backstory="Testing default templates",
llm="gpt-4o-mini"
)
assert agent.system_template is None
assert agent.prompt_template is None
assert agent.response_template is None
prompts = Prompts(i18n=self.i18n, has_tools=False, agent=agent)
prompt_dict = prompts.task_execution()
assert isinstance(prompt_dict, dict)
def test_incomplete_template_definitions(self):
"""Test behavior with incomplete template definitions.
Validates:
- Agents handle partial template customization gracefully
- Missing templates fall back to defaults
"""
agent_partial = Agent(
role="Partial Agent",
goal="Test partial templates",
backstory="Testing incomplete templates",
system_template="{{ .System }} - Custom system only",
llm="gpt-4o-mini"
)
assert agent_partial.system_template is not None
assert agent_partial.prompt_template is None
assert agent_partial.response_template is None
prompts = Prompts(i18n=self.i18n, has_tools=False, agent=agent_partial)
prompt_dict = prompts.task_execution()
assert isinstance(prompt_dict, dict)
def test_lite_agent_with_and_without_tools(self):
"""Test LiteAgent behavior with and without tools.
Validates:
- LiteAgent can be created with and without tools
- Tool configuration is properly stored
"""
lite_agent_no_tools = LiteAgent(
role="Reviewer",
goal="Review content",
backstory="Expert reviewer",
llm="gpt-4o-mini"
)
mock_tool = MockTool()
lite_agent_with_tools = LiteAgent(
role="Reviewer",
goal="Review content",
backstory="Expert reviewer",
tools=[mock_tool],
llm="gpt-4o-mini"
)
assert lite_agent_no_tools.role == "Reviewer"
assert lite_agent_with_tools.role == "Reviewer"
assert len(lite_agent_with_tools.tools) == 1
assert lite_agent_with_tools.tools[0].name == "mock_tool"
def test_malformed_template_handling(self):
"""Test handling of malformed or incomplete templates gracefully.
Validates:
- Agent creation succeeds with malformed templates
- Missing placeholders don't cause failures
- System handles edge cases gracefully
"""
incomplete_template = "This is a template without placeholders"
agent = Agent(
role="Test Agent",
goal="Test incomplete templates",
backstory="Agent for testing edge cases.",
system_template=incomplete_template,
llm="gpt-4o-mini"
)
assert agent.system_template == incomplete_template
assert agent.role == "Test Agent"
agent_empty = Agent(
role="Empty Template Agent",
goal="Test empty templates",
backstory="Agent with empty template.",
response_template="",
llm="gpt-4o-mini"
)
assert agent_empty.response_template == ""
def test_agent_creation_with_missing_required_parameters(self):
"""Test agent creation behavior when required parameters are missing.
Validates:
- Agent creation requires role, goal, and backstory
- Appropriate errors are raised for missing parameters
"""
with pytest.raises((TypeError, ValueError)):
Agent(llm="gpt-4o-mini") # Missing required parameters
with pytest.raises((TypeError, ValueError)):
Agent(role="Test", llm="gpt-4o-mini") # Missing goal and backstory

252
uv.lock generated
View File

@@ -337,15 +337,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a2/ee/3fd29bf416eb4f1c5579cf12bf393ae954099258abd7bde03c4f9716ef6b/autoflake-2.3.1-py3-none-any.whl", hash = "sha256:3ae7495db9084b7b32818b4140e6dc4fc280b712fb414f5b8fe57b0a8e85a840", size = 32483 },
]
[[package]]
name = "babel"
version = "2.16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 },
]
[[package]]
name = "backoff"
version = "2.2.1"
@@ -787,11 +778,6 @@ tools = [
[package.dev-dependencies]
dev = [
{ name = "cairosvg" },
{ name = "mkdocs" },
{ name = "mkdocs-material" },
{ name = "mkdocs-material-extensions" },
{ name = "mkdocstrings" },
{ name = "mkdocstrings-python" },
{ name = "mypy" },
{ name = "pillow" },
{ name = "pre-commit" },
@@ -846,11 +832,6 @@ requires-dist = [
[package.metadata.requires-dev]
dev = [
{ name = "cairosvg", specifier = ">=2.7.1" },
{ name = "mkdocs", specifier = ">=1.4.3" },
{ name = "mkdocs-material", specifier = ">=9.5.7" },
{ name = "mkdocs-material-extensions", specifier = ">=1.3.1" },
{ name = "mkdocstrings", specifier = ">=0.22.0" },
{ name = "mkdocstrings-python", specifier = ">=1.1.2" },
{ name = "mypy", specifier = ">=1.10.0" },
{ name = "pillow", specifier = ">=10.2.0" },
{ name = "pre-commit", specifier = ">=3.6.0" },
@@ -1428,18 +1409,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c6/b2/454d6e7f0158951d8a78c2e1eb4f69ae81beb8dca5fee9809c6c99e9d0d0/fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871", size = 179641 },
]
[[package]]
name = "ghp-import"
version = "2.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034 },
]
[[package]]
name = "google-auth"
version = "2.35.0"
@@ -1531,18 +1500,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 },
]
[[package]]
name = "griffe"
version = "1.5.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "colorama" },
]
sdist = { url = "https://files.pythonhosted.org/packages/d4/c9/8167810358ca129839156dc002526e7398b5fad4a9d7b6e88b875e802d0d/griffe-1.5.1.tar.gz", hash = "sha256:72964f93e08c553257706d6cd2c42d1c172213feb48b2be386f243380b405d4b", size = 384113 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ab/00/e693a155da0a2a72fd2df75b8fe338146cae59d590ad6f56800adde90cb5/griffe-1.5.1-py3-none-any.whl", hash = "sha256:ad6a7980f8c424c9102160aafa3bcdf799df0e75f7829d75af9ee5aef656f860", size = 127132 },
]
[[package]]
name = "grpcio"
version = "1.67.0"
@@ -2360,15 +2317,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/48/22/bc14c6f02e6dccaafb3eba95764c8f096714260c2aa5f76f654fd16a23dd/Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a", size = 78557 },
]
[[package]]
name = "markdown"
version = "3.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 },
]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
@@ -2499,131 +2447,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0c/fa/a2043c5a228077423678d9e7e0fe3aab89ab9a625a4f171a30967de1bbb3/mem0ai-0.1.94-py3-none-any.whl", hash = "sha256:862aaccf4ec41d65a5c935dc49c7b8175c96f6b60b29abeda338d8a335027e2c", size = 143077 },
]
[[package]]
name = "mergedeep"
version = "1.3.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354 },
]
[[package]]
name = "mkdocs"
version = "1.6.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "colorama", marker = "platform_system == 'Windows'" },
{ name = "ghp-import" },
{ name = "jinja2" },
{ name = "markdown" },
{ name = "markupsafe" },
{ name = "mergedeep" },
{ name = "mkdocs-get-deps" },
{ name = "packaging" },
{ name = "pathspec" },
{ name = "pyyaml" },
{ name = "pyyaml-env-tag" },
{ name = "watchdog" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451 },
]
[[package]]
name = "mkdocs-autorefs"
version = "1.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown" },
{ name = "markupsafe" },
{ name = "mkdocs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/ae/0f1154c614d6a8b8a36fff084e5b82af3a15f7d2060cf0dcdb1c53297a71/mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f", size = 40262 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/71/26/4d39d52ea2219604053a4d05b98e90d6a335511cc01806436ec4886b1028/mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f", size = 16522 },
]
[[package]]
name = "mkdocs-get-deps"
version = "0.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mergedeep" },
{ name = "platformdirs" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/f5/ed29cd50067784976f25ed0ed6fcd3c2ce9eb90650aa3b2796ddf7b6870b/mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c", size = 10239 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521 },
]
[[package]]
name = "mkdocs-material"
version = "9.5.42"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "babel" },
{ name = "colorama" },
{ name = "jinja2" },
{ name = "markdown" },
{ name = "mkdocs" },
{ name = "mkdocs-material-extensions" },
{ name = "paginate" },
{ name = "pygments" },
{ name = "pymdown-extensions" },
{ name = "regex" },
{ name = "requests" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f9/33/b3343ed975fbbd6798b8d8a7c4f1bf8489cc321fc8fd426eba3d87b0242e/mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2", size = 3963891 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/55/55/ad3e6a60ac1e8e76025543c49c1f24ecd80fb38e8a57000403bf2f0a4293/mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316", size = 8672619 },
]
[[package]]
name = "mkdocs-material-extensions"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728 },
]
[[package]]
name = "mkdocstrings"
version = "0.26.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "click" },
{ name = "jinja2" },
{ name = "markdown" },
{ name = "markupsafe" },
{ name = "mkdocs" },
{ name = "mkdocs-autorefs" },
{ name = "platformdirs" },
{ name = "pymdown-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/76/0475d10d27f3384df3a6ddfdf4a4fdfef83766f77cd4e327d905dc956c15/mkdocstrings-0.26.2.tar.gz", hash = "sha256:34a8b50f1e6cfd29546c6c09fbe02154adfb0b361bb758834bf56aa284ba876e", size = 92512 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/80/b6/4ee320d7c313da3774eff225875eb278f7e6bb26a9cd8e680b8dbc38fdea/mkdocstrings-0.26.2-py3-none-any.whl", hash = "sha256:1248f3228464f3b8d1a15bd91249ce1701fe3104ac517a5f167a0e01ca850ba5", size = 29716 },
]
[[package]]
name = "mkdocstrings-python"
version = "1.12.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "griffe" },
{ name = "mkdocs-autorefs" },
{ name = "mkdocstrings" },
]
sdist = { url = "https://files.pythonhosted.org/packages/23/ec/cb6debe2db77f1ef42b25b21d93b5021474de3037cd82385e586aee72545/mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3", size = 168207 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5b/c1/ac524e1026d9580cbc654b5d19f5843c8b364a66d30f956372cd09fd2f92/mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a", size = 111759 },
]
[[package]]
name = "mmh3"
version = "4.1.0"
@@ -3389,15 +3212,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011 },
]
[[package]]
name = "paginate"
version = "0.5.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746 },
]
[[package]]
name = "pandas"
version = "2.2.3"
@@ -3464,15 +3278,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 },
]
[[package]]
name = "pathspec"
version = "0.12.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191 },
]
[[package]]
name = "pdfminer-six"
version = "20231228"
@@ -4055,19 +3860,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 },
]
[[package]]
name = "pymdown-extensions"
version = "10.11.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "markdown" },
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f4/71/2730a20e9e3752393d78998347f8b1085ef9c417646ea9befbeef221e3c4/pymdown_extensions-10.11.2.tar.gz", hash = "sha256:bc8847ecc9e784a098efd35e20cba772bc5a1b529dfcef9dc1972db9021a1049", size = 830241 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c2/35/c0edf199257ef0a7d407d29cd51c4e70d1dad4370a5f44deb65a7a5475e2/pymdown_extensions-10.11.2-py3-none-any.whl", hash = "sha256:41cdde0a77290e480cf53892f5c5e50921a7ee3e5cd60ba91bf19837b33badcf", size = 259044 },
]
[[package]]
name = "pypdf"
version = "5.0.1"
@@ -4444,18 +4236,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
]
[[package]]
name = "pyyaml-env-tag"
version = "0.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pyyaml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/fb/8e/da1c6c58f751b70f8ceb1eb25bc25d524e8f14fe16edcce3f4e3ba08629c/pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb", size = 5631 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/5a/66/bbb1dd374f5c870f59c5bb1db0e18cbe7fa739415a24cbd95b2d1f5ae0c4/pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069", size = 3911 },
]
[[package]]
name = "qdrant-client"
version = "1.12.0"
@@ -5666,38 +5446,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/15/828ec11907aee2349a9342fa71fba4ba7f3af938162a382dd7da339dea16/virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655", size = 3110969 },
]
[[package]]
name = "watchdog"
version = "5.0.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/48/a86139aaeab2db0a2482676f64798d8ac4d2dbb457523f50ab37bf02ce2c/watchdog-5.0.3.tar.gz", hash = "sha256:108f42a7f0345042a854d4d0ad0834b741d421330d5f575b81cb27b883500176", size = 129556 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/05/2b/dd2081aab6fc9e785c2eee7146d3c6de58e607f4e70049d715cd170cbf77/watchdog-5.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:85527b882f3facda0579bce9d743ff7f10c3e1e0db0a0d0e28170a7d0e5ce2ea", size = 96652 },
{ url = "https://files.pythonhosted.org/packages/9e/4f/f643c0a720d16ef7316aea06a79b96e229e59df4e0d83bec5e12713c1f29/watchdog-5.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:53adf73dcdc0ef04f7735066b4a57a4cd3e49ef135daae41d77395f0b5b692cb", size = 88651 },
{ url = "https://files.pythonhosted.org/packages/2b/72/acb22067d1f18161914c9b1087c703d63638131a9fde78090da290663407/watchdog-5.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e25adddab85f674acac303cf1f5835951345a56c5f7f582987d266679979c75b", size = 89289 },
{ url = "https://files.pythonhosted.org/packages/70/34/946f08602f8b8e6af45bc725e4a8013975a34883ab5570bd0d827a4c9829/watchdog-5.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f01f4a3565a387080dc49bdd1fefe4ecc77f894991b88ef927edbfa45eb10818", size = 96650 },
{ url = "https://files.pythonhosted.org/packages/96/2b/b84e35d49e8b0bad77e5d086fc1e2c6c833bbfe74d53144cfe8b26117eff/watchdog-5.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:91b522adc25614cdeaf91f7897800b82c13b4b8ac68a42ca959f992f6990c490", size = 88653 },
{ url = "https://files.pythonhosted.org/packages/d5/3f/41b5d77c10f450b79921c17b7d0b416616048867bfe63acaa072a619a0cb/watchdog-5.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d52db5beb5e476e6853da2e2d24dbbbed6797b449c8bf7ea118a4ee0d2c9040e", size = 89286 },
{ url = "https://files.pythonhosted.org/packages/1c/9b/8b206a928c188fdeb7b12e1c795199534cd44bdef223b8470129016009dd/watchdog-5.0.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:94d11b07c64f63f49876e0ab8042ae034674c8653bfcdaa8c4b32e71cfff87e8", size = 96739 },
{ url = "https://files.pythonhosted.org/packages/e1/26/129ca9cd0f8016672f37000010c2fedc0b86816e894ebdc0af9bb04a6439/watchdog-5.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:349c9488e1d85d0a58e8cb14222d2c51cbc801ce11ac3936ab4c3af986536926", size = 88708 },
{ url = "https://files.pythonhosted.org/packages/8f/b3/5e10ec32f0c429cdb55b1369066d6e83faf9985b3a53a4e37bb5c5e29aa0/watchdog-5.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:53a3f10b62c2d569e260f96e8d966463dec1a50fa4f1b22aec69e3f91025060e", size = 89309 },
{ url = "https://files.pythonhosted.org/packages/54/c4/49af4ab00bcfb688e9962eace2edda07a2cf89b9699ea536da48e8585cff/watchdog-5.0.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:950f531ec6e03696a2414b6308f5c6ff9dab7821a768c9d5788b1314e9a46ca7", size = 96740 },
{ url = "https://files.pythonhosted.org/packages/96/a4/b24de77cc9ae424c1687c9d4fb15aa560d7d7b28ba559aca72f781d0202b/watchdog-5.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6deb336cba5d71476caa029ceb6e88047fc1dc74b62b7c4012639c0b563906", size = 88711 },
{ url = "https://files.pythonhosted.org/packages/a4/71/3f2e9fe8403386b99d788868955b3a790f7a09721501a7e1eb58f514ffaa/watchdog-5.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1021223c08ba8d2d38d71ec1704496471ffd7be42cfb26b87cd5059323a389a1", size = 89319 },
{ url = "https://files.pythonhosted.org/packages/a2/d6/1d1ca81c75d903eca3fdb7061d93845485b58a5ba182d146843b88fc51c2/watchdog-5.0.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:90a67d7857adb1d985aca232cc9905dd5bc4803ed85cfcdcfcf707e52049eda7", size = 88172 },
{ url = "https://files.pythonhosted.org/packages/47/bb/d5e0abcfd6d729029a24766682e062526db8b59e9ae0c94aff509e0fd2b9/watchdog-5.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:720ef9d3a4f9ca575a780af283c8fd3a0674b307651c1976714745090da5a9e8", size = 88644 },
{ url = "https://files.pythonhosted.org/packages/60/33/7cb71c9df9a77b6927ee5f48d25e1de5562ce0fa7e0c56dcf2b0472e64a2/watchdog-5.0.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dd021efa85970bd4824acacbb922066159d0f9e546389a4743d56919b6758b91", size = 79335 },
{ url = "https://files.pythonhosted.org/packages/f6/91/320bc1496cf951a3cf93a7ffd18a581f0792c304be963d943e0e608c2919/watchdog-5.0.3-py3-none-manylinux2014_armv7l.whl", hash = "sha256:78864cc8f23dbee55be34cc1494632a7ba30263951b5b2e8fc8286b95845f82c", size = 79334 },
{ url = "https://files.pythonhosted.org/packages/8b/2c/567c5e042ed667d3544c43d48a65cf853450a2d2a9089d9523a65f195e94/watchdog-5.0.3-py3-none-manylinux2014_i686.whl", hash = "sha256:1e9679245e3ea6498494b3028b90c7b25dbb2abe65c7d07423ecfc2d6218ff7c", size = 79333 },
{ url = "https://files.pythonhosted.org/packages/c3/f0/64059fe162ef3274662e67bbdea6c45b3cd53e846d5bd1365fcdc3dc1d15/watchdog-5.0.3-py3-none-manylinux2014_ppc64.whl", hash = "sha256:9413384f26b5d050b6978e6fcd0c1e7f0539be7a4f1a885061473c5deaa57221", size = 79334 },
{ url = "https://files.pythonhosted.org/packages/f6/d9/19b7d02965be2801e2d0f6f4bde23e4ae172620071b65430fa0c2f8441ac/watchdog-5.0.3-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:294b7a598974b8e2c6123d19ef15de9abcd282b0fbbdbc4d23dfa812959a9e05", size = 79333 },
{ url = "https://files.pythonhosted.org/packages/cb/a1/5393ac6d0b095d3a44946b09258e9b5f22cb2fb67bcfa419dd868478826c/watchdog-5.0.3-py3-none-manylinux2014_s390x.whl", hash = "sha256:26dd201857d702bdf9d78c273cafcab5871dd29343748524695cecffa44a8d97", size = 79332 },
{ url = "https://files.pythonhosted.org/packages/a0/58/edec25190b6403caf4426dd418234f2358a106634b7d6aa4aec6939b104f/watchdog-5.0.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:0f9332243355643d567697c3e3fa07330a1d1abf981611654a1f2bf2175612b7", size = 79334 },
{ url = "https://files.pythonhosted.org/packages/97/69/cfb2d17ba8aabc73be2e2d03c8c319b1f32053a02c4b571852983aa24ff2/watchdog-5.0.3-py3-none-win32.whl", hash = "sha256:c66f80ee5b602a9c7ab66e3c9f36026590a0902db3aea414d59a2f55188c1f49", size = 79320 },
{ url = "https://files.pythonhosted.org/packages/91/b4/2b5b59358dadfa2c8676322f955b6c22cde4937602f40490e2f7403e548e/watchdog-5.0.3-py3-none-win_amd64.whl", hash = "sha256:f00b4cf737f568be9665563347a910f8bdc76f88c2970121c86243c8cfdf90e9", size = 79325 },
{ url = "https://files.pythonhosted.org/packages/38/b8/0aa69337651b3005f161f7f494e59188a1d8d94171666900d26d29d10f69/watchdog-5.0.3-py3-none-win_ia64.whl", hash = "sha256:49f4d36cb315c25ea0d946e018c01bb028048023b9e103d3d3943f58e109dd45", size = 79324 },
]
[[package]]
name = "watchfiles"
version = "0.24.0"