-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathpyproject.toml
More file actions
473 lines (429 loc) · 20.5 KB
/
Copy pathpyproject.toml
File metadata and controls
473 lines (429 loc) · 20.5 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
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "openadapt-flow"
version = "1.30.0"
description = "Compile demonstrated GUI workflows into deterministic local replay with governed repair and refusal"
readme = "README.md"
license = { text = "MIT" }
# rapidocr-onnxruntime is part of the validated identity/OCR path and does not
# publish Python 3.13-compatible releases. Keep the package boundary aligned
# with the runtime we actually qualify; migrating OCR engines requires rerunning
# the identity and dense-surface safety evidence first.
requires-python = ">=3.10,<3.13"
authors = [{ name = "OpenAdapt.AI" }]
dependencies = [
"pydantic>=2.5",
"numpy>=1.26",
"opencv-python-headless>=4.9",
"pillow>=10.0",
"rapidocr-onnxruntime>=1.3",
# GPU-less runners call the on-prem VLM appliance over HTTP
# (runtime.remote_vlm). Lightweight; core so the fail-safe client is
# always importable on a runner.
"httpx>=0.27",
"idna>=3.6",
# Policy files (openadapt_flow.policy) are YAML; the `certify` CLI and the
# shipped example policies load them. Tiny, pure-Python, core so `certify`
# works out of the box.
"pyyaml>=6.0",
"tomli>=2.0; python_version < '3.11'",
# Opt-in encryption-at-rest for compiled bundles and durable checkpoints
# (openadapt_flow.crypto: AES-256-GCM sealed containers). Core so
# Workflow.save(encrypt=True) / load(key=...) and encrypted checkpoints work
# out of the box in a regulated/PHI deployment; the audited AEAD substrate
# for docs/phi_at_rest.md. Imported lazily, only on the encryption path.
"cryptography>=42.0",
]
[project.optional-dependencies]
browser = [
# Browser recording/replay is an explicit substrate capability. Native
# desktop, RDP, and Citrix users do not need this ~34-47 MB driver wheel or
# its separately downloaded Chromium runtime.
"playwright>=1.44",
]
dev = [
"pytest>=8",
"pytest-timeout>=2.2",
# Property-based (fuzz) testing of the identity gate's never-false-accept
# invariant (tests/test_identity_fuzz.py).
"hypothesis>=6.100",
# Benchmark harness: agent baseline (anthropic) + chart rendering.
"anthropic>=0.40",
"matplotlib>=3.8",
# Pixel-identity validation probe: SSIM comparison method (dev-only; the
# pixel tier is hard-gated OFF in the shipped runtime).
"scikit-image>=0.22",
# WindowsBackend tests (mock WAA server).
"requests>=2.31",
# VLM service + operator console tests (TestClient over the FastAPI apps);
# uvicorn for the console's boot smoke test.
"fastapi>=0.110",
"uvicorn>=0.29",
# V2 uses the separately signed entity contract from Types 0.9.0. Portable
# business decisions use the reviewed-copy contract from Types 0.10.0. A
# peer must still negotiate each schema; the dependency alone never
# upgrades an existing decision surface.
"openadapt-types>=0.10.0,<0.11.0",
# Engineering-hygiene gates (lint+format, type-check, coverage). Pinned to
# majors so CI and local dev run the same checkers.
"ruff==0.15.22",
"mypy>=1.11",
"pytest-cov>=5.0",
"jsonschema>=4.21",
# Browser tests remain part of the full development matrix even though the
# published base runtime no longer installs Playwright for non-web users.
"playwright>=1.44",
]
grounder = ["anthropic>=0.40"]
# PRIMARY grounding rung: OCR text-anchoring via openadapt-grounding
# (pillow + pytesseract; CPU-only, no GPU, no served model, no paid API).
# OCRAnchorGrounder imports it lazily and abstains (returns None) when absent,
# so the core stays installable and the ladder safe-halts without it.
grounding = ["openadapt-grounding>=0.1.0"]
# Operator console: `openadapt-flow console` serves a localhost-only web UI
# over compiled bundles / run reports / skill libraries (openadapt_flow.console).
# FastAPI app + uvicorn server; the API client side (httpx) is already core.
console = [
"fastapi>=0.110",
"uvicorn>=0.29",
"openadapt-types>=0.10.0,<0.11.0",
]
# WindowsBackend: HTTP client for the WAA (Windows Agent Arena) server.
windows = ["requests>=2.31"]
# Native macOS window capture/input. Imported lazily; other platforms never
# install or import these framework bindings.
macos = [
"pyobjc-framework-applicationservices>=10.3; sys_platform == 'darwin'",
"pyobjc-framework-cocoa>=10.3; sys_platform == 'darwin'",
"pyobjc-framework-quartz>=10.3; sys_platform == 'darwin'",
]
# Native Linux AT-SPI observation/actuation. Imported lazily; the system must
# also provide the AT-SPI typelib/runtime (for example gir1.2-atspi-2.0 on
# Debian/Ubuntu) and an interactive X11 session.
linux = [
"PyGObject>=3.46; sys_platform == 'linux'",
]
# FreeRDPBackend: pure-Python async RDP client for the pixel-only RDP path
# (L1/Retinology EMR over RDP). Lazily imported by AardwolfTransport — never
# needed for the mock-tested adapter, only for the real/live transport.
rdp = ["aardwolf==0.2.14"]
# PHI/PII scrubbing on persist/log paths (Presidio-backed). Optional: the
# runtime imports openadapt_flow.privacy unconditionally, but it degrades to a
# no-op when this extra is absent (OPENADAPT_FLOW_SCRUB=auto). A regulated
# deployment installs this and sets OPENADAPT_FLOW_SCRUB=on to fail closed.
# After install: python -m spacy download en_core_web_sm
privacy = [
"openadapt-privacy[presidio]>=1.0.0",
# spaCy imports Click directly from its CLI package but does not declare it;
# Typer 0.27 stopped supplying Click transitively. Keep regulated-mode
# compilation importable under fresh, unconstrained PyPI resolution.
"click>=8.0,<9",
]
# Preferred hosted-token storage. Without this extra, use the environment or
# explicitly opt into the mode-0600 plaintext fallback.
hosted = ["keyring>=25"]
# On-prem VLM inference service (the GPU-box appliance side).
service = ["fastapi>=0.110", "uvicorn[standard]>=0.29"]
# Apple-Silicon Research backend for the VLM service (local model, no GPU box).
# mlx-vlm 0.6.4 requires the Transformers range containing fixes for
# GHSA-69w3-r845-3855, GHSA-29pf-2h5f-8g72, and GHSA-fgcw-684q-jj6r. Keep the
# direct constraint as defense in depth in case a future transitive requirement
# is loosened.
service-mlx = [
"fastapi>=0.110",
"uvicorn[standard]>=0.29",
"mlx-vlm>=0.6.4,<0.7",
"transformers>=5.5,<5.15",
]
# Cross-platform desktop recording on-ramp: convert an openadapt-capture
# session into a flow recording (openadapt_flow.adapters.capture). Optional and
# imported lazily — the flow core never pulls it onto the replay hot path.
# Floor 1.2.0 retains window-scoped/UIA evidence and preserves keyboard
# shortcuts as first-class typed actions. The `test` job installs this extra
# so Flow validates against the released producer contract in headless CI.
capture = ["openadapt-capture>=1.2.0"]
# Canonical action-vocabulary interop (openadapt_flow.interop.types). Boundary
# only (emit / benchmark round-trip); never on the replay hot path. The shim
# imports openadapt-types lazily, so the core stays importable without it.
# Bounded pin: openadapt-types is 0-based semver (major_on_zero=false), so
# breaking changes land at the MINOR level. The action shim and runtime-overlay
# producer, attended-decision portal, and business-decision bridge are
# field-exact against the released schemas. The `interop-types` CI job
# type-checks and tests the boundaries against the real package; each schema is
# consumed only by an explicitly negotiated peer.
interop = ["openadapt-types>=0.10.0,<0.11.0"]
[project.scripts]
openadapt-flow = "openadapt_flow.__main__:main"
openadapt-flow-vlm-service = "openadapt_flow.services.vlm_service.__main__:main"
[tool.hatch.build.targets.wheel]
packages = ["openadapt_flow"]
# Publication artifacts carry the public mechanism, interfaces, and
# conservative runtime defaults -- never the grown identity corpora, their ROC
# tuning surface, or repository-only reliability recipes/results. Keep this
# list in lockstep with the sdist target and the archive validator below.
exclude = [
"/.hypothesis",
"/benchmark/**/api-delta-probe-*",
"/benchmark/**/bundle-live*",
"/benchmark/**/out",
"/benchmark/**/output",
"/benchmark/**/outputs",
"/benchmark/**/recording-live*",
"/benchmark/**/results-*",
"/benchmark/**/state",
"/benchmark/**/work",
"/benchmark/**/_bundle",
"/benchmark/**/_recording",
"/benchmark/**/_work",
"/public-demo",
"/benchmark/reliability",
"/docs/validation/IDENTITY_ROC.md",
"/docs/validation/adversary_corpus_manifest.json",
"/docs/validation/adversary_corpus_v2_manifest.json",
"/docs/validation/adversary_corpus_v3_manifest.json",
"/docs/validation/identity_roc.json",
"/docs/validation/identity_roc.png",
"/openadapt_flow/benchmark/reliability_corpus.py",
"/openadapt_flow/validation/adversary_corpus.py",
"/openadapt_flow/validation/adversary_corpus_v2.py",
"/openadapt_flow/validation/adversary_corpus_v3.py",
"/openadapt_flow/validation/identity_roc.py",
"/scripts/reliability",
"/tests/test_adversary_corpus.py",
"/tests/test_adversary_corpus_v2.py",
"/tests/test_adversary_corpus_v3.py",
"/tests/test_identity_corpus_rates.py",
"/tests/test_identity_out_of_corpus.py",
"/tests/test_reliability.py",
]
# Ship the PEP 561 marker so downstream type-checkers honor our annotations.
[tool.hatch.build.targets.wheel.force-include]
"openadapt_flow/py.typed" = "openadapt_flow/py.typed"
"schemas" = "openadapt_flow/schemas"
"public-artifacts.json" = "openadapt_flow/public-artifacts.json"
# NOTE: the operator console's static UI (openadapt_flow/console/static/) is
# package data hatchling already ships by default -- do NOT force-include it
# (a duplicate-path entry fails the wheel build).
[tool.hatch.build.targets.sdist]
# Keep PyPI artifacts under the declared MIT package license. The source
# checkout carries an isolated openIMIS reference environment whose adapted
# deployment files remain AGPL-3.0-only; ship none of that benchmark surface
# (including its launcher/test and repository-only notice) in the sdist. The
# exclusions below are defense in depth for former paths and future regressions:
# grown identity corpora, ROC tuning artifacts, and detailed public-web target
# recipes/raw rows are absent from the current public tree. Public mechanisms,
# fake-patient synthetic fixtures, and bounded aggregate evidence remain.
exclude = [
"/.hypothesis",
"/benchmark/**/api-delta-probe-*",
"/benchmark/**/bundle-live*",
"/benchmark/**/out",
"/benchmark/**/output",
"/benchmark/**/outputs",
"/benchmark/**/recording-live*",
"/benchmark/**/results-*",
"/benchmark/**/state",
"/benchmark/**/work",
"/benchmark/**/_bundle",
"/benchmark/**/_recording",
"/benchmark/**/_work",
"/public-demo",
"/THIRD_PARTY_NOTICES.md",
"/benchmark/openimis_claims",
"/benchmark/reliability",
"/docs/validation/IDENTITY_ROC.md",
"/docs/validation/adversary_corpus_manifest.json",
"/docs/validation/adversary_corpus_v2_manifest.json",
"/docs/validation/adversary_corpus_v3_manifest.json",
"/docs/validation/identity_roc.json",
"/docs/validation/identity_roc.png",
"/openadapt_flow/benchmark/reliability_corpus.py",
"/openadapt_flow/validation/adversary_corpus.py",
"/openadapt_flow/validation/adversary_corpus_v2.py",
"/openadapt_flow/validation/adversary_corpus_v3.py",
"/openadapt_flow/validation/identity_roc.py",
"/scripts/openimis_claims_demo.py",
"/scripts/openimis_eligibility_demo.py",
"/scripts/reliability",
"/tests/test_adversary_corpus.py",
"/tests/test_adversary_corpus_v2.py",
"/tests/test_adversary_corpus_v3.py",
"/tests/test_identity_corpus_rates.py",
"/tests/test_identity_out_of_corpus.py",
"/tests/test_openimis_claims_fixture.py",
"/tests/test_openimis_eligibility.py",
"/tests/test_reliability.py",
"/docs/showcase-openimis",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
timeout = 600
# Auto-release (matches the other openadapt repos). Python Semantic Release
# computes the next version from Conventional Commit subjects since the last
# tag: `feat:` -> minor, `fix:`/`perf:` -> patch, `BREAKING CHANGE` -> major.
# See .github/workflows/release.yml.
[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
# Keep the package __version__ in lockstep with the pyproject version so a
# released wheel never reports a stale version (they had drifted: 0.1.0 vs the
# released pyproject version).
version_variables = ["openadapt_flow/__init__.py:__version__"]
commit_message = "chore: release {version}"
# Semantic Release runs its build inside a Python 3.14 container, while Flow's
# validated runtime is Python 3.10-3.12. Stamp only the editable root lock entry
# instead of asking uv to resolve the project under an unsupported interpreter.
build_command = "python -m ensurepip --upgrade && python -m pip install --disable-pip-version-check uv==0.11.29 && python scripts/check_release_consistency.py --sync && git add uv.lock && uv build --wheel --sdist && python scripts/check_release_consistency.py --require-dist"
[tool.semantic_release.branches.main]
match = "main"
[tool.semantic_release.commit_parser_options]
allowed_tags = ["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "style", "test"]
minor_tags = ["feat"]
patch_tags = ["fix", "perf"]
# --------------------------------------------------------------------------
# Lint + format (ruff). Real, enforced gates — see .github/workflows/ci.yml.
# --------------------------------------------------------------------------
[tool.ruff]
target-version = "py310"
line-length = 88
# Generated / non-package trees at the repo root are not part of the lint
# surface. Anchored with a leading slash so the package's own
# openadapt_flow/benchmark/ IS still linted (a bare "benchmark" would match it).
extend-exclude = ["/benchmark", "/docs", "/runs", "/dist"]
[tool.ruff.lint]
# Start pragmatic: pyflakes (real bugs), the safe pycodestyle subset, warnings,
# and import sorting. Deliberately excludes opinionated rewrite families
# (UP/SIM/B) for now so the gate is green on the current code and can be
# tightened incrementally.
select = ["E4", "E7", "E9", "F", "W", "I"]
ignore = [
# Ambiguous single-letter name `l`: used only as an OCR-line loop variable
# in a handful of comprehensions; renaming is churn with no safety value.
"E741",
# Line length is shaped by the formatter; long strings/URLs/regexes here
# would otherwise trip E501 without improving readability.
"E501",
]
[tool.ruff.format]
# Match the formatter to the codebase's existing conventions.
quote-style = "double"
indent-style = "space"
# --------------------------------------------------------------------------
# Type checking (mypy). TWO gates, both required on PRs (see
# .github/workflows/ci.yml):
#
# 1. `lint` job -> plain `mypy` with THIS config: LENIENT, whole-package.
# Green today; catches import/name/obvious-signature errors everywhere.
# Tighten the knobs below over time (they are deliberately off to start).
#
# 2. `mypy-strict-safety` job -> a STRICT run scoped to the safety-critical
# path ONLY (compiler, identity, effects, policy, qualification, replayer,
# resolver).
# It turns ON the highest-value strict knob this config leaves off --
# `--check-untyped-defs` (type-check the BODIES of un-annotated functions,
# where real safety bugs hide) -- plus no-implicit-optional, strict
# equality, redundant-cast / unused-ignore / untyped-decorator checks and
# --extra-checks. The full `--strict` superset (disallow-untyped-defs,
# disallow-any-generics, warn-return-any, warn-unreachable) is NOT yet
# green on these files without source changes; those remain the ratchet to
# flip as annotations harden. The strict file list lives in the workflow
# and mirrors the CODEOWNERS safety path -- keep the three in sync.
#
# Scoped to the core package (not tests, not the benchmark harness).
# --------------------------------------------------------------------------
[tool.mypy]
python_version = "3.10"
files = ["openadapt_flow"]
# Optional extras (aardwolf, openadapt_grounding, openadapt_capture, mlx_vlm,
# rapidocr, cv2, …) are imported lazily and have no stubs — don't fail on them.
ignore_missing_imports = true
warn_unused_configs = true
# Kept off intentionally to start lenient (annotations are not yet complete);
# these are the knobs to flip when tightening.
disallow_untyped_defs = false
check_untyped_defs = false
# numpy 2.x ships stubs that use 3.12-only `type` statement syntax; parsing
# them under our 3.10 target crashes mypy. We don't type-check against numpy's
# internals, so skip following into it (and treat it as untyped). (scikit-image
# -> tifffile has the same issue, but its only consumer here — the pixel probe —
# is in the ignore-errors debt list below, so mypy never follows into it.)
[[tool.mypy.overrides]]
module = ["numpy", "numpy.*"]
follow_imports = "skip"
follow_imports_for_stubs = true
# Known type-check debt. These modules have pre-existing errors that need real
# code changes to resolve; they're excluded from the gate for now so the
# checker is green while still covering the other modules. Remove entries here
# as the annotations are hardened.
#
# The SAFETY-CRITICAL compile/replay path is NOT in this list: the compiler
# (compiler.compile), the pre-click identity gate (runtime.identity), and the
# replayer (runtime.replayer) are fully type-checked. What remains is genuinely
# lower-stakes, harder-to-annotate debt:
# - CLI / reporting surface: __main__, report
# - alternate backends: backends.playwright_backend, backends.rdp_backend
# - benchmark & interactive tooling: benchmark.desktop_benchmark,
# interactive_recorder
# - learning-loop synthesis: learning.synth_stream
# - disambiguation heuristics: compiler.disambiguation
# - runtime helpers still on untyped deps: runtime.effects._common,
# runtime.grounder, runtime.healing.perturbation
# - the VLM microservice (FastAPI, dynamic): services.vlm_service.*
# - offline validation harnesses (not on the runtime path):
# validation.* (dense_surface, identity_ladder,
# pixel_identity_probe, pixel_identity_aligned,
# vlm_identity_probe)
# - perceptual hashing on numpy internals: vision.hashing
[[tool.mypy.overrides]]
module = [
"openadapt_flow.__main__",
"openadapt_flow.backends.playwright_backend",
"openadapt_flow.backends.rdp_backend",
"openadapt_flow.benchmark.desktop_benchmark",
"openadapt_flow.compiler.disambiguation",
"openadapt_flow.interactive_recorder",
"openadapt_flow.learning.synth_stream",
"openadapt_flow.report",
"openadapt_flow.runtime.effects._common",
"openadapt_flow.runtime.grounder",
"openadapt_flow.runtime.healing.perturbation",
"openadapt_flow.services.vlm_service.app",
"openadapt_flow.services.vlm_service.backends",
"openadapt_flow.services.vlm_service.batching",
"openadapt_flow.validation.dense_surface",
"openadapt_flow.validation.identity_ladder",
"openadapt_flow.validation.pixel_identity_probe",
"openadapt_flow.validation.pixel_identity_aligned",
"openadapt_flow.validation.vlm_identity_probe",
"openadapt_flow.vision.hashing",
]
ignore_errors = true
# --------------------------------------------------------------------------
# Coverage. Whole-package measurement stays a VISIBILITY number, but the
# safety-critical path now has an ENFORCED, required floor on PRs.
#
# The `test` job (see .github/workflows/ci.yml) runs the fast unit suite under
# coverage, then enforces a ratchet with a SCOPED report:
#
# coverage report --fail-under=85 \
# --include='openadapt_flow/compiler/*,openadapt_flow/identity_signals.py,\
# openadapt_flow/runtime/identity*,\
# openadapt_flow/runtime/replayer.py,\
# openadapt_flow/runtime/resolver.py,openadapt_flow/policy.py,\
# openadapt_flow/runtime/effects/*'
#
# 85% is the ratchet floor: it sits just under the fast-suite's measured
# branch-inclusive coverage of that path (~88% locally, higher in CI where the
# FHIR-effect + replayer-dependent tests that collide with a sibling repo's
# `tests` package locally also run). NEVER decrease it -- raise it as coverage
# climbs. Keep the --include globs in sync with the mypy strict scope above and
# with CODEOWNERS.
# --------------------------------------------------------------------------
[tool.coverage.run]
source = ["openadapt_flow"]
branch = true
[tool.coverage.report]
show_missing = true
skip_covered = false
precision = 2