[project]
name = "pydantic-deep"
version = "0.3.42"
description = "Batteries-included agent harness for Python — tool-calling, sandboxed execution, multi-agent teams, and unlimited context on Pydantic AI"
readme = "README.md"
keywords = [
    "ai-agent",
    "autonomous-agent",
    "deep-agent",
    "pydantic-ai",
    "llm",
    "agent-framework",
    "multi-agent",
    "tool-calling",
    "claude",
    "openai",
    "mcp",
    "agentic",
    "subagents",
    "cli",
    "terminal-assistant",
]
license = "MIT"
requires-python = ">=3.10"
authors = [
    { name = "Pydantic Deep Contributors" }
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Operating System :: OS Independent",
    "Programming Language :: Python",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
    "Topic :: Software Development :: Libraries :: Python Modules",
    "Typing :: Typed",
]
dependencies = [
    "pydantic-ai-slim[web-fetch]>=2.0.0",
    "pydantic-ai-todo>=0.2.7",
    "pydantic-ai-backend[console]>=0.2.18",
    "summarization-pydantic-ai>=0.1.11",
    "subagents-pydantic-ai>=0.2.12",
    "pydantic-ai-shields>=0.3.4",
    "pydantic>=2.0",
    "chardet>=5.0.0",
]

[project.optional-dependencies]
# Docker sandbox support
sandbox = ["pydantic-ai-backend[docker]>=0.2.18"]
# YAML support for skills (pyyaml-based frontmatter parsing)
yaml = ["pyyaml>=6.0"]
# CLI tools + TUI (terminal assistant)
cli = [
    "textual>=3.0.0",
    "typer>=0.12.0",
    "rich>=13.0.0",
    "prompt-toolkit>=3.0.0",
    "tomli>=2.0; python_version < '3.11'",
    "python-dotenv>=1.0.0",
    "pydantic-ai-slim[anthropic,openai,openrouter,web-fetch,duckduckgo]>=2.0.0",
    # Enables read_file image downscaling (backend resizes oversized images);
    # a graceful no-op in the backend when absent.
    "pillow>=10.0.0",
]
# TUI (Textual-based terminal UI)
tui = [
    "textual>=3.0.0",
    "typer>=0.12.0",
    "rich>=13.0.0",
    "tomli>=2.0; python_version < '3.11'",
    "python-dotenv>=1.0.0",
    "pydantic-ai-slim[anthropic,openai,openrouter,web-fetch,duckduckgo]>=2.0.0",
]
# Web server support (for full_app example)
web = [
    "fastapi>=0.125.0",
    "uvicorn>=0.38.0",
    "python-multipart>=0.0.21",
]
# Browser automation support via Playwright
browser = [
    "playwright>=1.40.0",
    "html2text>=2020.1",
]
# MCP (Model Context Protocol) client support — connect to MCP servers.
# py-key-value-aio[disk] persists OAuth tokens (e.g. hosted Figma) across runs.
mcp = ["pydantic-ai-slim[mcp]>=2.0.0", "py-key-value-aio[disk]>=0.4.5"]
# Document parsing via LiteParse (requires Node.js >= 18).
# Upper bound: 2.x dropped the async API (parse_async/screenshot_async) the toolset uses.
liteparse = ["liteparse>=1.1.0,<2.0.0"]
# ACP (Agent Client Protocol) support for editor integration
acp = ["agent-client-protocol>=0.8.0"]
# Logfire tracing support
logfire = ["logfire>=4.0"]
# Google models (Gemini) via both the Developer API (google-gla) and Vertex AI
# (google-vertex). Both providers are backed by the same google-genai SDK.
google = ["pydantic-ai-slim[google]>=2.0.0"]
# All optional dependencies
all = [
    "pydantic-deep[sandbox,cli,web,yaml,acp,logfire,browser,liteparse,mcp,google]",
]

[project.urls]
Homepage = "https://github.com/vstorm-co/pydantic-deepagents"
Documentation = "https://github.com/vstorm-co/pydantic-deepagents"
Repository = "https://github.com/vstorm-co/pydantic-deepagents"
Issues = "https://github.com/vstorm-co/pydantic-deepagents/issues"

[project.scripts]
pydantic-deep = "apps.cli.main:app"

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


[tool.hatch.build.targets.wheel]
packages = ["pydantic_deep", "apps"]

# Dependency groups for development
[dependency-groups]
dev = [
    "pydantic-deep[all]",
    "pytest>=9.0.0",
    "pytest-asyncio>=0.23.0",
    "coverage>=7.0.0",
    "build>=1.3.0",
    "twine>=6.2.0",
    "pre-commit>=4.5.1",
    "griffe>=1.15.0",
]
lint = [
    # Capped below 0.16: that release started formatting code blocks inside
    # Markdown, which reformats 49 docs/skill files the repo never linted.
    # Lift the cap in a dedicated commit that reformats them.
    "ruff>=0.8.0,<0.16",
    "pyright>=1.1.0",
    "mypy>=1.0.0",
    "bandit>=1.8.0",
    "types-PyYAML>=6.0",
]
docs = [
    "mkdocs>=1.6.0",
    "mkdocs-material>=9.5.0",
    "mkdocstrings>=0.26.0",
    "mkdocstrings-python>=1.12.0",
    "mkdocs-llmstxt>=0.5.0",
]

# Ruff configuration
[tool.ruff]
line-length = 100
target-version = "py310"
exclude = ["notes", "playground"]

[tool.ruff.lint]
select = [
    "E",      # pycodestyle errors
    "F",      # Pyflakes
    "I",      # isort
    "UP",     # pyupgrade
    "B",      # flake8-bugbear
    "SIM",    # flake8-simplify
    "Q",      # flake8-quotes
    "RUF100", # unused noqa
    "C90",    # mccabe complexity
]

[tool.ruff.lint.per-file-ignores]
# Prompt strings contain long lines that shouldn't be wrapped
"apps/deepresearch/src/deepresearch/prompts.py" = ["E501"]
"apps/deepresearch/src/deepresearch/agent.py" = ["E501"]
"examples/full_app/app.py" = ["E501"]

[tool.ruff.lint.mccabe]
max-complexity = 15

[tool.ruff.format]
quote-style = "double"

# Pytest configuration
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
asyncio_default_fixture_loop_scope = "function"

# Coverage configuration
[tool.coverage.run]
branch = true
source = ["pydantic_deep"]
data_file = ".coverage/.coverage"

[tool.coverage.report]
fail_under = 100
skip_covered = true
show_missing = true
precision = 2
exclude_also = [
    "# pragma: no branch",
]
exclude_lines = [
    "pragma: no cover",
    "pragma: lax no cover",
    "if TYPE_CHECKING:",
    "@overload",
    "@abstractmethod",
    "raise NotImplementedError",
    "if __name__ == '__main__':",
    "except ImportError:",
    "pass",
    "\\.\\.\\.",
]

[tool.coverage.html]
directory = "htmlcov"

# Pyright configuration
[tool.pyright]
pythonVersion = "3.10"
typeCheckingMode = "basic"  # Use basic mode for pragmatic type checking
include = ["pydantic_deep"]
exclude = ["**/__pycache__", ".venv*", "site", "playground", "tests", "examples"]
reportMissingTypeStubs = false
reportUnknownMemberType = false
reportUnknownArgumentType = false
reportUnknownVariableType = false
reportUnknownParameterType = false
reportUnusedFunction = false  # Decorators register functions
reportPrivateUsage = false  # Internal usage is intentional
reportOptionalMemberAccess = false  # Docker SDK typing issues
reportCallIssue = false  # TypedDict constructor calls
reportAssignmentType = false  # Dynamic dict building
reportTypedDictNotRequiredAccess = false  # NotRequired keys with get()

# MyPy configuration
[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false
disable_error_code = ["arg-type", "list-item", "abstract"]

# Codespell configuration
[tool.codespell]
skip = ".git,.venv*,uv.lock,site,htmlcov,.coverage"
