mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-01 05:08:12 +00:00
Extract duplicated Redis URL parsing into a shared cache_config utility. Introduce ValkeyCache as a lightweight async key/value cache using valkey-glide. Wire it into A2A task handling, agent card caching, and file upload caching. Part 1/4 of Valkey storage implementation. fix: async-safe embeddings and resilient drain_writes Add bytes→float validators on MemoryRecord and ItemState to handle Valkey returning embeddings as raw bytes. Make embed_texts() safe when called from an async context by using a thread pool. Improve drain_writes() with per-save timeouts and error logging instead of raising on failure. Part 3/4 of Valkey storage implementation. feat(valkey): ValkeyStorage vector memory backend Add ValkeyStorage, a distributed StorageBackend implementation using Valkey-GLIDE with Valkey Search for vector similarity. Wire it into Memory as the 'valkey' storage option. Pin scrapegraph-py<2 to fix unrelated upstream breakage. Part 4/4 of Valkey storage implementation. fix: use datetime.utcnow() for last_accessed consistency MemoryRecord defaults use utcnow() for created_at and last_accessed. Match that in ValkeyStorage.update_record() to avoid timezone inconsistency in recency scoring. feat(valkey): shared cache config + ValkeyCache for A2A and file uploads Extract duplicated Redis URL parsing into a shared cache_config utility. Introduce ValkeyCache as a lightweight async key/value cache using valkey-glide. Wire it into A2A task handling, agent card caching, and file upload caching. Part 1/4 of Valkey storage implementation. fix: handle non-numeric database path in cache URL parsing Extract _parse_db_from_path() helper that catches ValueError for paths like /mydb and defaults to 0 with a warning, instead of crashing. fix: async-safe embeddings and resilient drain_writes Add bytes→float validators on MemoryRecord and ItemState to handle Valkey returning embeddings as raw bytes. Make embed_texts() safe when called from an async context by using a thread pool. Improve drain_writes() with per-save timeouts and error logging instead of raising on failure. Part 3/4 of Valkey storage implementation. fix: catch concurrent.futures.TimeoutError for Python 3.10 compat In Python <3.11, concurrent.futures.TimeoutError is distinct from the builtin TimeoutError. Catch both so the timeout warning path works on all supported Python versions.
230 lines
8.4 KiB
TOML
230 lines
8.4 KiB
TOML
name = "crewai-workspace"
|
|
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."
|
|
readme = "README.md"
|
|
requires-python = ">=3.10,<3.14"
|
|
authors = [
|
|
{ name = "Joao Moura", email = "joao@crewai.com" }
|
|
]
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"ruff==0.15.1",
|
|
"mypy==1.19.1",
|
|
"pre-commit==4.5.1",
|
|
"bandit==1.9.2",
|
|
"pytest==9.0.3",
|
|
"pytest-asyncio==1.3.0",
|
|
"pytest-subprocess==1.5.3",
|
|
"vcrpy==7.0.0", # pinned, less versions break pytest-recording
|
|
"pytest-recording==0.13.4",
|
|
"pytest-randomly==4.0.1",
|
|
"pytest-timeout==2.4.0",
|
|
"pytest-xdist==3.8.0",
|
|
"pytest-split==0.11.0",
|
|
"types-requests~=2.31.0.6",
|
|
"types-pyyaml==6.0.*",
|
|
"types-regex==2026.1.15.*",
|
|
"types-appdirs==1.4.*",
|
|
"boto3-stubs[bedrock-runtime]==1.42.40",
|
|
"types-psycopg2==2.9.21.20251012",
|
|
"types-pymysql==1.1.0.20250916",
|
|
"types-aiofiles~=25.1.0",
|
|
"types-redis~=4.6",
|
|
"commitizen>=4.13.9",
|
|
"pip-audit==2.9.0",
|
|
]
|
|
|
|
|
|
[tool.ruff]
|
|
src = ["lib/*"]
|
|
extend-exclude = [
|
|
"lib/crewai/src/crewai/cli/templates",
|
|
"lib/cli/src/crewai_cli/templates",
|
|
"lib/crewai/tests/",
|
|
"lib/crewai-tools/tests/",
|
|
"lib/cli/tests/",
|
|
]
|
|
respect-gitignore = true
|
|
force-exclude = true
|
|
fix = true
|
|
target-version = "py310"
|
|
|
|
[tool.ruff.format]
|
|
docstring-code-format = true
|
|
|
|
[tool.ruff.lint]
|
|
future-annotations = true
|
|
extend-select = [
|
|
"E", # pycodestyle errors (style issues)
|
|
"F", # Pyflakes (code errors)
|
|
"B", # flake8-bugbear (bug prevention)
|
|
"S", # bandit (security issues)
|
|
"RUF", # ruff-specific rules
|
|
"N", # pep8-naming (naming conventions)
|
|
"W", # pycodestyle warnings
|
|
"I", # isort (import formatting)
|
|
"T", # flake8-print (print statements)
|
|
# "D", # pydocstyle (docstring conventions) disabled until
|
|
"PERF", # performance issues
|
|
"PIE", # flake8-pie (unnecessary code)
|
|
"TID", # flake8-tidy-imports (import best practices)
|
|
"ASYNC", # async/await best practices
|
|
"RET", # flake8-return (return improvements)
|
|
"SIM118", # use `key in dict` instead of `key in dict.keys()`
|
|
"UP006", # use collections.abc
|
|
"UP007", # use X | Y for unions
|
|
"UP035", # use dict/list instead of typing.Dict/List
|
|
"UP037", # remove quotes from type annotations
|
|
"UP045", # use X | None instead of Optional[X]
|
|
"UP004", # use isinstance instead of type
|
|
"UP008", # use super() instead of super(Class, self)
|
|
"UP010", # use isinstance for type checks
|
|
"UP018", # use str() instead of "string"
|
|
"UP031", # use f-strings for .format()
|
|
"UP032", # use f-strings for .format() with positional
|
|
"I001", # sort imports
|
|
"I002", # remove unused imports
|
|
]
|
|
ignore = ["E501"] # ignore line too long globally
|
|
|
|
[tool.ruff.lint.flake8-tidy-imports]
|
|
ban-relative-imports = "all"
|
|
|
|
[tool.ruff.lint.flake8-type-checking]
|
|
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
|
|
|
[tool.ruff.lint.isort]
|
|
no-sections = false
|
|
case-sensitive = true
|
|
combine-as-imports = true
|
|
force-single-line = false
|
|
force-sort-within-sections = true
|
|
known-first-party = []
|
|
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
|
|
lines-after-imports = 2
|
|
split-on-trailing-comma = true
|
|
|
|
[tool.ruff.lint.pydocstyle]
|
|
convention = "google"
|
|
ignore-decorators = ["typing.overload"]
|
|
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"lib/crewai/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements, unnecessary assignments, and hardcoded passwords in tests
|
|
"lib/crewai-tools/tests/**/*.py" = ["S101", "RET504", "S105", "S106", "RUF012", "N818", "E402", "RUF043", "S110", "B017"] # Allow various test-specific patterns
|
|
"lib/crewai-files/tests/**/*.py" = ["S101", "RET504", "S105", "S106", "B017", "F841"] # Allow assert statements and blind exception assertions in tests
|
|
"lib/cli/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements in tests
|
|
"lib/crewai-core/tests/**/*.py" = ["S101", "RET504", "S105", "S106"] # Allow assert statements in tests
|
|
"lib/devtools/tests/**/*.py" = ["S101"]
|
|
|
|
|
|
[tool.mypy]
|
|
strict = true
|
|
disallow_untyped_defs = true
|
|
disallow_any_unimported = true
|
|
no_implicit_optional = true
|
|
check_untyped_defs = true
|
|
warn_return_any = true
|
|
show_error_codes = true
|
|
warn_unused_ignores = true
|
|
python_version = "3.12"
|
|
exclude = "(?x)(^lib/crewai/src/crewai/cli/templates/|^lib/cli/src/crewai_cli/templates/|^lib/crewai/tests/|^lib/crewai-tools/tests/|^lib/crewai-files/tests/|^lib/cli/tests/|^lib/devtools/tests/)"
|
|
plugins = ["pydantic.mypy"]
|
|
|
|
|
|
[tool.bandit]
|
|
exclude_dirs = ["lib/crewai/src/crewai/cli/templates", "lib/cli/src/crewai_cli/templates"]
|
|
|
|
|
|
[tool.pytest.ini_options]
|
|
markers = [
|
|
"telemetry: mark test as a telemetry test (don't mock telemetry)",
|
|
]
|
|
testpaths = [
|
|
"lib/crewai/tests",
|
|
"lib/crewai-tools/tests",
|
|
"lib/crewai-files/tests",
|
|
"lib/cli/tests",
|
|
"lib/crewai-core/tests",
|
|
]
|
|
asyncio_mode = "strict"
|
|
asyncio_default_fixture_loop_scope = "function"
|
|
addopts = "--tb=short -n auto --timeout=60 --dist=loadfile --max-worker-restart=2 --block-network --import-mode=importlib"
|
|
python_files = "test_*.py"
|
|
python_classes = "Test*"
|
|
python_functions = "test_*"
|
|
|
|
[tool.commitizen]
|
|
name = "cz_customize"
|
|
version_provider = "scm"
|
|
tag_format = "$version"
|
|
allowed_prefixes = ["Merge", "Revert"]
|
|
changelog_incremental = true
|
|
update_changelog_on_bump = false
|
|
|
|
[tool.commitizen.customize]
|
|
schema = "<type>(<scope>): <description>"
|
|
schema_pattern = "^(feat|fix|refactor|perf|test|docs|chore|ci|style|revert)(\\(.+\\))?!?: .{1,72}"
|
|
bump_pattern = "^(feat|fix|perf|refactor|revert)"
|
|
bump_map = { feat = "MINOR", fix = "PATCH", perf = "PATCH", refactor = "PATCH", revert = "PATCH" }
|
|
info = "Commits must follow Conventional Commits 1.0.0."
|
|
|
|
|
|
[tool.uv]
|
|
exclude-newer = "3 days"
|
|
|
|
# composio-core pins rich<14 but textual requires rich>=14.
|
|
# onnxruntime 1.24+ dropped Python 3.10 wheels; cap it so qdrant[fastembed] resolves on 3.10.
|
|
# fastembed 0.7.x and docling 2.63 cap pillow<12; the removed APIs don't affect them.
|
|
# langchain-core <1.2.31 has GHSA-926x-3r5x-gfhw and is required by langchain-text-splitters 1.1.2+.
|
|
# langchain-core 1.0.0-1.3.2 has GHSA-pjwx-r37v-7724 (unsafe deserialization via broad load() allowlists); force 1.3.3+.
|
|
# langchain-text-splitters <1.1.2 has GHSA-fv5p-p927-qmxr (SSRF bypass in split_text_from_url).
|
|
# transformers 4.57.6 has CVE-2026-1839; force 5.4+ (docling 2.84 allows huggingface-hub>=1).
|
|
# cryptography 46.0.6 has CVE-2026-39892; force 46.0.7+.
|
|
# pypdf <6.10.2 has GHSA-4pxv-j86v-mhcw, GHSA-7gw9-cf7v-778f, GHSA-x284-j5p8-9c5p; force 6.10.2+.
|
|
# uv <0.11.6 has GHSA-pjjw-68hj-v9mw; force 0.11.6+.
|
|
# python-multipart <0.0.27 has GHSA-pp6c-gr5w-3c5g (DoS via unbounded multipart headers).
|
|
# gitpython <3.1.50 has GHSA-mv93-w799-cj2w (config_writer newline injection bypassing the 3.1.49 patch -> RCE via core.hooksPath).
|
|
# urllib3 <2.7.0 has GHSA-qccp-gfcp-xxvc (ProxyManager cross-origin redirect leaks Authorization/Cookie) and GHSA-mf9v-mfxr-j63j (streaming decompression-bomb bypass); force 2.7.0+.
|
|
# langsmith <0.7.31 has GHSA-rr7j-v2q5-chgv (streaming token redaction bypass); force 0.7.31+.
|
|
# authlib <1.6.11 has GHSA-jj8c-mmj3-mmgv (CSRF bypass in cache-based state storage).
|
|
# litellm 1.83.8+ hard-pins openai==2.24.0, missing openai.types.responses used by crewai;
|
|
# override to >=2.30.0 (the version litellm 1.83.7 used) until upstream relaxes the pin.
|
|
override-dependencies = [
|
|
"openai>=2.30.0,<3",
|
|
"rich>=13.7.1",
|
|
"onnxruntime<1.24; python_version < '3.11'",
|
|
"pillow>=12.1.1",
|
|
"langchain-core>=1.3.3,<2",
|
|
"langchain-text-splitters>=1.1.2,<2",
|
|
"urllib3>=2.7.0",
|
|
"transformers>=5.4.0; python_version >= '3.10'",
|
|
"cryptography>=46.0.7",
|
|
"pypdf>=6.10.2,<7",
|
|
"uv>=0.11.6,<1",
|
|
"python-multipart>=0.0.27,<1",
|
|
"gitpython>=3.1.50,<4",
|
|
"langsmith>=0.7.31,<0.8",
|
|
"authlib>=1.6.11",
|
|
# scrapegraph-py 2.x removed Client class; pin until upstream fixes type ignores
|
|
"scrapegraph-py>=1.46.0,<2",
|
|
]
|
|
|
|
[tool.uv.workspace]
|
|
members = [
|
|
"lib/crewai",
|
|
"lib/crewai-tools",
|
|
"lib/devtools",
|
|
"lib/crewai-files",
|
|
"lib/cli",
|
|
"lib/crewai-core",
|
|
]
|
|
|
|
|
|
[tool.uv.sources]
|
|
crewai = { workspace = true }
|
|
crewai-tools = { workspace = true }
|
|
crewai-devtools = { workspace = true }
|
|
crewai-files = { workspace = true }
|
|
crewai-cli = { workspace = true }
|
|
crewai-core = { workspace = true }
|