forked from omnigent-ai/omnigent
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
659 lines (641 loc) · 34.8 KB
/
Copy pathpyproject.toml
File metadata and controls
659 lines (641 loc) · 34.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
[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.10.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.10.0.dev0",
"omnigent-ui-sdk==0.10.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,<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.
# 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.
"pillow>=12.2,<13",
# 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",
# 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,<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",
# 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.
"certifi>=2023.7",
# 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 = []
# `all` carries dependencies moved out of the default install that internal
# CI / dev workflows still exercise.
all = [
"databricks-sdk>=0.56.0,<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"]
# 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"]
# 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.
openshell = ["openshell>=0.0.88,<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"]
# 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"]
# Backwards-compatibility alias: this extra was renamed to `hindsight` (see
# above) in #2605. Keep `memory` pulling the same client so existing
# `omnigent[memory]` / `--extra memory` invocations keep working.
# TODO(0.70): remove this `memory` alias extra — it exists only to keep the
# pre-rename install command working during the deprecation window.
memory = ["hindsight-client>=0.4.0"]
# Nimble research runs (the `nimble_research` builtin). The tool imports the
# nimble-python client lazily, so only users who enable nimble_research need
# this extra. nimble_extract talks raw httpx and needs no extra.
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.10.0.dev0",
]
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. 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",
# 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",
"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",
# 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)
# databricks: protobuf<7 (databricks-sdk>=0.56 caps at <7.0)
# lint group: protobuf<7 (grpcio-tools<=1.81.1 requires protobuf<7) — only
# conflicts with antigravity, not with cwsandbox/modal/databricks
conflicts = [
[{ extra = "antigravity" }, { extra = "cwsandbox" }],
[{ extra = "antigravity" }, { extra = "modal" }],
[{ extra = "antigravity" }, { extra = "databricks" }],
[{ 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_native" = ["*.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, 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.",
"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 unpinned ubuntu-latest.",
"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.",
"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",
# Protobuf-generated code (DO NOT EDIT); not ours to restyle.
"omnigent/api/**/*_pb2.py",
"omnigent/api/**/*_pb2.pyi",
]
[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 = [
# 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"]
# 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"]