682 lines
31 KiB
TOML
682 lines
31 KiB
TOML
[build-system]
|
||
requires = ["setuptools>=68.0"]
|
||
build-backend = "setuptools.build_meta"
|
||
|
||
[project]
|
||
name = "omnigent"
|
||
# Keep in sync with omnigent/version.py's VERSION constant.
|
||
version = "0.6.0.dev0"
|
||
description = "Omnigent: declarative agent authoring and runtime framework"
|
||
readme = "README.md"
|
||
requires-python = ">=3.12"
|
||
authors = [
|
||
{ name = "Databricks, Inc." },
|
||
]
|
||
keywords = ["agents", "llm", "ai", "databricks", "cli"]
|
||
classifiers = [
|
||
"Development Status :: 3 - Alpha",
|
||
"Intended Audience :: Developers",
|
||
"License :: OSI Approved :: Apache Software License",
|
||
"Programming Language :: Python :: 3",
|
||
"Programming Language :: Python :: 3.12",
|
||
"Programming Language :: Python :: 3.13",
|
||
]
|
||
dependencies = [
|
||
# SDK path-deps, version-locked: the three packages release together at
|
||
# one version, so a published `omnigent==X` must resolve the SDK wheels
|
||
# built alongside it (release-omnigent.yml verifies these pins match the
|
||
# release tag). Local/editable installs still resolve via tool.uv.sources.
|
||
"omnigent-client==0.6.0.dev0",
|
||
"omnigent-ui-sdk==0.6.0.dev0",
|
||
# Merged from omnigent + omnigent.
|
||
"pyyaml>=6.0,<7",
|
||
"openai>=1.0,<3",
|
||
# >=14: the `e2b` extra's SDK (>=2.26) needs rich>=14 (was >=13,<14).
|
||
"rich>=14,<15",
|
||
"prompt_toolkit>=3.0,<4",
|
||
"mcp>=1.0,<2",
|
||
"starlette>=1.0.1,<2",
|
||
"uvicorn[standard]>=0.30,<1",
|
||
# websockets >=15 asyncio client hangs on macOS before emitting any handshake
|
||
# bytes; pin below 15 until upstream fixes the regression (see issue #1514).
|
||
"websockets>=10.4,<15",
|
||
"httpx>=0.27,<1",
|
||
"ftfy>=6.0",
|
||
# Portable zombie-aware PID liveness checks for the host daemon
|
||
# lifecycle (omnigent/host/local_server.py).
|
||
"psutil>=5.9,<8",
|
||
# CEL (Common Expression Language) for inline policy evaluation.
|
||
# Non-Turing-complete, side-effect-free, guaranteed to terminate.
|
||
# No wheels for Linux aarch64 or macOS x86_64 (Intel); excluded so
|
||
# installation succeeds. The CEL policy module degrades gracefully
|
||
# when the library is absent.
|
||
'cel-expr-python>=0.1; platform_machine != "aarch64" and (sys_platform != "darwin" or platform_machine != "x86_64")',
|
||
# OS keychain for storing model-provider API keys (OSS model
|
||
# selection). Used by omnigent/onboarding/secrets.py; falls back to
|
||
# a 0600 file when no keyring backend is available (e.g. headless).
|
||
"keyring>=24,<26",
|
||
# Round-trip (comment/format-preserving) TOML editing of the user's
|
||
# ~/.codex/config.toml when removing a Databricks provider
|
||
# (omnigent/onboarding/ucode_cleanup.py). stdlib tomllib is read-only.
|
||
"tomlkit>=0.12,<1",
|
||
# omnigent deps (runtime, spec, server, persistent terminal, etc.).
|
||
"alembic>=1.0,<2",
|
||
"anyio>=4.0,<5",
|
||
"cachetools>=5.0,<7",
|
||
# _HostGroup (omnigent/cli.py) rewrites a leading positional server URL
|
||
# into `--server` before Click parses it, so it no longer depends on
|
||
# Click's internal `protected_args` (made read-only in click 8.2, slated
|
||
# for removal in click 9). Upper bound `<10` only guards against an
|
||
# as-yet-unreleased click 10 with unknown breaking changes.
|
||
"click>=8.0,<10",
|
||
"fastapi>=0.100,<1",
|
||
# pexpect/pyte back the POSIX tmux/PTY terminal stack, which is disabled
|
||
# on Windows (no usable PTY); omnigent never imports them on the core
|
||
# path, so skip them there to avoid shipping an unusable dependency.
|
||
"pexpect>=4.9,<5; platform_system != 'Windows'",
|
||
"pyte>=0.8,<1; platform_system != 'Windows'",
|
||
"pydantic>=2.0,<3",
|
||
"sqlalchemy>=2.0,<3",
|
||
# Client-side compression for opaque text columns (omnigent/db/compression.py),
|
||
# so per-conversation JSON/text is stored uniformly compressed across SQLite,
|
||
# PostgreSQL, and MySQL rather than depending on each backend's storage engine.
|
||
"zstandard>=0.22,<1",
|
||
"tiktoken>=0.7,<1",
|
||
"opentelemetry-exporter-otlp-proto-grpc>=1.20,<2",
|
||
"opentelemetry-exporter-otlp-proto-http>=1.20,<2",
|
||
"opentelemetry-instrumentation-fastapi>=0,<1",
|
||
"opentelemetry-instrumentation-httpx>=0,<1",
|
||
"opentelemetry-instrumentation-sqlalchemy>=0,<1",
|
||
# The Claude Code and OpenAI Agents harnesses are part of the
|
||
# baseline install — every CUJ command in the README depends on at
|
||
# least one of them, so making them optional just forces every user
|
||
# to remember `--extra all`. Issue #406.
|
||
"claude-agent-sdk>=0.1.62",
|
||
"openai-agents>=0.0.17",
|
||
"PyJWT[crypto]>=2.8,<3",
|
||
"argon2-cffi>=23.1,<24",
|
||
# PEP 440 version comparison for the update check / `omni upgrade`
|
||
# (omnigent/update_check.py, omnigent/cli.py): compares the installed
|
||
# version against the latest PyPI release. Previously only a
|
||
# transitive dep; pinned here now that we import it directly.
|
||
"packaging>=23,<26",
|
||
]
|
||
|
||
[project.optional-dependencies]
|
||
# Retained as no-op aliases so existing `--extra` invocations keep
|
||
# working; the underlying packages are now default deps above.
|
||
claude-sdk = []
|
||
openai-agents = []
|
||
# `all` additionally carries databricks-sdk: the SDK moved out of the
|
||
# default install (it now lives in the `databricks` extra), but internal
|
||
# CI / dev installs use `--extra all` and the test suite, deploy tooling,
|
||
# and databricks_mcps servers import it.
|
||
all = ["databricks-sdk>=0.56.0,<1"]
|
||
# From omnigent.
|
||
bedrock = ["boto3>=1.30,<2", "botocore>=1.30,<2"]
|
||
# S3-compatible artifact store (AWS S3, Cloudflare R2, MinIO, …). Selected
|
||
# with ``OMNIGENT_ARTIFACT_URI=s3://bucket/prefix``; the store imports boto3
|
||
# lazily, so only users of this backend need the extra.
|
||
s3 = ["boto3>=1.30,<2", "botocore>=1.30,<2"]
|
||
vertex = ["google-auth>=2.0,<3"]
|
||
# Modal sandbox launcher (`omnigent sandbox --provider modal`). The
|
||
# launcher module ships in the base package and imports the SDK lazily,
|
||
# so only users of the provider need this extra.
|
||
modal = ["modal>=1.0,<2"]
|
||
# Daytona sandbox launcher (`omnigent sandbox --provider daytona` and
|
||
# server-managed `sandbox.provider: daytona`).
|
||
# Same lazy-import posture as the modal extra. Pre-1.0 SDK: pin minor.
|
||
daytona = ["daytona>=0.180,<1"]
|
||
# Boxlite sandbox launcher: server-managed `sandbox.provider: boxlite`, either
|
||
# local embedded micro-VMs (KVM/HVF, no daemon) or a remote `boxlite serve`
|
||
# pool. Same lazy-import posture as the modal/daytona extras. Pre-1.0 SDK: pin
|
||
# minor.
|
||
boxlite = ["boxlite>=0.9.5,<1"]
|
||
# CoreWeave Sandbox launcher (`omnigent sandbox --provider cwsandbox` and
|
||
# server-managed `sandbox.provider: cwsandbox`).
|
||
# Same lazy-import posture as above. Pre-1.0 SDK: pin minor.
|
||
cwsandbox = ["cwsandbox>=0.24,<1"]
|
||
# E2B sandbox launcher (`omnigent sandbox --provider e2b` and
|
||
# server-managed `sandbox.provider: e2b`).
|
||
# Same lazy-import posture as above.
|
||
e2b = ["e2b>=2.26,<3"]
|
||
# NVIDIA OpenShell launcher (`omnigent sandbox --provider openshell`).
|
||
# Self-hosted gRPC gateway; the SDK pulls grpcio + protobuf. Same
|
||
# lazy-import posture as above. Pre-1.0 SDK: pin minor.
|
||
openshell = ["openshell>=0.0.7,<1"]
|
||
# On-demand Kubernetes runner Pod launcher (server-managed
|
||
# `sandbox.provider: kubernetes`). The launcher module ships in the base
|
||
# package and imports the official client lazily, so only users of the
|
||
# provider need this extra.
|
||
kubernetes = ["kubernetes>=36,<37"]
|
||
# The tracing extra is now a no-op shim kept for backwards compatibility.
|
||
# Tracing is built on OpenTelemetry directly (opentelemetry-exporter-otlp-*
|
||
# are in the default install). `omnigent[tracing]` still works — it just
|
||
# no longer pulls in the heavy mlflow dependency.
|
||
tracing = []
|
||
agents-sdk = [
|
||
"openai-agents>=0.1,<1",
|
||
"opentelemetry-instrumentation-openai-agents-v2>=0.1",
|
||
]
|
||
# Google Antigravity SDK harness (`harness: antigravity`). Optional: the
|
||
# harness module imports the SDK lazily on first turn, so only users of the
|
||
# harness need this extra. Early SDK (v0.1.x) — pin minor.
|
||
antigravity = ["google-antigravity>=0.1,<1"]
|
||
# GitHub Copilot SDK harness (`harness: copilot`). Optional: the harness module
|
||
# imports the SDK lazily on first turn, so only users of the harness need this
|
||
# extra. The wheel bundles the Copilot CLI binary it drives (~90MB), which is
|
||
# why it is not part of the baseline install. Pin major.
|
||
copilot = ["github-copilot-sdk>=1,<2"]
|
||
# Cursor SDK harness (`harness: cursor`). Optional like antigravity: the
|
||
# harness imports the cursor-sdk lazily on first turn, so only `--harness
|
||
# cursor` users need this extra (`omnigent[cursor]`). Was a baseline dependency;
|
||
# now opt-in to keep the default install lean.
|
||
cursor = ["cursor-sdk>=0.1.7"]
|
||
# Hindsight long-term memory built-in tools (hindsight_retain / _recall /
|
||
# _reflect). The tools import the client lazily, so only users who enable a
|
||
# Hindsight memory tool need this extra.
|
||
memory = ["hindsight-client>=0.4.0"]
|
||
databricks = [
|
||
# Floor matches what core code was tested against when the SDK was a
|
||
# default dependency (it moved here from `dependencies` above).
|
||
"databricks-sdk>=0.56.0,<1",
|
||
"opentelemetry-distro>=0,<1",
|
||
"psycopg[binary]>=3.1,<4",
|
||
"pymysql>=1.1,<2",
|
||
# Databricks-specific MCP servers. Not imported by core Omnigent
|
||
# code, so it is opt-in here rather than a default dependency.
|
||
"databricks-mcp>=0.1.0",
|
||
]
|
||
dev = [
|
||
"pytest>=7.0",
|
||
# hindsight-client is opt-in (the `memory` extra), but the Hindsight
|
||
# memory tool tests import + mock it, so keep it in the dev set.
|
||
"hindsight-client>=0.4.0",
|
||
"pytest-asyncio>=0.21",
|
||
"pytest-xdist>=3.6",
|
||
# Line coverage during the unit-test matrix. Each CI shard writes its
|
||
# own data file; the code-coverage workflow combines them. See
|
||
# `[tool.coverage.run]` below for the relative-files setting that makes
|
||
# cross-runner combine work.
|
||
"pytest-cov>=5",
|
||
"pytest-playwright>=0.7",
|
||
# Visual-regression snapshot plugin for the e2e_ui suite. Provides the
|
||
# `assert_snapshot` fixture + `--update-snapshots` flag the UI diff gate
|
||
# uses (see tests/e2e_ui/visual/ and .github/workflows/ui-snapshot.yml).
|
||
# Requires pytest-playwright>=0.7 (hence the floor bump above).
|
||
"pytest-playwright-visual-snapshot>=0.5.1",
|
||
# Hash-partition the test suite across N shards for the nightly
|
||
# matrix. Pinned to a known-stable older release. Used by e2e.yml;
|
||
# the e2e-ui suite uses its own round-robin `--splits`/`--group`
|
||
# split (see tests/e2e_ui/conftest.py), so no extra dep there.
|
||
"pytest-shard==0.1.2",
|
||
# Per-test wallclock cap. Without this, a single hung test (e.g.
|
||
# a pexpect REPL test waiting for a terminal pattern that never
|
||
# arrives) blocks the whole pytest session until the workflow's
|
||
# step-level timeout-minutes fires, killing the worker without
|
||
# producing a junit XML or per-test traceback. With --timeout=N,
|
||
# pytest-timeout fails the offending test with a clear traceback
|
||
# and lets the rest of the suite continue. Pinned exactly to a
|
||
# known-good release for consistency with pytest-shard above.
|
||
"pytest-timeout==2.4.0",
|
||
# Retry LLM-driven inner tests up to 2 extra times on codex; see
|
||
# ``pytest_collection_modifyitems`` in ``tests/inner/conftest.py``.
|
||
# Pinned exactly to a known-stable release for consistency with
|
||
# pytest-shard / pytest-timeout above. 16.2+ is required under
|
||
# pytest 9: 14.0 predates pytest 9 and corrupts fixture-finalizer
|
||
# state around reruns (stale FixtureDef._finalizers / SetupState
|
||
# surgery, fixed upstream in 16.2), which leaked one test's
|
||
# monkeypatch of ``sessions._get_runner_client`` into later tests
|
||
# on the same xdist worker and flaked the WS-tunnel suite (the
|
||
# "Runner stream relay exited before becoming ready" 503s).
|
||
"pytest-rerunfailures==16.3",
|
||
"filelock>=3.0",
|
||
"ruff>=0.6",
|
||
"mypy>=1.10",
|
||
"pre-commit>=3.5",
|
||
"types-PyYAML>=6.0",
|
||
"filelock>=3.0",
|
||
# gitwildmatch glob matching for repo tooling manifests. Declared
|
||
# explicitly rather than relied on transitively (via mypy).
|
||
"pathspec>=0.12",
|
||
# Cloud-service mocks for the artifact-store / Cloudflare integration
|
||
# tests: moto is the standard S3-compatible mock (used for R2), respx is
|
||
# the standard HTTPX mock (used to back the Cloudflare D1 REST API with an
|
||
# in-memory SQLite), and boto3 backs the S3 artifact store under test.
|
||
"moto[s3]>=5,<6",
|
||
"respx>=0.21,<1",
|
||
"boto3>=1.30,<2",
|
||
# The Cloudflare D1 SQLAlchemy dialect, exercised by the D1 FTS integration
|
||
# test (tests/db/test_d1_fts_dialect.py) via respx + sqlite3.
|
||
"sqlalchemy-cloudflare-d1==0.3.10",
|
||
]
|
||
|
||
[project.scripts]
|
||
# Unified entry point. `omnigent` is the click-based CLI that absorbs
|
||
# the legacy argparse commands from `omnigent/inner/cli.py` plus the
|
||
# omnigent `ap` subcommands. See designs/UNIFICATION.md § CLI
|
||
# absorption. `omni` is installed as a short alias — both resolve to
|
||
# the same entry point. (No former-name aliases: only `omnigent` and
|
||
# `omni` ship, internal and OSS alike.)
|
||
omnigent = "omnigent.cli:main"
|
||
omni = "omnigent.cli:main"
|
||
|
||
# uv path-deps for the sibling SDK packages (renamed in Stage 3).
|
||
[tool.uv.sources]
|
||
omnigent-client = { path = "sdks/python-client", editable = true }
|
||
omnigent-ui-sdk = { path = "sdks/ui", editable = true }
|
||
|
||
[tool.setuptools]
|
||
include-package-data = true
|
||
|
||
[tool.setuptools.packages.find]
|
||
where = ["."]
|
||
# Discovers the `omnigent` package (including `omnigent.inner.*` and
|
||
# all omnigent subpackages absorbed during unification).
|
||
include = ["omnigent*"]
|
||
|
||
[tool.setuptools.package-data]
|
||
"omnigent.db" = ["alembic.ini"]
|
||
"omnigent.db.migrations" = ["script.py.mako"]
|
||
"omnigent.resources.examples" = ["*.yaml", "*.sh", "debby/**/*", "polly/**/*"]
|
||
"omnigent.resources.pi_native" = ["*.js"]
|
||
# include UI assets in build, plus the static API-only landing page served
|
||
# at "/" when no web UI bundle is present
|
||
"omnigent.server" = ["static/web-ui/**/*", "static/api_only_landing.html"]
|
||
|
||
[tool.pytest.ini_options]
|
||
# auto mode: async tests without @pytest.mark.asyncio() are auto-
|
||
# collected as asyncio. Inner (omnigent-legacy) tests rely on
|
||
# this. SDK tests (tests/frontends/sdk/) use explicit markers;
|
||
# both work under auto.
|
||
asyncio_mode = "auto"
|
||
testpaths = ["tests"]
|
||
# tests/e2e, tests/e2e_ui, and tests/e2e_live all require real LLM
|
||
# credentials and/or extra setup (Databricks profile; npm build +
|
||
# Playwright browsers for the UI suite; a deployed Databricks App URL
|
||
# for the live suite). Opt-in via explicit pytest invocation.
|
||
addopts = "--ignore=tests/e2e --ignore=tests/e2e_ui --ignore=tests/e2e_live --ignore=tests/integration"
|
||
# Default per-test wallclock cap. Catches infinite hangs in any
|
||
# suite (unit, inner, integration, e2e) without bothering tests
|
||
# that actually finish. The longest legitimate integration tests
|
||
# are well under 5 min; anything longer than that is almost
|
||
# certainly a hang and should surface a traceback rather than
|
||
# stall the worker. CLI overrides still work: e2e workflows pass
|
||
# a stricter --timeout=180; individual tests can opt out via
|
||
# ``@pytest.mark.timeout(N)``. ``thread`` method is more reliable
|
||
# than the default ``signal`` method when tests fork subprocesses
|
||
# (SIGALRM doesn't reach blocked-on-pty children) — see
|
||
# pytest-timeout README.
|
||
timeout = 300
|
||
timeout_method = "thread"
|
||
# SDK tests under ``tests/frontends/sdk/`` import the
|
||
# ``omnigent_client`` and ``omnigent_ui_sdk`` packages that
|
||
# live in ``sdks/python-client/`` and ``sdks/ui/`` respectively.
|
||
# Without this pythonpath the imports fail at collection time
|
||
# with ``ModuleNotFoundError: No module named 'omnigent_client'``
|
||
# unless the SDKs are installed editable into the venv. Listing
|
||
# both relative paths here keeps the test suite self-contained.
|
||
pythonpath = [".", "sdks/python-client", "sdks/ui"]
|
||
markers = [
|
||
"live: end-to-end tests requiring real LLM API key (run with --llm-api-key)",
|
||
"live_app: end-to-end tests requiring a deployed Databricks App server",
|
||
"databricks: requires the `databricks` extra (psycopg / databricks-sdk). Deselected on the standard lanes via -m 'not databricks'; runs only in the Pytest (databricks) lane, which installs the extra. Use for tests that build a postgresql+psycopg engine or call the Databricks SDK.",
|
||
"model(name, ...): one arg pins this test to that model overriding the suite-wide --model CLI default; multiple args fan the test out across all listed models via indirect parametrize.",
|
||
"model_pinned: opt out of tests/_model_pools.py spreading and retry rotation; literal model strings are used as written.",
|
||
"flaky(reruns=2, reruns_delay=0): rerun a nondeterministic test on failure (pytest-rerunfailures). Use for tests flaky due to timing/scheduling races (e.g. PTY drain timing), NOT real-LLM nondeterminism — those use llm_flaky, which rotates models per attempt.",
|
||
"llm_flaky(reruns=2, reruns_delay=1): rerun a nondeterministic real-LLM test on failure, rotating to a different model each attempt (tests/_model_pools.py). Never apply to heavy e2e tests that can hit the CI --timeout=180 cap (rerun + loadscope can crash the shard).",
|
||
"in_process_sessions: run a server integration test with the legacy in-process sessions path instead of sessions-native runner dispatch.",
|
||
"nightly: runs only in the scheduled/dispatch pass of its suite; PR and push runs exclude it via -m 'not nightly'. Remove the marker to promote a burned-in test to the PR gate.",
|
||
"min_server_version(version): skip this test when the live server under test is older than `version` (PEP 440 release-tuple comparison, so a `.devN` of X satisfies X). Used by the server-version backwards-compat CI (docs/SERVER_VERSION_COMPAT_CI.md); inert in normal runs where the server is current.",
|
||
"min_runner_version(version): skip this test when the pinned runner/host under test is older than `version` (PEP 440 release-tuple comparison, so a `.devN` of X satisfies X). Used by the runner/host backwards-compat CI (Config 2); inert in normal runs (no OMNIGENT_COMPAT_RUNNER_VERSION set).",
|
||
"mock_only: tests/integration test that only works in mock-LLM mode (no --llm-api-key). Skipped by tests/integration/conftest.py when a real --llm-api-key is supplied (the real-LLM Integration jobs). Use for tests whose mock LLM is scripted with a fixed tool-call sequence — a real LLM cannot reproduce the scripted markers.",
|
||
"visual: UI diff visual-regression snapshot (pytest-playwright-visual-snapshot). Runs only in the pinned-runner gate (.github/workflows/ui-snapshot.yml); the main e2e_ui suite excludes it via -m 'not visual' since it runs on the unpinned ubuntu-latest.",
|
||
"posix_only: test relies on POSIX-only behaviour (fork, PTY, tmux, Unix sockets, signals); auto-skipped on Windows by tests/conftest.py.",
|
||
"windows_only: test relies on Windows-only behaviour (Job Objects, cmd.exe); auto-skipped on POSIX by tests/conftest.py.",
|
||
]
|
||
# Visual snapshot baselines are committed here, keyed per-OS by the plugin
|
||
# (e.g. test_empty_landing_matches_baseline[linux].png). Failure artifacts
|
||
# (actual/expected/diff PNGs) land in the gitignored sibling dir. Both are
|
||
# relative to the repo root, which is where pytest is always invoked.
|
||
playwright_visual_snapshots_path = "tests/e2e_ui/visual/snapshots"
|
||
playwright_visual_snapshot_failures_path = "tests/e2e_ui/visual/snapshot_failures"
|
||
|
||
[tool.coverage.run]
|
||
# Measure the shipped package only; tests live under tests/.
|
||
source = ["omnigent"]
|
||
# Each CI shard sets COVERAGE_FILE=artifacts/.coverage.<group> and writes
|
||
# one data file (pytest-cov already combines the xdist workers within a
|
||
# shard). `relative_files` stores paths relative to the repo root so the
|
||
# code-coverage workflow can `coverage combine` data files produced on
|
||
# separate sharded runners with differing absolute checkout paths.
|
||
relative_files = true
|
||
|
||
[tool.coverage.report]
|
||
show_missing = true
|
||
# Report-only for now: no `fail_under`, so coverage never fails a build.
|
||
# The code-coverage workflow reports against a plain `git checkout` that
|
||
# has no generated files (e.g. omnigent/_build_info.py, written during
|
||
# `uv sync` in the CI shards). Without this, `coverage report`/`xml` exit
|
||
# 1 on "No source for code" and fail the step under `set -e`; ignore those
|
||
# unreadable-source files instead.
|
||
ignore_errors = true
|
||
|
||
[tool.ruff]
|
||
line-length = 99
|
||
# NOTE: kept at py310 even though requires-python is >=3.12. Bumping this to
|
||
# py312 makes ruff's UP041 rewrite `asyncio.TimeoutError` -> `TimeoutError`
|
||
# (aliased since 3.11) across the whole codebase — a separate, out-of-scope
|
||
# migration that belongs in its own cleanup PR.
|
||
target-version = "py310"
|
||
# Vendored upstream code — not ours to restyle.
|
||
# - ``omnigent/inner/databricks_mcps/google``: Google MCP server source.
|
||
# - ``assistant-ui/``: assistant-ui.com React/Python suite imported as a
|
||
# vendored snapshot; tracked upstream, no in-tree edits.
|
||
extend-exclude = [
|
||
"omnigent/inner/databricks_mcps/google",
|
||
"assistant-ui",
|
||
]
|
||
|
||
[tool.ruff.lint]
|
||
# ``E``/``F`` — pycodestyle + pyflakes baseline
|
||
# ``I`` — import sorting
|
||
# ``UP`` — pyupgrade (modernize syntax)
|
||
# ``ARG`` — unused function arguments
|
||
# ``BLE`` — blind ``except Exception``
|
||
# ``B`` — flake8-bugbear (latent bugs, e.g. mutable defaults,
|
||
# unbound loop variables in closures, raise-from)
|
||
# ``SIM`` — flake8-simplify (reduce unnecessary complexity)
|
||
# ``RET`` — flake8-return (consistent return statements)
|
||
# ``C4`` — flake8-comprehensions (cleaner list/dict/set comprehensions)
|
||
# ``PIE`` — flake8-pie (misc correctness + style)
|
||
# ``RUF`` — ruff-specific (sorted ``__all__``, dangling asyncio
|
||
# tasks, unused noqa, ...)
|
||
select = ["E", "F", "I", "UP", "ARG", "BLE", "B", "SIM", "RET", "C4", "PIE", "RUF"]
|
||
ignore = [
|
||
# ARG003 (unused class-method args): too noisy on ABC-subclass signatures
|
||
# where the arg is required by the interface contract.
|
||
"ARG003",
|
||
# RUF001/002/003 ambiguous-unicode: the repo uses ``—`` / ``–`` / ``×`` /
|
||
# ``╱`` in docstrings and CLI UI strings intentionally. The rule was
|
||
# designed for source strings that could be confused with ASCII and
|
||
# throws off on legitimate typographic characters in prose.
|
||
"RUF001",
|
||
"RUF002",
|
||
"RUF003",
|
||
# SIM102/103/108: style-only transforms (collapse nested if / return
|
||
# condition directly / rewrite if-else as ternary). Often make code
|
||
# harder to read when the conditions are non-trivial. Kept available
|
||
# as manual refactoring hints but not enforced.
|
||
"SIM102",
|
||
"SIM103",
|
||
"SIM108",
|
||
]
|
||
|
||
[tool.ruff.lint.isort]
|
||
# Classify first-party imports by NAME, not by file existence. Ruff's
|
||
# default detection resolves each module against the filesystem, so an
|
||
# import of an optional submodule absent from a given checkout (e.g.
|
||
# omnigent.onboarding.internal_beta) would be reclassified as third-party
|
||
# there, demanding a different import order per checkout. Pinning the
|
||
# package name keeps one canonical order everywhere.
|
||
known-first-party = ["omnigent"]
|
||
|
||
[tool.ruff.lint.per-file-ignores]
|
||
# Tests legitimately accept parameters they don't use (pytest fixtures,
|
||
# mock callback signatures) and intercept broad exceptions to assert on
|
||
# error paths. Cleaning these up is a separate cleanup pass.
|
||
#
|
||
# RUF012 (mutable default class attribute): test fake classes and
|
||
# Textual/pytest harnesses routinely declare class-level
|
||
# ``BINDINGS = [...]`` / ``inputSchema: dict = {...}`` that are never
|
||
# mutated — the rule's production-shared-state concern doesn't apply.
|
||
#
|
||
# B007 (loop var unused): occasional ``for i, x in enumerate(...)`` in
|
||
# tests where only ``x`` matters; style not worth policing.
|
||
#
|
||
# B008 (function call in default): pytest / factory_boy idioms.
|
||
#
|
||
# SIM117 (combined with): already-legible nested ``with`` in test
|
||
# fixtures that would be harder to read if merged.
|
||
"tests/**/*.py" = [
|
||
"ARG001", "ARG002", "ARG004", "ARG005", "BLE001",
|
||
"RUF012", "B007", "B008", "SIM117",
|
||
]
|
||
# Example scripts predate the rule and are exempted until they graduate.
|
||
"tests/resources/examples/**/*.py" = [
|
||
"ARG001", "ARG002", "ARG004", "ARG005", "BLE001",
|
||
"RUF012", "B007", "B008", "SIM117",
|
||
]
|
||
# Graduation backlog for code migrated from omnigent during the
|
||
# unification. Pre-unification Omnigent' ruff config only selected
|
||
# ``E, F, I, UP`` — none of the ARG/BLE/B/SIM/... rules — so these
|
||
# files have a backlog of unused-arg, blind-except, and bugbear issues
|
||
# that were invisible before. Graduate each subpath out of this list
|
||
# as it's cleaned up.
|
||
"omnigent/llms/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
"omnigent/onboarding/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
"omnigent/runtime/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
"omnigent/terminals/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
"omnigent/tools/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
# The native Antigravity (agy) transcript forwarder / supervisor is a
|
||
# long-lived boundary loop that must restart on ANY non-cancellation
|
||
# Exception (a crash there silently stops the web transcript mirror), so its
|
||
# top-level catch is a deliberate, documented boundary catch — BLE001 is
|
||
# waived for these top-level antigravity_native modules (see the inline
|
||
# comments at each catch site).
|
||
"omnigent/antigravity_native*.py" = ["BLE001"]
|
||
"sdks/**/*.py" = [
|
||
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
|
||
]
|
||
|
||
[tool.mypy]
|
||
python_version = "3.12"
|
||
strict = true
|
||
# Ban explicit `Any` in annotations. `Any` defeats static typing; prefer
|
||
# real types, Protocols, TypedDicts, or `object` with runtime checks. When
|
||
# a genuine boundary needs it (opaque JSON shapes, foreign SDKs) annotate
|
||
# with `# type: ignore[explicit-any]` *and a comment explaining why*.
|
||
disallow_any_explicit = true
|
||
# Vendored Google MCP server code — upstream code, not ours to type.
|
||
# setup.py — build-time scaffolding that imports the (untyped) setuptools
|
||
# build_py and subclasses it; not application code, so excluded from mypy
|
||
# rather than pulling in types-setuptools just for one shim file.
|
||
exclude = ["^omnigent/inner/databricks_mcps/google/", "^setup\\.py$"]
|
||
# Incremental rollout: load imported modules for type info but don't
|
||
# report their errors. Remove once every omnigent/ module is clean.
|
||
follow_imports = "silent"
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "mcp.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "databricks.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "databricks_mcp.*"
|
||
ignore_missing_imports = true
|
||
|
||
# psycopg is an optional dep (only declared in the ``databricks``
|
||
# extra, used by ``deploy/databricks/grant_sp_perms.py``). Previously installed
|
||
# transitively via ``dbos``; after the DBOS removal, ``uv sync
|
||
# --extra dev`` no longer pulls it, so the lint workflow can't
|
||
# import it. Treat the missing module as silent — runtime use still
|
||
# requires installing the ``databricks`` extra.
|
||
[[tool.mypy.overrides]]
|
||
module = "psycopg.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "openai.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "claude_agent_sdk.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "agents.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "ftfy"
|
||
ignore_missing_imports = true
|
||
|
||
# modal is an optional dep (the `modal` extra); the sandbox launcher
|
||
# imports it lazily so the base install never needs it.
|
||
[[tool.mypy.overrides]]
|
||
module = "modal.*"
|
||
ignore_missing_imports = true
|
||
|
||
# daytona is an optional dep (the `daytona` extra); same lazy-import
|
||
# posture as modal above.
|
||
[[tool.mypy.overrides]]
|
||
module = "daytona.*"
|
||
ignore_missing_imports = true
|
||
|
||
# hindsight-client is an optional dep (the `memory` extra); the memory
|
||
# built-in tools import it lazily so the base install never needs it.
|
||
[[tool.mypy.overrides]]
|
||
module = "hindsight_client.*"
|
||
ignore_missing_imports = true
|
||
|
||
# cwsandbox is an optional dep (the `cwsandbox` extra); same lazy-import
|
||
# posture as modal above.
|
||
[[tool.mypy.overrides]]
|
||
module = "cwsandbox.*"
|
||
ignore_missing_imports = true
|
||
|
||
# e2b is an optional dep (the `e2b` extra); same lazy-import posture as
|
||
# modal above.
|
||
[[tool.mypy.overrides]]
|
||
module = "e2b.*"
|
||
ignore_missing_imports = true
|
||
|
||
# openshell is an optional dep (the `openshell` extra); same lazy-import
|
||
# posture as modal above. grpc rides in via the openshell SDK and is not
|
||
# a base dependency, so its imports are unresolved in the default env too.
|
||
[[tool.mypy.overrides]]
|
||
module = "openshell.*"
|
||
ignore_missing_imports = true
|
||
|
||
# boxlite is an optional dep (the `boxlite` extra); same lazy-import posture
|
||
# as modal above.
|
||
[[tool.mypy.overrides]]
|
||
module = "boxlite.*"
|
||
ignore_missing_imports = true
|
||
|
||
# kubernetes is an optional dep (the `kubernetes` extra); same lazy-import
|
||
# posture as modal above. urllib3 rides in via the kubernetes client.
|
||
[[tool.mypy.overrides]]
|
||
module = "kubernetes.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "grpc.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "prompt_toolkit.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "yaml"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "pexpect"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "cachetools"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "httpx"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "boto3"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "botocore.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "google.*"
|
||
ignore_missing_imports = true
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "opentelemetry.instrumentation.*"
|
||
ignore_missing_imports = true
|
||
|
||
# The Modal deploy glue (deploy/modal/modal_app.py) decorates with the
|
||
# optional `modal` extra, which the lint env doesn't install — under the
|
||
# modal.* ignore-missing-imports override above its decorators type as
|
||
# Any and trip disallow_untyped_decorators. Relax just that flag.
|
||
[[tool.mypy.overrides]]
|
||
module = "modal_app"
|
||
disallow_untyped_decorators = false
|
||
|
||
# omnigent-derived repl code has its own relaxed typing config.
|
||
[[tool.mypy.overrides]]
|
||
module = "omnigent.repl.*"
|
||
disallow_untyped_defs = false
|
||
disallow_untyped_decorators = false
|
||
warn_return_any = false
|
||
check_untyped_defs = false
|
||
|
||
# omnigent-derived code that pre-unification omnigent never
|
||
# subjected to ``disallow_any_explicit`` (its pyproject.toml didn't
|
||
# set that flag). Keep the rest of strict mypy on — just relax the
|
||
# explicit-Any ban until these modules can be graduated.
|
||
[[tool.mypy.overrides]]
|
||
module = [
|
||
"omnigent.runtime.*",
|
||
"omnigent.server.*",
|
||
"omnigent.tools.*",
|
||
"omnigent.entities.*",
|
||
"omnigent.stores.*",
|
||
"omnigent.db.*",
|
||
"omnigent.llms.*",
|
||
"omnigent.onboarding.*",
|
||
"omnigent.terminals.*",
|
||
"omnigent.client_tools.*",
|
||
"omnigent.spec.omnigent",
|
||
"omnigent.spec._omnigent_compat",
|
||
"dump_openapi",
|
||
]
|
||
disallow_any_explicit = false
|
||
|
||
[[tool.mypy.overrides]]
|
||
module = "omnigent_ui_sdk.*"
|
||
ignore_missing_imports = true
|
||
follow_imports = "skip"
|
||
|
||
# SDK shim aliases — ignore their own import resolution issues. These
|
||
# are re-exports of omnigent_client/omnigent_ui_sdk (post-Stage-3)
|
||
# via sys.modules aliasing.
|
||
[[tool.mypy.overrides]]
|
||
module = "omnigent_client.*"
|
||
ignore_missing_imports = true
|
||
disallow_any_explicit = false
|
||
|
||
# Tests in the mypy allowlist predate the stricter omnigent
|
||
# Any rule.
|
||
[[tool.mypy.overrides]]
|
||
module = "tests.*"
|
||
disallow_any_explicit = false
|