[build-system]
build-backend = "poetry.core.masonry.api"
# PEP 621 project metadata (for UV compatibility)
# This section coexists with [tool.poetry] during the migration period
requires = [ "poetry-core" ]

[project]
name = "openhands-ai"
description = "OpenHands: Code Less, Make More"
readme = "README.md"
license = "MIT"
authors = [ { name = "OpenHands", email = "contact@all-hands.dev" } ]
requires-python = ">=3.12,<3.14"
classifiers = [
  "Programming Language :: Python :: 3 :: Only",
  "Programming Language :: Python :: 3.12",
  "Programming Language :: Python :: 3.13",
]
# Version is managed dynamically by poetry-dynamic-versioning
dynamic = [ "version" ]

# Main dependencies (mirrors [tool.poetry.dependencies] for UV compatibility)
dependencies = [
  "aiohttp>=3.13.4",
  "anthropic[vertex]",
  "anyio==4.9",
  "asyncpg>=0.30",
  "authlib>=1.6.9",
  "bashlex>=0.18",
  "boto3",
  "browsergym-core==0.13.3",
  "deprecated",
  "deprecation>=2.1",
  "dirhash",
  "docker",
  "fastapi",
  "fastmcp>=3.2,<4",
  "gitpython>=3.1.49",
  "google-api-python-client>=2.164",
  "google-auth-httplib2",
  "google-auth-oauthlib",
  "google-cloud-aiplatform",
  "google-genai",
  "html2text",
  "httpx-aiohttp>=0.1.8",
  "ipywidgets>=8.1.5",
  "jinja2>=3.1.6",
  "joblib",
  "joserfc>=1.0.0",
  "json-repair",
  "jupyter-kernel-gateway",
  "kubernetes>=33.1",
  "libtmux>=0.46.2",
  "litellm==1.84.1",
  "lmnr>=0.7.20",
  "mcp>=1.25",
  "memory-profiler>=0.61",
  "numpy",
  "openai==2.33.0",
  "openhands-agent-server==1.23.1",
  "openhands-sdk==1.23.1",
  "openhands-tools==1.23.1",
  "opentelemetry-api>=1.33.1",
  "opentelemetry-exporter-otlp-proto-grpc>=1.33.1",
  "orjson>=3.11.6",
  "pathspec>=0.12.1",
  "pexpect",
  "pg8000>=1.31.5",
  "pillow>=12.1.1",
  "playwright>=1.55",
  "poetry>=2.3.4,<2.4.0",
  "prompt-toolkit>=3.0.50",
  "protobuf>=5.29.6,<6",
  "psutil",
  "pybase62>=1",
  "pygithub>=2.5",
  "pyjwt>=2.12",
  "pylatexenc",
  "pypdf>=6.10.2",
  "python-docx",
  "python-dotenv",
  "python-frontmatter>=1.1",
  "python-json-logger>=3.2.1",
  "python-multipart>=0.0.28",
  "python-pptx",
  "python-socketio==5.14",
  "pythonnet; sys_platform=='win32'",
  "pyyaml>=6.0.2",
  "qtconsole>=5.6.1",
  "rapidfuzz>=3.9",
  "redis>=5.2,<7",
  "requests>=2.33",
  "setuptools>=78.1.1",
  "shellingham>=1.5.4",
  "sqlalchemy[asyncio]>=2.0.40",
  "sse-starlette>=3.0.2",
  "starlette>=0.49.1",
  "tenacity>=8.5,<10",
  "termcolor",
  "toml",
  "tornado>=6.5",
  "tree-sitter-language-pack>=0.7.3",
  "types-toml",
  "urllib3>=2.7.0",
  "uvicorn",
  "whatthepatch>=1.0.6",
  "zope-interface==7.2",
]

urls.Homepage = "https://github.com/OpenHands/OpenHands"
urls.Repository = "https://github.com/OpenHands/OpenHands"

[dependency-groups]
dev = [
  "build",
  "mypy==1.17",
  "pre-commit==4.2",
  "pytest>=8.4",
  "pytest-asyncio>=1.3",
  "ruff==0.12.5",
  "types-setuptools",
]
test = [
  "gevent>=24.2.1,<26",
  "pandas",
  "pytest",
  "pytest-asyncio",
  "pytest-cov",
  "pytest-forked",
  "pytest-playwright>=0.7",
  "pytest-timeout>=2.4",
  "pytest-xdist",
  "reportlab",
]
runtime = [
  "flake8",
  "jupyterlab",
  "notebook",
]

[tool.poetry]
name = "openhands-ai"
version = "1.7.0"
description = "OpenHands: Code Less, Make More"
authors = [ "OpenHands" ]
license = "MIT"
readme = "README.md"
repository = "https://github.com/OpenHands/OpenHands"
packages = [
  { include = "openhands/**/*" },
  { include = "pyproject.toml", to = "openhands" },
  { include = "poetry.lock", to = "openhands" },
]
include = [
  "skills/**/*",
]

[tool.poetry.dependencies]
python = "^3.12,<3.14"
authlib = ">=1.6.9"                                # CVE-2026-27962 (fixed in 1.6.9)
orjson = ">=3.11.6"                                # Pinned to fix CVE-2025-67221
litellm = "1.84.1"                                 # Exact pin to the verified 1.84.1 release; bump explicitly when upgrading (rather than a floor) to ensure only the tested version is used
openai = "2.33.0"                                  # Pin because litellm 1.84.1 requires 2.33.0 and is incompatible with >=1.100.0 (BerriAI/litellm#13711)
aiohttp = ">=3.13.4"                               # Keep aiohttp on a fixed-or-newer release while allowing litellm's pinned 3.13.4
google-genai = "*"                                 # To use litellm with Gemini Pro API
google-api-python-client = "^2.164.0"              # For Google Sheets API
google-auth-httplib2 = "*"                         # For Google Sheets authentication
google-auth-oauthlib = "*"                         # For Google Sheets OAuth
termcolor = "*"
docker = "*"
fastapi = "*"
toml = "*"
types-toml = "*"
uvicorn = "*"
numpy = "*"
json-repair = "*"
browsergym-core = "0.13.3"                         # integrate browsergym-core as the browsing interface
playwright = "^1.55.0"
html2text = "*"
deprecated = "*"
pexpect = "*"
jinja2 = "^3.1.6"
python-multipart = ">=0.0.28"
tenacity = ">=8.5,<10.0"
zope-interface = "7.2"
pathspec = ">=0.12.1,<1.1.0"
pyjwt = "^2.12.0"
dirhash = "*"
tornado = ">=6.5"
python-dotenv = "*"
rapidfuzz = "^3.9.0"
tree-sitter-language-pack = "^0.7.3"
whatthepatch = "^1.0.6"
protobuf = ">=5.29.6,<6.0.0"                       # Updated to fix CVE-2026-0994
opentelemetry-api = "^1.33.1"
opentelemetry-exporter-otlp-proto-grpc = "^1.33.1"

libtmux = ">=0.46.2"
pygithub = "^2.5.0"
joblib = "*"
gitpython = ">=3.1.49"
python-socketio = "5.14.0"
sse-starlette = "^3.0.2"
psutil = "*"
python-json-logger = ">=3.2.1,<5.0.0"
prompt-toolkit = "^3.0.50"
poetry = ">=2.3.4,<2.4.0"
anyio = "4.9.0"
pythonnet = { version = "*", markers = "sys_platform == 'win32'" }
fastmcp = ">=3.2,<4"
python-frontmatter = "^1.1.0"
shellingham = "^1.5.4"
# TODO: Should these go into the runtime group?
ipywidgets = "^8.1.5"
qtconsole = "^5.6.1"
python-pptx = "*"
pylatexenc = "*"
python-docx = "*"
bashlex = "^0.18"

# Explicitly pinned packages for latest versions
pypdf = "^6.10.2"
pillow = "^12.1.1"
starlette = ">=0.49.1,<1.1.0"
urllib3 = "^2.7.0"
requests = "^2.33.0"
setuptools = ">=78.1.1"

# TODO: These are integrations that should probably be optional
redis = ">=5.2,<7.0"

google-cloud-aiplatform = "*"
anthropic = { extras = [ "vertex" ], version = "*" }
boto3 = "*"
kubernetes = ">=33.1,<36.0"
pyyaml = "^6.0.2"
memory-profiler = "^0.61.0"
jupyter_kernel_gateway = "*"

# Third-party runtime dependencies (optional)
modal = { version = ">=0.66.26,<1.2.0", optional = true }
runloop-api-client = { version = "0.50.0", optional = true }
daytona = { version = "0.24.2", optional = true }
httpx-aiohttp = "^0.1.8"
e2b-code-interpreter = { version = "^2.0.0", optional = true }
pybase62 = "^1.0.0"

# V1 dependencies
openhands-sdk = "==1.23.1"
openhands-agent-server = "==1.23.1"
openhands-tools = "==1.23.1"
joserfc = ">=1.0.0"
sqlalchemy = { extras = [ "asyncio" ], version = "^2.0.40" }
pg8000 = "^1.31.5"
asyncpg = ">=0.30,<0.32"
deprecation = "^2.1.0"
lmnr = "^0.7.20"

[tool.poetry.group.dev]
optional = true

[tool.poetry.group.dev.dependencies]
ruff = "0.12.5"
mypy = "1.17.0"
pre-commit = "4.2.0"
build = "*"
types-setuptools = "*"
pytest = ">=8.4,<10.0"
pytest-asyncio = "^1.3.0"

[tool.poetry.group.test]
optional = true

[tool.poetry.group.test.dependencies]
pytest = "*"
pytest-cov = "*"
pytest-asyncio = "*"
pytest-forked = "*"
pytest-xdist = "*"
pytest-playwright = "^0.7.0"
pytest-timeout = "^2.4.0"
pandas = "*"
reportlab = "*"
gevent = ">=24.2.1,<26.0.0"

[tool.poetry.group.runtime]
optional = true

[tool.poetry.group.runtime.dependencies]
jupyterlab = "*"
notebook = "*"
flake8 = "*"

[tool.poetry-dynamic-versioning]
enable = true
style = "semver"

[tool.autopep8]
# autopep8 fights with mypy on line length issue
ignore = [ "E501" ]

[tool.black]
# prevent black (if installed) from changing single quotes to double quotes
skip-string-normalization = true

[tool.ruff]
exclude = [ "enterprise/" ]
format.quote-style = "single"
lint.select = [
  "ASYNC",
  "B",
  "E",
  "F",
  "I",
  "Q",
  "UP006",
  "UP007",
  "UP008",
  "W",
]
lint.ignore = [
  "ASYNC109",
  "ASYNC110",
  "ASYNC220",
  "ASYNC221",
  "ASYNC230",
  "ASYNC251",
  "B003",
  "B007",
  "B009",
  "B010",
  "B018",
  "B904",
  "E501",
]
lint.flake8-bugbear.extend-immutable-calls = [
  "Depends",
  "fastapi.Depends",
  "fastapi.params.Depends",
]
lint.flake8-quotes.docstring-quotes = "double"
lint.flake8-quotes.inline-quotes = "single"

[tool.coverage.run]
concurrency = [ "gevent" ]
relative_files = true
omit = [ "enterprise/tests/*", "**/test_*" ]
