pyproject.toml
Rama main · réplica de lectura del repositorio original.
[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.22.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.22.0.dev0",
"omnigent-ui-sdk==0.22.0.dev0",
# Merged from omnigent + omnigent.
"pyyaml>=6.0,<7",
# OpenClaw stores its wrapped acpx registry as JSON5.
"json5>=0.10,<1",
# openai-agents<0.18.2 omits a field required by openai>=2.45.
# Keep this cap until the websockets<15 compatibility pin can be lifted.
"openai>=1.0,<2.45",
# >=14: the `e2b` extra's SDK (>=2.26) needs rich>=14 (was >=13,<14).
"rich>=14,<16",
"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.
# NOT pure-Python: cel-python hard-depends on google-re2 (a C++ extension,
# imported at celpy module scope with no fallback), whose sdist needs bazel.
# Packagers must pin its prebuilt wheel — see WHEEL_PACKAGES in
# .github/scripts/homebrew/generate_formula.py.
"cel-python>=0.5",
# 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",
# Decode and validate public branding assets before serving them.
# uv.lock pins 13.0.0 for its security fixes; the floor stays at 12.2 so
# installs behind a package-age cooldown mirror still resolve until 13 ages in.
"pillow>=12.2,<14",
# 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,<8",
"filelock>=3.0",
# _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",
# Server performance metrics use the no-op API even when tracing is off.
"opentelemetry-api>=1.20,<2",
# 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,<26",
# 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,<27",
# CA root bundle for client TLS verification (omnigent/tls.py,
# omnigent/inner/egress/ca.py). Required as a real fallback on uv /
# python-build-standalone interpreters whose OpenSSL has no default cert
# path; previously only transitive, pinned here now that we import it.
# 2026.10.19 drops the roots behind the compromised eMudhra intermediates.
# custom-lint: disable-next=young-dependency-floor -- CA security fix; proxy serves it
"certifi>=2026.10.19",
# Protobuf schema for the AI-gateway routing API
# (omnigent/api/routing/v1/routing.proto).
# Previously only a transitive dep; declared directly now that we ship a proto.
# Upper bound widened to <8 so the google-antigravity extra can pull in
# protobuf 7.x without conflicting with this core floor. Our own
# routing_pb2 gencode was compiled against protobuf 6.x; the protobuf
# runtime guarantee allows a newer runtime (7.x) to load older gencode, so
# a plain install stays on 6.x and an antigravity install upgrades to 7.x.
"protobuf>=6,<8",
# RFC 5545 recurrence rules for the scheduled-task scheduler
# (omnigent/server/scheduled/rrule.py). Imported at module top and pulled
# onto the core server boot path via app.py; previously only a transitive
# dep, declared directly now that we import it.
"python-dateutil>=2.8,<3",
# IANA time-zone database for `zoneinfo`. Windows ships no system tz
# database, so `ZoneInfo("UTC")` raises ZoneInfoNotFoundError there
# unless this package is installed. Evaluated at module top in
# omnigent/server/scheduled/rrule.py and scheduler.py, both pulled onto
# the core server boot path via app.py, so a Windows install crashes on
# `omnigent server start` without it. POSIX platforms use the system
# database and don't need the wheel.
"tzdata>=2024.1; platform_system == 'Windows'",
]
[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 = []
cockroachdb = [
"psycopg[binary]>=3.1,<4",
"sqlalchemy-cockroachdb>=2.0,<3",
]
# `all` carries dependencies moved out of the default install that internal
# CI / dev workflows still exercise.
all = [
"databricks-sdk[sandbox]>=0.153,<1",
"opentelemetry-sdk>=1.20,<2",
"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",
]
# From omnigent.
bedrock = ["boto3>=1.30,<2", "botocore>=1.30,<2"]
# The credential store's AWS KMS backend (omnigent/stores/credential_store/secret_cipher.py)
# imports boto3 lazily, only when OMNIGENT_CREDENTIAL_KMS_KEY_ID is set. Its own extra, so a
# KMS deployment installs `omnigent[kms]`; the Vault backend uses `vault` (hvac) instead, and
# the backend-agnostic base store needs neither.
kms = ["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"]
# Blaxel sandbox launcher (`omnigent sandbox --provider blaxel` and
# server-managed `sandbox.provider: blaxel`).
blaxel = ["blaxel>=0.4.1,<0.5"]
# 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"]
# Microsandbox launcher: local libkrun microVMs with an optional embedded SDK.
# Require 0.6.9 for upstream bug fixes and pin the beta SDK's minor version.
microsandbox = ["microsandbox>=0.6.9,<0.7"]
# 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"]
# Islo sandbox launcher (`omnigent sandbox --provider islo` and
# server-managed `sandbox.provider: islo`). The launcher module ships in
# the base package and imports the SDK lazily, so only users of the
# provider need this extra.
islo = ["islo>=0.3.5,<0.4"]
# 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. 0.1 addresses
# exec by sandbox name within a workspace.
openshell = ["openshell>=0.1.0,<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,<38"]
# AWS Lambda MicroVMs launcher (server-managed `sandbox.provider:
# lambda_microvm`). The launcher module ships in the base package and imports
# boto3 lazily, so only users of the provider need this extra. Floor is the
# `lambda-microvms` service-model GA release (botocore 1.43.35 and its matching
# boto3), NOT the looser bedrock/s3 pin — an older boto3 passes the import
# probe and then fails at `boto3.client("lambda-microvms")` with
# UnknownServiceError.
lambda-microvm = ["boto3>=1.43.35,<2", "botocore>=1.43.35,<2"]
# Vault Transit backend for the credential store's SecretCipher — the
# non-AWS alternative to the built-in KMS cipher (selected by
# OMNIGENT_CREDENTIAL_VAULT_KEY). hvac is imported lazily, like boto3, so
# only deployments that pick the Vault backend need this extra.
vault = ["hvac>=2,<3"]
# OpenTelemetry tracing is opt-in so the exporters and automatic
# instrumentors do not inflate the default install.
tracing = [
"opentelemetry-sdk>=1.20,<2",
"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",
]
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.
# google-antigravity ships proto gencode compiled against protobuf 7.x, so
# the runtime must satisfy >=7 when this extra is installed; the core allows
# >=6,<8, so this constraint selects the 7.x slot and prevents the
# "gencode/runtime version mismatch" error at import time.
antigravity = ["google-antigravity>=0.1,<1", "protobuf>=7,<8"]
# 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"]
# Server-side streaming dictation (`WS /v1/dictation/stream`,
# designs/server-dictation.md). Local CPU speech-to-text via sherpa-onnx;
# the engine module imports it lazily, so only servers offering dictation
# need the extra. Models are fetched separately
# (scripts/fetch-dictation-models.sh). sherpa-onnx-core (the native
# onnxruntime payload) is pinned explicitly because sherpa-onnx's wheel
# metadata declares it inconsistently across platforms — without the
# explicit pin it is missing from uv.lock, which breaks both the hashed
# OSV audit and aarch64 installs.
dictation = [
"sherpa-onnx>=1.13,<2",
"sherpa-onnx-core>=1.13,<2",
# The engine converts PCM frames with numpy directly; declare it
# rather than riding whichever extra happens to pull it in.
"numpy>=1.24,<3",
]
# 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.
hindsight = ["hindsight-client>=0.4.0"]
# The Nimble builtins (`nimble_research`, `nimble_extract`). nimble_research
# imports the nimble-python client lazily; nimble_extract talks raw httpx and
# needs no client at runtime. Installing this extra is the opt-in signal that
# surfaces both tools in the onboarding assistant's builtin list.
nimble = ["nimble-python>=1.2.0,<2"]
# Slack integration (`omni integration slack`). The @omnigent socket-mode bot
# lives in the separate `omnigent-slack` package (heavy deps — slack_bolt /
# aiohttp — kept out of the baseline install). The CLI launches it as a
# subprocess (`python -m omnigent_slack`), so it must be importable in the same
# environment; installing `omnigent[slack]` puts it there. Local/editable
# installs resolve it from `integrations/slack` via [tool.uv.sources] below;
# publishing `omnigent[slack]` to an index additionally requires publishing
# `omnigent-slack` there (not yet wired into the release pipeline).
# Version-locked (==) with the lockstep cycle — `scripts/update_versions.py`
# keeps this pin in sync with the other sibling `==` pins
# (`omnigent-client`, `omnigent-ui-sdk`) and the sub-package's own
# `[project].version` in `integrations/slack/pyproject.toml`.
slack = [
"omnigent-slack==0.22.0.dev0",
]
# PostgreSQL storage backend. The server builds a psycopg engine whenever
# the database URI is Postgres (``OMNIGENT_DATABASE_URI=postgresql+psycopg://…``
# / ``--database-uri``). That is a general-purpose escape hatch — any
# standalone Postgres deployment needs the driver, not only Databricks — so it
# gets its own extra rather than being reachable only via `databricks`.
# ``_create_engine`` raises an actionable "install omnigent[postgres]" error
# when the URI is Postgres but this driver is absent.
postgres = ["psycopg[binary]>=3.1,<4"]
databricks = [
# 0.153 is the first SDK with streaming Sandbox command execution; the
# `sandbox` extra adds the grpcio it runs over.
"databricks-sdk[sandbox]>=0.153,<1",
"opentelemetry-distro>=0,<1",
# Databricks uses a Postgres control plane (Lakebase); reuse the single
# psycopg pin from the `postgres` extra so the two never drift.
"omnigent[postgres]",
"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. Floored
# at 0.9.0 (the release the lock already resolves): with the old >=0.1.0
# floor, a fresh install could satisfy the ai-bridge floor below by
# dropping mcp to 0.1.0, which pulls no mlflow/pyarrow at all.
"databricks-mcp>=0.9.0",
# Floor the transitive databricks-ai-bridge: older releases pull a
# databricks-vectorsearch that pins protobuf 5.x (conflicts with our
# protobuf>=6), so the resolver backtracks to an ai-bridge that caps
# mlflow at 3.2 and pyarrow<22 — and pyarrow 21 has no cp314 wheel, so a
# fresh install on Python 3.14 tries (and fails) to build it from source.
"databricks-ai-bridge>=0.19",
]
# Load testing (dev/loadtest/). Locust drives the concurrency and the
# openai-agents harness runs the mocked turns. Opt-in — only load-test users
# need it.
loadtest = [
"locust>=2.30,<3",
]
# Repository-only workflows use PEP 735 dependency groups so development
# tooling is not published as an installable Omnigent capability.
[dependency-groups]
lint = [
"ruff>=0.6",
"pyrefly==1.1.1",
"pre-commit>=3.5",
# protoc + the well-known-type protos, for regenerating the routing API
# bindings (omnigent/api/routing/v1/routing_pb2.*). Bundles its own compiler so no
# system protoc is needed. Capped below 1.83 so the bundled libprotoc emits
# protobuf 6.x gencode; routing_pb2 must stay at gencode 6.x because
# cwsandbox/modal installs are pinned to a protobuf 6.x runtime and the
# protobuf runtime cannot be older than the gencode version. A 7.x runtime
# (antigravity) also loads 6.x gencode under the forward-compat guarantee,
# so 6.x gencode satisfies all install forks.
"grpcio-tools>=1.68,<=1.81.1",
]
test = [
"pytest>=7.0",
# PEP 517 frontend used by the standalone-package artifact checks.
"build>=1.2",
# These clients are optional product capabilities, but their tests import
# and execute the real packages against mocks.
"hindsight-client>=0.4.0",
"nimble-python>=1.2.0,<2",
"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",
# Isolated pytest subprocesses use the plugin's built-in base-URL support.
"pytest-playwright>=0.10",
# 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).
"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",
# 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",
]
dev = [
{ include-group = "lint" },
{ include-group = "test" },
]
[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"
[tool.uv]
# Keep plain `uv sync` aligned with the published base package. Repository
# workflows opt into the smallest dependency group they need.
default-groups = []
# `antigravity` requires protobuf>=7 (google-antigravity ships gencode
# compiled against protobuf 7.x). The following extras/groups all cap their
# own transitive deps at protobuf<7, making them mutually exclusive with
# `antigravity`. Declaring conflicts lets uv resolve each set in an isolated
# fork rather than failing the whole lockfile or silently downgrading
# shared dependencies like databricks-sdk.
# cwsandbox: protobuf<7 (cwsandbox itself)
# modal: protobuf<7 (modal itself)
# lint group: protobuf<7 (grpcio-tools<=1.81.1 requires protobuf<7) — only
# conflicts with antigravity, not with cwsandbox/modal
# `databricks` needs no entry: databricks-sdk>=0.153 accepts protobuf 7.
conflicts = [
[{ extra = "antigravity" }, { extra = "cwsandbox" }],
[{ extra = "antigravity" }, { extra = "modal" }],
[{ group = "lint" }, { extra = "antigravity" }],
]
# Share the repository lockfile with standalone automation packages.
[tool.uv.workspace]
members = [".github/triage_v2"]
# 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 }
# Local resolution for the `slack` extra. Only pulled in when `omnigent[slack]`
# is requested (the extra is opt-in), so a default install never builds it.
omnigent-slack = { path = "integrations/slack", 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" = ["*.cjs"]
"omnigent.resources.pi_native" = ["*.js", "*.cjs"]
"omnigent.resources.pi_gateway" = ["*.js"]
"omnigent.resources.scripts" = ["*.sh"]
# 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, tests/browser_ui, and tests/e2e_live require
# credentials and/or extra setup (Databricks profile; npm build + Playwright
# browsers for the UI suites; a deployed Databricks App URL for the live
# suite). Opt in via explicit pytest invocation.
# structlog-config's pytest plugin clobbers unittest's private item._excinfo.
# Disable it until the plugin stops writing to that attribute.
addopts = "-p no:structlog_config --ignore=tests/e2e --ignore=tests/e2e_ui --ignore=tests/browser_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.",
"compat_smoke: core server↔runner and UI↔server protocol boundary test. Must use mock LLM and exercise a cross-component interaction. Selected by the backwards-compat PR gate (-m compat_smoke) for a fast multi-test signal before the full overnight matrix.",
"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 standard runner image.",
"workspace_panel_product_default: UI test that must exercise the real collapsed-by-default Workspace panel state instead of the open-panel E2E baseline.",
"smart_routing: end-to-end Smart Routing CUJ (tests/e2e/routing). Opt-in via OMNIGENT_E2E_SMART_ROUTING=1: launches a real omnigent host plus real claude/codex TUIs against a gateway. The routing service itself is an in-test mock, so no AI-Gateway task_v1 deployment is needed.",
"live_model_flows: end-to-end model-flow CUJs (tests/e2e/omnigent/test_model_flows_live.py). Opt-in via OMNIGENT_E2E_MODEL_FLOWS=1: boots a real omnigent server + host from a checkout (OMNIGENT_E2E_MODEL_FLOWS_REPO overrides which one, enabling the red-on-main matrix) with real claude/codex logins, drives the real SPA in a browser, and asserts pane truth via tmux. Never runs in CI by accident; each landing PR runs it locally per docs/model-flows test plan.",
"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
target-version = "py312"
# 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",
# Protobuf-generated code (DO NOT EDIT); not ours to restyle.
"omnigent/api/**/*_pb2.py",
"omnigent/api/**/*_pb2.pyi",
]
[tool.ruff.format]
docstring-code-format = true
[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)
# ``DTZ`` — flake8-datetimez (explicit timezone-aware datetimes)
# ``LOG`` — flake8-logging (correct exception and logger usage)
# ``RUF`` — ruff-specific (sorted ``__all__``, dangling asyncio
# tasks, unused noqa, ...)
select = ["E", "F", "I", "UP", "ARG", "BLE", "B", "SIM", "RET", "C4", "PIE", "DTZ", "LOG", "RUF"]
ignore = [
# Preserve runtime type-alias, enum, and generic semantics. These rewrites
# need compatibility review rather than automatic syntax modernization.
"UP040",
"UP042",
"UP046",
"UP047",
# 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/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/harnesses/antigravity_native/*.py" = ["BLE001"]
# Telemetry modules intentionally catch all exceptions at every boundary —
# telemetry must never disrupt the application under any circumstances.
"omnigent/telemetry/*.py" = ["BLE001", "SIM105"]
"sdks/**/*.py" = [
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
]
# slack_bolt dispatches to handlers by parameter NAME (``body``, ``event``,
# ``client``, ``ack``, ``view``), so unused handler args can't be renamed to
# ``_`` without breaking injection. The bot also has deliberate boundary
# catches (best-effort acks, background login tasks) that must never abort a
# turn, hence BLE001.
"integrations/slack/**/*.py" = [
"ARG001", "ARG002", "BLE001", "B008", "RUF012",
]
# The sessions route is a facade over an implementation package. Its explicit
# imports intentionally re-export implementation names and load route modules
# for registration, so F401 remains expected in this package.
"omnigent/server/routes/sessions/__init__.py" = ["ARG001", "ARG002", "BLE001", "E501", "F401"]
"omnigent/server/routes/sessions/*.py" = ["ARG001", "ARG002", "BLE001", "E501", "F401"]