[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[metadata]
license_file = "LICENSE"
description_file = "README.md"

[project]
name = "ag2"
description = "A programming framework for agentic AI"
readme = "README.md"
authors = [
    {name = "Chi Wang & Qingyun Wu", email = "support@ag2.ai"}
]

keywords = [
    "ai",
    "agent",
    "autogen",
    "ag2",
    "ag2.ai",
    "ag2ai",
    "agentic"
]

requires-python = ">=3.10,<3.14"

dynamic = ["version"]

classifiers = [
    "Development Status :: 5 - Production/Stable",
    "License :: OSI Approved :: Apache Software License",
    "Programming Language :: Python",
    "Programming Language :: Python :: Implementation :: CPython",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3 :: Only",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Operating System :: OS Independent",
    "Topic :: Software Development :: Libraries :: Application Frameworks",
    "Topic :: Software Development :: Libraries :: Python Modules",
    "Topic :: Software Development :: Libraries",
    "Topic :: Software Development",
    "Intended Audience :: Developers",
    "Intended Audience :: Information Technology",
]

dependencies = [
    "diskcache",
    "termcolor",
    "python-dotenv",
    "tiktoken",
    # Disallowing 2.6.0 can be removed when this is fixed https://github.com/pydantic/pydantic/issues/8705
    "pydantic>=2.6.1,<3",
    "docker",
    "packaging",
    "asyncer==0.0.8",
#    "fast-depends>=2.4.12,<3",  # integrated into the package
    "httpx>=0.28.1,<1",
    "anyio>=3.0.0,<5.0.0"  # needed by the internal fast-depends
]

[project.optional-dependencies]

flaml = [
    "flaml",
    # numpy is installed by flaml, but we want to pin the version to below 2.x (see https://github.com/microsoft/autogen/issues/1960)
    "numpy>=2.1; python_version>='3.13'",  # numpy 2.1+ required for Python 3.13
    "numpy>=1.24.0,<2.0.0; python_version<'3.13'",  # numpy 1.24+ for older Python versions
]

# public distributions

openai = [
    "openai>=1.99.3",
]

openai-realtime = [
    "ag2[openai]",
    "openai[realtime]",
]

jupyter-executor = [
    "jupyter-kernel-gateway",
    "websocket-client",
    "requests",
    "jupyter-client>=8.6.0",
    "ipykernel>=6.29.0",
]

retrievechat = [
    "protobuf==6.31.1",
    "chromadb==1.0.16",
    "sentence_transformers<=5.1.0",
    "pypdf",
    "ipython",
    "beautifulsoup4",
    "markdownify",
]

retrievechat-pgvector = [
    "ag2[retrievechat]",
    "pgvector>=0.2.5",
    "psycopg[binary]>=3.1.18; platform_system=='Windows' or platform_system=='Darwin'",
    "psycopg>=3.1.18; platform_system=='Linux'",
]

retrievechat-mongodb = [
    "ag2[retrievechat]",
    "pymongo>=4.0.0",
    "numpy",
]

retrievechat-qdrant = [
    "ag2[retrievechat]",
    "qdrant_client",
    "fastembed>=0.3.1",
]

retrievechat-couchbase = [
    "ag2[retrievechat]",
    "couchbase>=4.3.0",
    "numpy",
]

graph-rag-falkor-db = [
    "graphrag_sdk==0.7.1",
    "falkordb>=1.0.10",
]

rag = [
    "docling>=2.15.1,<3",
    "selenium>=4.28.1,<5",
    "webdriver-manager==4.0.2",
    "chromadb>=0.5,<2",
    "llama-index>=0.12,<1",
    "llama-index-vector-stores-chroma==0.4.1",
    "llama-index-vector-stores-mongodb==0.8.0",
    "llama-index-embeddings-huggingface==0.6.0",
    "llama-index-llms-langchain==0.7.0",
    "requests>=2.32.3,<3",
]


crawl4ai = [
    "crawl4ai>=0.4.247,<0.8",
]

browser-use = [
    # ToDo: Restrict browser-use to a specific version
    # browser-use>0.1.38 moved langchain-google-genai, aws, etc to its dev dependencies
    "browser-use==0.1.37",
]

google-client = [
    "google-api-python-client>=2.163.0,<3.0",
]

google-api = [
    "ag2[google-client]",
    "google-auth-httplib2>=0.2.0,<0.3",
    "google-auth-oauthlib>=1.2.1,<2.0",
]

google-search = [
    "ag2[google-client]",
]

wikipedia = [
    "wikipedia-api>=0.8.1, <1.0"
]

neo4j = [
    "docx2txt==0.9",
    "llama-index>=0.12,<1",
    "llama-index-graph-stores-neo4j==0.5.0",
    "llama-index-readers-web==0.5.0",
]

# used for agentchat_realtime_swarm notebook and realtime agent twilio demo
twilio = [
    "fastapi>=0.115.0,<1",
    "uvicorn>=0.30.6,<1",
    "twilio>=9.3.2"
]

mcp = [
    # mcp 1.9.4+ fixes issue #1865 where string parameters are converted to integers
    "mcp>=1.11.0",
]

mcp-proxy-gen = [
    "fastapi-code-generator>=0.5.4",
    "fastapi>=0.112,<1",
    "requests",  # do not pin it
    "typer",
    "PyYAML",
]

interop-crewai = [
    "crewai[tools]>=0.76,<1; python_version>='3.10' and python_version<'3.13'",
    # TODO: crewai needs litellm and litellm version above 1.67.1 has problem in windows.
    # TODO: Remove the below line once the problem is fixed
    "litellm<=1.75.5.post1",
    "weaviate-client>=4,<5; python_version>='3.10' and python_version<'3.13'",
]
interop-langchain = ["langchain-community>=0.3.12,<1"]
interop-pydantic-ai = ["pydantic-ai==0.6.2"]
interop =[
    "ag2[interop-crewai, interop-langchain, interop-pydantic-ai]"
]

autobuild = [
    "chromadb",
    "sentence_transformers<=5.1.0",
    "huggingface-hub"
]

blendsearch = ["flaml[blendsearch]"]
mathchat = ["sympy", "wolframalpha"]
captainagent = ["ag2[autobuild]", "pandas"]
teachable = ["chromadb"]
lmm = ["replicate", "pillow"]
graph = ["networkx", "matplotlib"]
gemini = [
    "google-api-core",
    "google-genai>=1.20.0",
    "google-cloud-aiplatform",
    "google-auth",
    "pillow",
    "jsonschema",
]

gemini-realtime = [
    "ag2[gemini]",
    "ag2[websockets]",
]

together = ["together>=1.2"]
websurfer = ["beautifulsoup4", "markdownify", "pdfminer.six", "pathvalidate"]
redis = ["redis"]
cosmosdb = ["azure-cosmos>=4.2.0"]
websockets = ["websockets>=14.0,<16"]
long-context = ["llmlingua<0.3"]
anthropic = ["anthropic[vertex]>=0.23.1"]
cerebras = ["cerebras_cloud_sdk>=1.0.0"]
mistral = ["mistralai>=1.0.1"]
groq = ["groq>=0.9.0"]
cohere = ["cohere>=5.13.5"]
ollama = ["ollama>=0.4.7", "fix_busted_json>=0.0.18"]
bedrock = ["boto3>=1.34.149"]
deepseek = ["ag2[openai]"]

commsagent-discord = ["discord.py>=2.4.0,<2.6"]
commsagent-slack = ["slack_sdk>=3.33.0,<3.40"]
commsagent-telegram = ["telethon>=1.38.1, <2"]

duckduckgo = ["duckduckgo_search>=8.0.2"]
tavily = ["tavily-python>=0.7.4"]

## dev dependencies

# test dependencies
test = [
    "ipykernel==6.30.1",
    "nbconvert==7.16.6",
    "nbformat==5.10.4",
    "pytest-cov==6.2.1",
    "pytest-asyncio==1.1.0",
    "pytest==8.4.1",
    "mock==5.2.0",
    "pandas==2.3.1",
    "fastapi==0.116.1",
    "dirty-equals==0.9.0",
    "mcp>=1.11.0"
]

docs = [
    "mkdocs-material==9.6.16",
    "mkdocstrings[python]==0.30.0",
    "mkdocs-literate-nav==0.6.2",
    "mdx-include==1.4.2",
    # ToDo: currently problematic and cannot be upgraded
    "mkdocs-git-revision-date-localized-plugin==1.4.7",
    "mike==2.1.3",
    "typer==0.16.0",
    "mkdocs-minify-plugin==0.8.0",
    "mkdocs-macros-plugin==1.3.7",  # includes with variables
    "mkdocs-glightbox==0.4.0",  # img zoom
    "mkdocs-redirects==1.2.2",  # required for handling redirects natively
    "pillow",  # required for mkdocs-glightbo
    "cairosvg",  # required for mkdocs-glightbo
    "pdoc3==0.11.6",
    "jinja2==3.1.6",
    "pyyaml==6.0.2",
    "termcolor==3.1.0",
    "nbclient==0.10.2",
    "mcp>=1.11.0",
]

types = [
    "mypy==1.17.1",
    "types-PyYAML",
    "types-decorator",
    "types-pycurl",
    "types-python-dateutil",
    "types-requests",
    "types-ujson",
    "ag2[test, openai]",
]

lint = [
    "ruff==0.12.8",
    "codespell==2.4.1",
    "pyupgrade-directories==0.3.0",
]

dev = [
    "toml==0.10.2",
    "ag2[lint,test,types,docs]",
    "pre-commit==4.3.0",
    "detect-secrets==1.5.0",
    "uv==0.8.8",
]


[project.urls]
Homepage = "https://ag2.ai/"
Documentation = "https://docs.ag2.ai"
Tracker = "https://github.com/ag2ai/ag2/issues"
Source = "https://github.com/ag2ai/ag2"
Discord = "https://discord.gg/pAbnFJrkgZ"


[tool.hatch.version]
path = "autogen/version.py"

[tool.hatch.build]
skip-excluded-dirs = true
exclude = ["/test", "/notebook"]

[tool.hatch.build.targets.wheel]
packages = ["autogen"]
only-include = [
    "autogen",
    # need for generation of MCP Servers from OpenAPI specification
    "templates",
]

[tool.hatch.build.targets.sdist]
exclude = ["test", "notebook"]

[tool.hatch.build.targets.wheel.sources]
"autogen" = "autogen"

[tool.pytest.ini_options]
addopts = '--cov=autogen --cov-append --cov-branch --cov-report=xml -m "not conda"'
testpaths = [
    "test",
]

markers = [
    "conda: test related to conda forge distribution",
    "all",
    "openai",
    "openai_realtime",
    "gemini",
    "gemini_realtime",
    "anthropic",
    "deepseek",
    "cosmosdb",
    "ollama",
    "bedrock",
    "cerebras",
    "aux_neg_flag",
    # optional deps
    "redis",
    "docker",
    "docs",
    "rag",
    "jupyter_executor",
    "retrievechat",
    "retrievechat_pgvector",
    "retrievechat_mongodb",
    "retrievechat_qdrant",
    "graph_rag_falkor_db",
    "neo4j",
    "twilio",
    "mcp",
    "interop",
    "browser_use",
    "crawl4ai",
    "google_api",
    "google_search",
    "websockets",
    "commsagent_discord",
    "commsagent_slack",
    "commsagent-telegram",
    "lmm",
]

[tool.black]
# https://github.com/psf/black
line-length = 120
exclude = "(.eggs|.git|.hg|.mypy_cache|.venv|_build|buck-out|build|dist)"


[tool.ruff]
fix = true
line-length = 120
target-version = 'py310'
# Exclude a variety of commonly ignored directories.
exclude = [
    ".eggs",
    ".git",
    ".mypy_cache",
    ".ruff_cache",
    "__pypackages__",
    "_build",
    "build",
    "dist",
    "docs",
    # This file needs to be either upgraded or removed and therefore should be
    # ignore from type checking for now
    "math_utils\\.py$",
    "setup_*.py",
]

preview = true

[tool.ruff.lint]
# Enable Pyflakes `E` and `F` codes by default.
select = [
    "E",     # pycodestyle errors     https://docs.astral.sh/ruff/rules/#error-e
    "W",     # pycodestyle warnings   https://docs.astral.sh/ruff/rules/#warning-w
    "C90",   # mccabe                 https://docs.astral.sh/ruff/rules/#mccabe-c90
    "N",     # pep8-naming            https://docs.astral.sh/ruff/rules/#pep8-naming-n
#    "D",     # pydocstyle             https://docs.astral.sh/ruff/rules/#pydocstyle-d
    "I",     # isort                  https://docs.astral.sh/ruff/rules/#isort-i
    "F",     # pyflakes               https://docs.astral.sh/ruff/rules/#pyflakes-f
    "ASYNC", # flake8-async           https://docs.astral.sh/ruff/rules/#flake8-async-async
#    "C4",    # flake8-comprehensions  https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4
#    "B",     # flake8-bugbear         https://docs.astral.sh/ruff/rules/#flake8-bugbear-b
    "Q",     # flake8-quotes          https://docs.astral.sh/ruff/rules/#flake8-quotes-q
#    "T20",   # flake8-print           https://docs.astral.sh/ruff/rules/#flake8-print-t20
    "SIM",   # flake8-simplify        https://docs.astral.sh/ruff/rules/#flake8-simplify-sim
#    "PT",    # flake8-pytest-style    https://docs.astral.sh/ruff/rules/#flake8-pytest-style-pt
#    "PTH",   # flake8-use-pathlib     https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
#    "TCH",   # flake8-type-checking   https://docs.astral.sh/ruff/rules/#flake8-type-checking-tch
#    "RUF",   # Ruff-specific rules    https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
#    "PERF",  # Perflint               https://docs.astral.sh/ruff/rules/#perflint-perf
    "RUF022", # Sort __all__           https://docs.astral.sh/ruff/rules/unsorted-dunder-all/
    "UP",     # pyupgrade              https://docs.astral.sh/ruff/rules/#pydocstyle-d
]

extend-select = ["D417"]

ignore = ["E501", "F403", "C901",
    "E402",
    "E721",
    "ASYNC109",
    "E501",  # line too long, handled by formatter later
    "D100", "D101", "D102", "D103", "D104",
    "C901",  # too complex
]

[tool.ruff.lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10

[tool.ruff.lint.isort]
case-sensitive = true

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint.pydocstyle]
convention = "google"


[tool.mypy]
python_version = "3.10"

files = [
    "autogen/agentchat/agent.py",
#    "autogen/agentchat/cenversable_agent.py",
    "autogen/agentchat/contrib/rag",
    "autogen/agentchat/contrib/graph_rag",
    "autogen/agentchat/contrib/swarm_agent.py",
    "autogen/agentchat/group",
    "autogen/agentchat/realtime_agent",
    "autogen/agentchat/utils.py",
    "autogen/agents",
    "autogen/coding",
    "autogen/exception_utils.py",
    "autogen/fast_depends",
    "autogen/import_utils.py",
    "autogen/interop",
    "autogen/io",
    "autogen/json_utils.py",
    "autogen/llm_config",
    "autogen/logger",
    "autogen/messages",
    "autogen/oai/gemini_types.py",
    "autogen/oai/oai_models",
    "autogen/oai/openai_utils.py",
    "autogen/tools",
    "autogen/_website",
    "website/*.py",
    "test/agentchat/contrib/rag",
    "test/agentchat/contrib/graph_rag",
    "test/agentchat/contrib/test_swarm.py",
    "test/agentchat/group",
    "test/agentchat/realtime_agent",
    "test/agents",
    "test/conftest.py",
#    "test/fast_depends",
    "test/interop",
    "test/io",
    "test/oai/test_oai_models.py",
    "test/oai/test_gemini_types.py",
    "test/test_json_utils.py",
    "test/test_llm_config.py",
    "test/messages",
    "test/test_import_utils.py",
    "test/test_import.py",
    "test/tools",
    "test/website",
]

exclude = [
    "autogen/math_utils\\.py",
    "autogen/oai/completion\\.py",
    "autogen/agentchat/contrib/compressible_agent\\.py",
    "autogen/agentchat/contrib/math_user_proxy_agent.py",
    "autogen/oai/openai_utils.py",
]

strict = true
ignore_missing_imports = true
install_types = true
non_interactive = true
plugins = ["pydantic.mypy"]

# remove after all files in the repo are fixed
follow_imports = "silent"

# from https://blog.wolt.com/engineering/2021/09/30/professional-grade-mypy-configuration/
disallow_untyped_defs = true
no_implicit_optional = true
check_untyped_defs = true
warn_return_any = true
show_error_codes = true

warn_unused_ignores = false

disallow_incomplete_defs = true
disallow_untyped_decorators = true
disallow_any_unimported = true

[tool.codespell]
skip = "*.js,*.map,*.pdf,*.po,*.ts,*.json,*.svg,./website/node_modules,.notebook/agentchat_microsoft_fabric.ipynb,./notebook/agentchat_swarm_graphrag_telemetry_trip_planner.ipynb,./notebook/agentchat_graph_rag_neo4j.ipynb"
quiet-level = 3
ignore-words-list = "ans,linar,nam,tread,ot,assertIn,dependin,socio-economic,ege,leapYear,fO,bu,te,ROUGE,ser,doubleClick,CNa,wOh,Hart,Empress,Chage,mane,digitalize,brunch"
