[build-system] requires = ['hatchling', 'uv-dynamic-versioning>=0.7.0'] build-backend = 'hatchling.build' [project] name = 'pydantic-ai-harness' dynamic = ['version'] description = 'The batteries for your Pydantic AI agent' readme = 'README.md' requires-python = '>=3.10' license = 'MIT' authors = [ { name = 'Douwe Maan', email = 'douwe@pydantic.dev' }, { name = 'David SF', email = 'david.sanchez@pydantic.dev' }, { name = 'Aditya Vardhan', email = 'aditya@pydantic.dev' }, ] classifiers = [ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: 3.14', 'Topic :: Software Development :: Libraries', 'Typing :: Typed', ] dependencies = [ "httpx>=0.28.1", "pydantic-ai-slim>=2.1.0", ] [project.optional-dependencies] code-mode = [ 'pydantic-monty>=0.0.16', ] # Extras metadata has no native redirect syntax, so aliases are represented as duplicate extras. codemode = [ 'pydantic-monty>=0.0.16', ] temporal = [ 'pydantic-ai-slim[temporal]', ] dbos = [ 'pydantic-ai-slim[dbos]', ] logfire = [ 'logfire>=4.31.0', "pydantic-ai-slim[spec]>=2.1.0", ] dynamic-workflow = [ "pydantic-monty>=0.0.16", ] acp = [ # The SDK breaks across minors, so cap per minor. "agent-client-protocol>=0.11,<0.12", ] [project.urls] Homepage = 'https://github.com/pydantic/pydantic-ai-harness' Source = 'https://github.com/pydantic/pydantic-ai-harness' Issues = 'https://github.com/pydantic/pydantic-ai-harness/issues' [dependency-groups] dev = [ 'pydantic-ai-harness[code-mode]', # Floors selected to keep the `test-floor` job (using `--resolution lowest-direct`) # working: `anyio>=4.11.0` is when the pytest plugin started registering the # `anyio_mode` ini option. `pytest-anyio` has only version 0.0.0 on PyPI, so no # floor. The rest match pydantic-ai's discipline. 'pytest>=9.0.0', 'anyio[trio]>=4.11.0', 'pytest-anyio', 'coverage>=7.10.7', 'logfire[httpx]>=4.31.0', 'dirty-equals>=0.9.0', 'inline-snapshot>=0.32.5', 'pydantic-ai-slim[spec]>=2.1.0', "pytest-examples>=0.0.18", "pytest-recording>=0.13.4", ] lint = [ 'ruff>=0.14', 'pyright>=1.1.408', ] [tool.hatch.version] source = 'uv-dynamic-versioning' [tool.uv-dynamic-versioning] vcs = 'git' style = 'pep440' bump = true [tool.hatch.build.targets.wheel] packages = ['pydantic_ai_harness'] [tool.ruff] line-length = 120 target-version = 'py310' exclude = ['template'] [tool.ruff.lint] extend-select = ['Q', 'RUF100', 'C90', 'UP', 'I', 'D', 'TID251'] [tool.ruff.lint.per-file-ignores] 'tests/**/*.py' = ['D'] [tool.ruff.lint.flake8-quotes] inline-quotes = 'single' [tool.ruff.lint.mccabe] max-complexity = 15 [tool.ruff.lint.pydocstyle] convention = 'google' [tool.ruff.format] # don't format python in docstrings, pytest-examples takes care of it docstring-code-format = false quote-style = 'single' [tool.pyright] pythonVersion = '3.10' typeCheckingMode = 'strict' exclude = ['template', '.venv', 'mutants'] # `reportUnusedFunction` is disabled for tests because fixtures and `@agent.tool_plain` # helpers are registered via decorators and never referenced by name (matches pydantic-ai). executionEnvironments = [ { root = 'tests', reportPrivateUsage = false, reportUnusedFunction = false }, ] [tool.pytest.ini_options] testpaths = ['tests'] xfail_strict = true filterwarnings = [ 'error', # DBOS's run_sync triggers this on Python 3.12+ — not our code. 'ignore:There is no current event loop:DeprecationWarning', # Experimental capabilities warn on import by design; assert it explicitly where it matters. 'ignore::pydantic_ai_harness.experimental.HarnessExperimentalWarning', ] anyio_mode = 'auto' [tool.coverage.run] branch = true source = ['pydantic_ai_harness', 'tests'] [tool.coverage.paths] source = ['.', '/home/runner/work/pydantic-ai-harness/pydantic-ai-harness'] [tool.coverage.report] fail_under = 100 show_missing = true exclude_lines = [ 'pragma: no cover', 'pragma: lax no cover', 'assert_never', 'if TYPE_CHECKING:', ] [tool.mutmut] paths_to_mutate = [ 'pydantic_ai_harness/filesystem/_toolset.py', 'pydantic_ai_harness/shell/_toolset.py', ] tests_dir = ['tests/filesystem/', 'tests/shell/'] also_copy = ['pydantic_ai_harness/', 'tests/'] # Skip trio-parametrized tests during mutation testing — trio segfaults in # mutmut's subprocess environment on Python 3.14 (not a code bug). pytest_add_cli_args = ['-k', 'not trio'] # See docs/mutation-testing.md for full results (89.7% kill rate, 60 equivalent mutants).