[project] name = "cai-framework" version = "1.1.5" description = "Cybersecurity AI Framework" readme = "README.md" requires-python = ">=3.10" license = {text = "Dual-licensed MIT and Proprietary"} authors = [{ name = "Alias Robotics", email = "research@aliasrobotics.com" }] dependencies = [ # --- Core (always needed) --- "openai>=1.75.0", "httpx>=0.27", # Direct HTTP for alias models [N] "pydantic>=2.10, <3", "typing-extensions>=4.12.2, <5", "rich", "prompt_toolkit>=3.0.39", "questionary>=2.0.1", "python-dotenv>=0.19.0", "pytz>=2024.1", # DataRecorder timestamps (run_to_jsonl); not always transitive "PyYAML", "wasabi>=1.1.3", "tiktoken>=0.5", # Token counting "mako>=1.3.8", # Prompt templates "griffe>=1.5.6, <2", # Function schema generation # --- LLM routing (still needed for non-alias models + proxy) --- "litellm[proxy]>=1.80.5", # --- TUI --- "textual>=0.86.0", # --- Networking & Tools --- "requests>=2.0, <3", "paramiko>=3.5.1", # SSH "docker", # Container management "cryptography>=42, <44", # --- Web fetch tool (fetch_url) --- "trafilatura>=2.0", # HTML -> Markdown main-content extraction "curl-cffi>=0.7", # Anti-bot fallback (Chrome TLS fingerprint) "pypdf>=4.0", # PDF text extraction (BSD-licensed successor of PyPDF2) # --- API server --- "uvicorn<=1", "fastapi>=0.115.5, <1", # --- Misc (used in specific modules) --- "mcp", # Model Context Protocol "nest_asyncio", # Async compat in sync contexts ] classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", "License :: OSI Approved :: MIT License", ] [project.urls] Homepage = "https://github.com/aliasrobotics/cai" Repository = "https://github.com/aliasrobotics/cai" Documentation = "https://aliasrobotics.github.io/cai/" Issues = "https://github.com/aliasrobotics/cai/issues" Research = "https://cybersecurityrobotics.com/research/cai-bug-bounty-cybersecurity-ai/" [project.optional-dependencies] voice = ["numpy>=2.2.0", "websockets>=15.0"] viz = ["graphviz>=0.17", "matplotlib>=3.0,<4", "networkx", "folium>=0.15.0,<1"] data = ["numpy>=1.21,<3", "pandas>=1.3,<3", "scipy"] # CTR graph canvas in the TUI needs networkx; full CTR solver needs numpy/scipy (see data/viz). tui = ["networkx", "numpy>=1.21,<3", "scipy"] docs = ["mkdocs>=1.6.0", "mkdocs-material>=9.6.0"] mail = ["dnspython"] pdf = ["PyPDF2"] web = ["flask"] telemetry = ["openinference-instrumentation-openai>=0.1.22"] test = [ "pytest", "pytest-asyncio", "pytest-mock>=3.14.0", "pytest-timeout", "inline-snapshot>=0.20.7", "graphviz>=0.17", ] all = [ "cai-framework[viz,data,tui,docs,mail,pdf,web,telemetry,test]", ] [dependency-groups] dev = [ "mypy", "ruff==0.9.2", "pytest", "pytest-asyncio", "pytest-mock>=3.14.0", "rich", "mkdocs>=1.6.0", "mkdocs-material>=9.6.0", "mkdocstrings[python]>=0.28.0", "coverage>=7.6.12", "playwright==1.50.0", "inline-snapshot>=0.20.7", "pynput", "types-pynput", "sounddevice", "textual", "websockets", "litellm>=1.63.7", "prisma", "graphviz", "nest_asyncio" ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build] exclude = [ ".trunk/", ".git/", ".vscode/", ".devcontainer/", ".mypy_cache/", ".pytest_cache/", ".ruff_cache/", "venv/", ".venv/", "dist/", "build/", "*.egg-info/", "workspaces/", "benchmarks/", "src/cai/caibench/", "logs/", "site/", ".cai/", "nohup.out", "ci/", "tools/cut_the_rope/", "private/", "data/", "tools/license_check.py", "tools/create_root_user.sh", "media/", "docs/media/", "docs" ] [tool.hatch.build.targets.wheel] packages = ["src/cai", "tools"] exclude = [ ".trunk/", ".git/", ".vscode/", ".devcontainer/", ".mypy_cache/", ".pytest_cache/", ".ruff_cache/", "venv/", ".venv/", "dist/", "build/", "*.egg-info/", "workspaces/", "benchmarks/", "logs/", "site/", ".cai/", "nohup.out", "ci/", "tools/cut_the_rope/", "private/", "data/", "tools/license_check.py", "tools/create_root_user.sh", "media/", "docs/media/", "docs" ] # Explicitly include pricing data files artifacts = [ "src/cai/pricings/*.json" ] [tool.hatch.build.targets.wheel.sources] "src" = "" # Note: tools/cut_the_rope is excluded in the exclude list above "tools" = "tools" [tool.hatch.build.targets.sdist] exclude = [ ".trunk/", ".git/", ".vscode/", ".devcontainer/", ".mypy_cache/", ".pytest_cache/", ".ruff_cache/", "venv/", ".venv/", "dist/", "build/", "*.egg-info/", "workspaces/", "benchmarks/", "logs/", "site/", ".cai/", "nohup.out", "ci/", "tools/cut_the_rope/", "private/", "data/", "tools/license_check.py", "tools/create_root_user.sh", "media/", "docs/media/", "docs" ] [tool.ruff] line-length = 100 target-version = "py39" [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade ] isort = { combine-as-imports = true, known-first-party = ["agents"] } [tool.ruff.lint.pydocstyle] convention = "google" [tool.ruff.lint.per-file-ignores] "examples/**/*.py" = ["E501"] [tool.mypy] strict = true disallow_incomplete_defs = false disallow_untyped_defs = false disallow_untyped_calls = false [[tool.mypy.overrides]] module = "sounddevice.*" ignore_missing_imports = true [tool.coverage.run] source = ["tests", "src/cai/sdk/agents"] [tool.coverage.report] show_missing = true sort = "-Cover" exclude_also = [ # This is only executed while typechecking "if TYPE_CHECKING:", "@abc.abstractmethod", "raise NotImplementedError", "logger.debug", ] [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "session" filterwarnings = [ # This is a warning that is expected to happen: we have an async filter that raises an exception "ignore:coroutine 'test_async_input_filter_fails..invalid_input_filter' was never awaited:RuntimeWarning", ] markers = [ "allow_call_model_methods: mark test as allowing calls to real model implementations", "slow: heavier imports (e.g. full agent graph); exclude with pytest -m \"not slow\" in fast slices", ] [tool.inline-snapshot] format-command = "ruff format --stdin-filename {filename}" [project.scripts] cai = "cai.cli:main" cai-replay = "tools.replay:main" cai-asciinema = "tools.asciinema:main" cai-gif = "tools.gif:main" cai-bench = "cai.caibench.cli:main" cai-ctr = "tools.ctr_experiment:main"