pyproject.toml
Rama main · réplica de lectura del repositorio original.
[build-system]
requires = ["uv_build>=0.9.2,<0.13"]
build-backend = "uv_build"
[tool.uv.build-backend]
# Distribution is named "ag2" but the importable module lives in ./ag2
module-root = "."
module-name = "ag2"
source-exclude = ["test", "notebook"]
[[tool.uv.index]]
name = "pytorch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.uv.sources]
torch = [{ index = "pytorch-cpu", marker = "sys_platform == 'linux'" }]
[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"
[project]
name = "ag2"
description = "A programming framework for agentic AI"
readme = "README.md"
license = "Apache-2.0"
license-files = ["LICENSE"]
authors = [{ name = "Chi Wang & Qingyun Wu", email = "support@ag2.ai" }]
keywords = ["ai", "agent", "autogen", "ag2", "ag2.ai", "ag2ai", "agentic"]
requires-python = ">=3.11"
version = "1.3.1"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"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",
"Framework :: Pydantic",
"Framework :: Pydantic :: 2",
]
dependencies = [
"pydantic>=2.6.1,<3",
"httpx>=0.28.1,<1",
"anyio>=4.0.0,<5.0.0",
# SKILL.md frontmatter (ag2.tools.skills)
"pyyaml>=6.0.2",
# for tools
"fast-depends[pydantic]>=3.0.8,<4.0.0",
]
[project.optional-dependencies]
# Each extra below corresponds to a `missing_optional_dependency(..., "<extra>", ...)`
# fallback in the codebase. Extension packages (docker, daytona, e2b, sounddevice, exa-py,
# tinyfish, ...) use `missing_additional_dependency` and are installed directly, not as extras.
# === Agent protocols ===
a2a = ["a2a-sdk>=1.3.0,<2"]
a2ui = ["jsonschema>=4.18.0,<5", "starlette>=0.40,<2"]
acp = [
"agent-client-protocol>=0.12.1,<0.13",
# Tool exposure to CLI agents runs an in-process HTTP MCP server, also requiring starlette and uvicorn
"ag2[mcp]",
"starlette>=0.40,<2",
"uvicorn>=0.51.0,<1",
]
ag-ui = ["ag-ui-protocol>=1.0,<2"]
# === LLM providers (ag2.config) ===
openai = ["openai>=3.45.0,<4"]
anthropic = ["anthropic>=1.15.0,<3"]
gemini = [
# Version bounds: local types in gemini_types.py are tested for subset compatibility
# with the SDK (local can have extra fields for forward compatibility).
"google-genai>=1.68.0,<3.0",
# `google.auth.credentials` / `google.oauth2.service_account` in gemini_client.py.
# Vertex AI is reached through google-genai's own `vertexai=True`, so
# google-cloud-aiplatform is not needed.
"google-auth",
]
# === Voice / TTS providers (ag2.live) ===
elevenlabs = ["elevenlabs>=2.73.0,<3"]
xai = ["xai-sdk>=1.21.0,<2"]
zai = ["zai-sdk>=0.2.3,<1"]
mistral = ["mistralai>=3.6.0,<4"]
ollama = ["ollama>=0.5.2,<1"]
bedrock = ["aiobotocore>=3.9.1,<4"]
dashscope = ["dashscope>=1.25.13"]
typesafe = ["typesafe-sdk>=0.7.5,<0.8"]
redis = ["redis>=5.0,<9"]
# SDK only: ag2 builds spans and hands them to whatever SpanProcessor the caller
# passes in, so the exporter (console, OTLP over http/grpc, vendor SDK) is the
# caller's choice to install.
tracing = ["opentelemetry-sdk>=1.20"]
metrics = ["prometheus-client>=0.20.0,<0.30.0"]
# === Search tools ===
tavily = ["tavily-python>=0.7.4,<0.9"]
ddgs = ["ddgs>=9.0.0,<10"]
perplexity = ["perplexityai>=0.30.0,<1"]
# === MCP (ag2.mcp) ===
mcp = [
"mcp>=2.3.0,<3",
"mcp-types>=2.3.0,<3",
# imported directly to validate tool arguments; `mcp` requires it too, so this
# only pins what is already installed
"jsonschema>=4.20.0,<5",
]
# MCP-UI resources (ag2.mcp_ui) — return renderable UI blobs from tool results
mcp-ui = [
"mcp-ui-server>=1.0.0",
"mcp>=2.3.0,<3",
]
[dependency-groups]
# Dev dependency groups (PEP 735). These replace the former dev *extras* and are
# NOT published with the package — install with `uv pip install --group <name>`
# (or `uv sync`). Feature extras (openai, gemini, redis, …) stay in
# [project.optional-dependencies] because they are part of the published API.
# test dependencies
test-core = [
"pytest==9.1.1",
"pytest-asyncio==1.4.0",
"pytest-cov==7.1.0",
"pytest-timeout>=2.4.0,<3",
"dirty-equals>=0.11,<0.12",
"freezegun>=1.5,<2",
]
test = [
{ include-group = "test-core" },
"docker>=6.0.0,<8",
"ag2[mcp]",
"ag2[mcp-ui]", # ag2.mcp_ui — MCP-UI resource & action builders
"pillow", # test/providers/gemini builds an image fixture; no longer implied by ag2[gemini]
"python-dotenv", # provider smoke tests load repo-root .env
"respx>=0.23.0,<0.24.0", # search tests
# starlette >=1.0 drives `starlette.testclient.TestClient` with httpx2 and warns
# (StarletteDeprecationWarning) when it has to fall back to httpx 0.x; the 2.10
# floor is what mcp>=2.3 requires
"httpx2>=2.10.0,<3",
]
# All optional feature deps needed so the full (non-LLM) test suite can be
# collected and run. This has no dev-extra equivalent; it is consumed directly
# by the test CI workflow alongside the `test` group.
optionals = [
"ag2[redis]",
"ag2[ag-ui]",
"ag2[a2a]", # ag2.a2a — without it `test/a2a` importorskips itself out of the run
"ag2[a2ui]", # provides starlette/jsonschema for AG-UI / a2ui serving tests
"ag2[mcp]", # ag2.mcp — serve an Agent as an MCP server
"ag2[mcp-ui]", # ag2.mcp_ui — MCP-UI resource & action builders
"ag2[acp]",
"ag2[tracing]",
"ag2[metrics]",
# search tools
"ag2[tavily,ddgs,perplexity]",
# extensions are not shipped as extras; install their packages directly for testing
"a2a-sdk[signing,sqlite]", # AgentCard JWS signing (test_card_signing.py) and the SQL task store (test_multi_replica.py); not part of ag2[a2a]
"agent-client-protocol[http]", # ag2.acp.remote transports — without them `test/acp/test_remote_*` importorskips itself out of the run
"watchdog>=4.0,<7", # DiskKnowledgeStore (ag2.knowledge)
"websockets>=14.0,<17", # WsLink (ag2.network)
"mistralai[realtime]>=3.6.0,<4", # MistralRealtimeTranscriber, MistralRealtimeTTSConfig (ag2.live)
"docker>=6.0.0,<8", # code execution (ag2.extensions.docker)
"daytona>=0.171.0,<1",
"tenki>=1.4.0,<2",
"boxd>=0.3.0,<1",
"e2b>=2.0.0,<3",
"tinyfish>=0.5,<0.6",
"exa-py>=2.12.1,<3",
"firecrawl-py>=4.53,<5",
"torch>=2.5,<3",
"transformers>=4.57,<6",
"safetensors>=0.4.3,<1",
# providers
"ag2[openai]",
"ag2[anthropic]",
"ag2[bedrock]",
"ag2[gemini]",
"ag2[ollama]",
"ag2[dashscope]",
"ag2[xai]",
"ag2[zai]",
"ag2[mistral]",
"ag2[typesafe]",
"ag2[elevenlabs]",
]
docs = [
"ag2[a2a]", # A2A is exposed in the public API by the optional `ag2.a2a` module
"ag2[tracing]", # Tracing is exposed in the public API by the optional `ag2.opentelemetry` / `ag2.middleware` module
"ag2[metrics]", # Metrics is exposed in the public API by the optional `ag2.middleware` module
"ag2[ag-ui]", # AG-UI is exposed in the public API by the optional `ag2.ag_ui` module
# Extensions are not shipped as extras; install their packages directly so docs can import the modules
"tinyfish>=0.5,<0.6",
"daytona>=0.171.0,<1",
"tenki>=1.4.0,<2",
"boxd>=0.3.0,<1",
"e2b>=2.0.0,<3",
"exa-py>=2.12.1,<3",
"firecrawl-py>=4.53,<5",
"docker>=6.0.0,<8", # Code execution tools are exposed in the public API by the optional `ag2.tools` module
"nlip-sdk>=0.1.0,<1", # NLIP is exposed in the public API by the optional `autogen.extensions.nlip` module
"nlip-server>=0.1.3,<1",
"torch>=2.5,<3", # Used by the optional `ag2.extensions.mi4afa` module
"transformers>=4.57,<6",
"safetensors>=0.4.3,<1",
# Optional dependencies
"ag2[openai]", # OpenAI is exposed in the public API by the optional `ag2.config` module
"ag2[anthropic]", # Anthropic is exposed in the public API by the optional `ag2.config` module
"ag2[gemini]", # Gemini is exposed in the public API by the optional `ag2.config` module
"ag2[ollama]", # Ollama is exposed in the public API by the optional `ag2.config` module
"ag2[dashscope]", # DashScope is exposed in the public API by the optional `ag2.config` module
"ag2[xai]", # xAI is exposed in the public API by the optional `ag2.config` module
"ag2[mistral]", # Mistral is exposed in the public API by the optional `ag2.config` module
"ag2[redis]", # Redis is exposed in the public API by the optional `ag2.streams` module
"watchdog>=4.0,<7", # DiskKnowledgeStore (ag2.knowledge) — additional dependency
"websockets>=14.0,<17", # WsLink (ag2.network) — additional dependency
"ag2[tavily,ddgs,perplexity]", # Search tools are exposed by optional search modules
"mkdocs-material==9.7.7",
"mkdocs-literate-nav==0.6.3",
"mdx-include==1.4.2",
# ToDo: currently problematic and cannot be upgraded
"mkdocs-git-revision-date-localized-plugin==1.6.0",
"typer>=0.22,<0.28",
"mkdocs-minify-plugin==0.8.0",
"mkdocs-macros-plugin==1.5.0", # includes with variables
"mkdocs-glightbox==0.5.2", # img zoom
"mkdocs-redirects==1.2.3", # required for handling redirects natively
"jinja2==3.1.6",
"pyyaml==6.0.3",
"mcp>=2.3.0,<3",
]
types = [
"mypy==2.4.0",
"types-PyYAML",
# `ag2/a2ui` registers format checks with jsonschema, which ships no inline types
"types-jsonschema",
# aiobotocore is data-driven and ships no runtime param classes. The extra pulls
# `botocore-stubs` in, which `ag2/config/bedrock/bedrock_client.py` needs under
# `disallow_any_unimported`. Type-check only — never a published constraint.
"types-aiobotocore[bedrock-runtime]",
{ include-group = "test" },
"ag2[openai, anthropic, gemini, mistral, xai, zai, ollama, dashscope, typesafe, elevenlabs, a2a, ag-ui, acp]",
# search tools in `ag2/tools/search`, checked under `disallow_any_unimported`
"ag2[ddgs, perplexity]",
# `ag2/streams/redis`, `ag2/knowledge/redis.py` and `ag2/middleware/builtin/metrics.py`:
# without these their imports are Any, which hides real errors (redis) or trips
# `disallow_any_unimported` (prometheus_client)
"ag2[redis, metrics]",
# `ag2/textual.py` subclasses textual's `App`; unresolved, the base class is Any
# and trips `disallow_any_unimported`. Not an extra: the TUI is an optional demo.
"textual",
# Extensions are not shipped as extras. Unresolved, their packages are Any, which hides
# real errors or trips `disallow_any_unimported` in `ag2/extensions/*`.
"daytona>=0.171.0,<1",
"tenki>=1.4.0,<2",
"boxd>=0.3.0,<1",
"exa-py>=2.12.1,<3",
"nlip-sdk>=0.1.0,<1",
"nlip-server>=0.1.3,<1",
"e2b>=2.0.0,<3",
]
lint = ["ruff==0.16.10", "codespell==2.4.3", "zizmor==1.30.1"]
dev = [
{ include-group = "lint" },
{ include-group = "test" },
{ include-group = "types" },
{ include-group = "docs" },
"prek==0.5.4",
]
[tool.pytest.ini_options]
addopts = '-m "not conda"'
timeout = 45
testpaths = ["test"]
markers = [
"conda: test related to conda forge distribution",
"all",
"openai",
"openai_realtime",
"gemini",
"gemini_realtime",
"anthropic",
"zai",
"mistral",
"typesafe",
"deepseek",
"cosmosdb",
"ollama",
"bedrock",
"cerebras",
"cohere",
"groq",
"together",
"integration",
"aux_neg_flag",
# optional deps
"redis",
"docker",
"docs",
"rag",
"jupyter_executor",
"retrievechat",
"retrievechat_pgvector",
"retrievechat_mongodb",
"retrievechat_qdrant",
"graph_rag_falkor_db",
"neo4j",
"mcp",
"interop",
"browser_use",
"crawl4ai",
"google_api",
"google_search",
"websockets",
"elevenlabs",
"commsagent_discord",
"commsagent_slack",
"commsagent-telegram",
"lmm",
"tracing",
]
[tool.coverage.run]
branch = true
source = ["ag2"]
# Store source paths relative to the repo root (with normalized separators) so
# coverage data recorded on different runners (Linux/macOS/Windows) can be
# merged by `coverage combine` into a single report before upload.
relative_files = true
[tool.ruff]
fix = true
line-length = 120
target-version = 'py311'
# 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
"D417", # undocumented-param https://docs.astral.sh/ruff/rules/undocumented-param/
]
ignore = [
"E501",
"F403",
"C901",
"E402",
"E721",
"E501", # line too long, handled by formatter later
"C901", # too complex
"ASYNC109",
"ASYNC240",
"UP042", # Preserve the str() behavior of existing public str/Enum types.
]
[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.11"
# The `ag2` tree is not yet strict-clean. Strict mypy coverage is being
# (re)introduced module-by-module; until then mypy is scoped to modules
# that already pass under `strict = true`.
files = [
"ag2/__init__.py",
"ag2/_import_utils.py",
"ag2/_model_input.py",
"ag2/_replay.py",
"ag2/_run_lifecycle.py",
"ag2/_telemetry_consts.py",
"ag2/a2a",
"ag2/a2ui",
"ag2/acp",
"ag2/ag_ui",
"ag2/agent.py",
"ag2/aggregate.py",
"ag2/annotations.py",
"ag2/assembly.py",
"ag2/compact.py",
"ag2/config",
"ag2/context.py",
"ag2/eval",
"ag2/events",
"ag2/exceptions.py",
"ag2/extensions",
"ag2/files",
"ag2/history.py",
"ag2/hitl.py",
"ag2/knowledge",
"ag2/live",
"ag2/mcp",
"ag2/mcp_ui",
"ag2/middleware",
"ag2/mypy.py",
"ag2/network/__init__.py",
"ag2/network/adapters/__init__.py",
"ag2/network/auth.py",
"ag2/network/channel.py",
"ag2/network/client/__init__.py",
"ag2/network/client/agent_client.py",
"ag2/network/client/channel.py",
"ag2/network/client/checkpoint.py",
"ag2/network/client/human_client.py",
"ag2/network/client/inject.py",
"ag2/network/client/network_client.py",
"ag2/network/client/task.py",
"ag2/network/client/tools/__init__.py",
"ag2/network/client/tools/say.py",
"ag2/network/envelope.py",
"ag2/network/errors.py",
"ag2/network/handoff.py",
"ag2/network/hub/arbiter.py",
"ag2/network/hub/expectations.py",
"ag2/network/hub/layout.py",
"ag2/network/hub/sweepers.py",
"ag2/network/identity.py",
"ag2/network/ids.py",
"ag2/network/policies.py",
"ag2/network/remote.py",
"ag2/network/rule.py",
"ag2/network/task_mirror.py",
"ag2/network/testing.py",
"ag2/network/transport",
"ag2/network/views",
"ag2/network/workflow_helpers.py",
"ag2/observers",
"ag2/plugin.py",
"ag2/policies",
"ag2/response",
"ag2/scopes.py",
"ag2/spec.py",
"ag2/stream.py",
"ag2/streams",
"ag2/task.py",
"ag2/testing.py",
"ag2/textual.py",
"ag2/tools",
"ag2/types.py",
"ag2/usage.py",
"ag2/utils.py",
"ag2/version.py",
"ag2/watch.py",
]
strict = true
ignore_missing_imports = true
install_types = true
non_interactive = true
plugins = ["pydantic.mypy", "ag2.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
# `perplexity.types` re-exports its result types without an `__all__`, which
# strict mode reads as "not exported". The alternative is importing from
# `perplexity.generated.*`, which is internal.
[[tool.mypy.overrides]]
module = "perplexity.*"
implicit_reexport = true
[[tool.mypy.overrides]]
module = "xai_sdk.*"
follow_untyped_imports = true
# `mcp-ui-server` is fully annotated but ships no `py.typed` marker, so mypy
# would hand us `Any` from every name we import. Following it uses its real types.
[[tool.mypy.overrides]]
module = "mcp_ui_server.*"
follow_untyped_imports = true
# `nlip-sdk` / `nlip-server` are annotated (pydantic models, typed session hooks) but
# ship no `py.typed` marker; `ag2/extensions/nlip` subclasses and returns their types.
[[tool.mypy.overrides]]
module = ["nlip_sdk.*", "nlip_server.*"]
follow_untyped_imports = true
# `ag2/extensions/mi4afa` is built on torch / transformers. They are too heavy for the
# `types` group, so the type-check job runs without them and their types are Any there.
[[tool.mypy.overrides]]
module = "ag2.extensions.mi4afa.*"
disallow_any_unimported = false
# AG-UI's SDK does not ship typing metadata, so values crossing that boundary
# are Any even though this module's own functions remain checked strictly.
[[tool.mypy.overrides]]
module = "ag2.ag_ui.*"
disable_error_code = ["no-any-unimported"]
# `sounddevice` ships no stubs, so its types arrive as Any at this module's boundary.
[[tool.mypy.overrides]]
module = "ag2.live.sound_device"
disable_error_code = ["no-any-unimported"]
# numpy's bundled stubs use 3.12-only `type` syntax, which mypy cannot parse
# under python_version = "3.11"; skip analysing numpy entirely (it is not our code).
[[tool.mypy.overrides]]
module = "numpy.*"
follow_imports = "skip"
follow_imports_for_stubs = true
[tool.codespell]
skip = "*.js,*.map,*.pdf,*.po,*.ts,*.json,*.svg"
quiet-level = 3
ignore-words-list = "ans,crasher,fulfilment,iif"