Ctrl K
ComunidadGuías…

pyproject.toml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[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"]