openadapt 1.2.2__tar.gz → 1.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/main.yml +8 -1
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/release-and-publish.yml +18 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/CHANGELOG.md +27 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/PKG-INFO +1 -1
- {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/__init__.py +3 -5
- {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/cli.py +58 -16
- {openadapt-1.2.2 → openadapt-1.2.4}/pyproject.toml +1 -1
- openadapt-1.2.4/tests/test_cli_smoke.py +231 -0
- openadapt-1.2.4/tests/test_import_integrity.py +253 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/CODEOWNERS +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/FUNDING.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/bug_form.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/new_feature.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/ISSUE_TEMPLATE/use_case.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/pull_request_template.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/docs.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.github/workflows/notify-docs.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/.gitignore +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/CLAUDE.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/CONTRIBUTING.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/LICENSE +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/README.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/CNAME +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/DOCS_UPDATE_SUMMARY.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/LEGACY_FREEZE.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/_scripts/README.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/_scripts/generate_docs_screenshots.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/architecture-evolution.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/architecture.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/architecture-diagram.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_accessibility.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_input_monitoring.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_permissions_alert.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/assets/macOS_screen_recording.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/cli.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/contributing.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/INDEX.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/landing-page-strategy.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/openadapt-tray.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/production-execution-design.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/repo-rename-analysis.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/telemetry-design.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/design/tray-logging.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/installation.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/permissions.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/getting-started/quickstart.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/index.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/legacy/freeze.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/capture.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/evals.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/grounding.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/index.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/ml.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/privacy.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/retrieval.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/packages/viewer.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/permissions-macos.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/publication-roadmap.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/docs/roadmap-priorities.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/examples/capture_train_eval.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/examples/demo_retrieval_augmented.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/.flake8 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/.pre-commit-config.yaml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/CHANGELOG.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/CONTRIBUTING.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/README.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/SETUP.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/fixtures.sql +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_accessibility.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_input_monitoring.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_permissions_alert.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/macOS_screen_recording.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/assets/visualize.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/get_version.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/macos.sh +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/test_app_run_macos.sh +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/test_app_run_windows.bat +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/build_scripts/upload_release_artifacts.sh +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/background.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/content.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/icons/logo.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/chrome_extension/manifest.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/.env.example +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/README.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/.dockerignore +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/Dockerfile +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/client.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/deploy/models/omniparser/deploy.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/deploy/pyproject.toml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/describe_actions.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/fastsamsom.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/gpt4o_seg.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/handle_similar_segments.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/experiments/imagesimilarity.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/install/install_openadapt.ps1 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/install/install_openadapt.sh +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/prompt.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/replicate.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/som.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/adapters/ultralytics.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/README +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/context_loader.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/env.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/script.py.mako +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/104d4a614d95_add_performancestat.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/186316d4f3ca_add_scrubbed_columns.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/20f9c2afb42c_rename_input_event_to_action_event.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/2a8a241785f2_add_original_recording_id.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/30a5ba9d6453_add_active_segment_description_and_.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/5139d7df38f6_add_recording_task_description.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/530f0663324e_add_recording_video_start_time.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/57d78d23087a_add_windowevent_state.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/607d1380b5ae_add_memorystat.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/8495f5471e23_add_recording_config.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/8713b142f5de_add_png_diff_data_and_png_diff_mask_data.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/87a78a84a8bf_remove_recording_timestamp_fks.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/98505a067995_add_browserevent_table.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/98c8851a5321_add_audio_info.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/a29b537fabe6_add_disabled_field_to_action_event.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/b206c80f7640_add_recording_inputevent_screenshot_.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/b2dc41850120_window_window_id.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/bb25e889ad71_generate_unique_user_id.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/c24abb5455d3_create_new_recording_fks.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/d63569e4fb90_actionevent_element_state.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/d714cc86fce8_add_scrubbed_recording_model.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/ec337f277666_datetime_timestamp.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic/versions/f9586c10a561_migrate_data_to_new_fks.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/alembic.ini +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo.ico +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/assets/logo_inverted.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.eslintrc.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.gitignore +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.nvmrc +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/.prettierrc.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/README.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/action_events.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/index.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/recordings.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/scrubbing.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api/settings.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/api.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/favicon.ico +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/globals.css +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/layout.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/onboarding/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/providers.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/RawRecordings.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/ScrubbedRecordings.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/detail/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/recordings/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/routes.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/scrubbing/ScrubbingUpdates.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/scrubbing/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/(api_keys)/form.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/(api_keys)/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/SettingsHeader.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/layout.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/navbar.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/record_and_replay/form.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/record_and_replay/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/scrubbing/form.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/scrubbing/page.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/settings/utils.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/app/utils.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/assets/logo.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/ActionEvent.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/ActionEvents.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/RemoveActionEvent.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/Screenshots.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/ActionEvent/index.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Navbar/Navbar.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Navbar/index.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/BookACall.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/RegisterForUpdates.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Onboarding/steps/Tutorial.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/RecordingDetails/RecordingDetails.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/RecordingDetails/index.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Shell/Shell.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/Shell/index.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/SimpleTable/SimpleTable.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/components/SimpleTable/index.tsx +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/entrypoint.ps1 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/entrypoint.sh +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/index.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/next.config.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/package-lock.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/package.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/postcss.config.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/run.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/tailwind.config.js +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/tsconfig.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/action-event.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/recording.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/dashboard/types/scrubbing.ts +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/app/tray.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/browser.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/build.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/build_utils.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/cache.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/__main__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_linux.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_macos.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/capture/_windows.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/common.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/config.defaults.json +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/config.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/som/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/contrib/som/visualizer.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/custom_logger.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/crud.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/db.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/list.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/db/remove.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/deprecated/app/cards.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/anthropic.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/google.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/drivers/openai.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/entrypoint.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/error_reporting.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/events.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/extensions/synchronized_queue.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/models.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/playback.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/plotting.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/base.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/aws_comprehend.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/presidio.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/privacy/providers/private_ai.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/productivity.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/apply_replay_instructions.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/describe_recording--segment.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/describe_recording.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/description.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/generate_action_event--segment.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/generate_action_event.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/is_action_complete.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/prompts/system.j2 +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/record.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/replay.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/reset_db.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scripts/scrub.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/scrub.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/share.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/download_model.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/spacy_model_helpers/spacy_model_init.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/start.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/base.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/demo.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/ascii.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/huggingface.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/ocr.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/openai.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/sam.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/mixins/summary.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/naive.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/segment.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/stateful.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/vanilla.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/visual.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/strategies/visual_browser.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/utils.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/video.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/vision.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/visualize.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/__init__.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_linux.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_macos.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/openadapt/window/_windows.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/permissions_in_macOS.md +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/poetry.lock +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/scripts/downloads.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/scripts/postinstall.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/setup.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/calculator.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/excel.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/sample_llc_1.pdf +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_emr_image.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_image_redaction_presidio.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/assets/test_image_redaction_privateai.png +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/conftest.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_anthropic.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_google.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/drivers/test_openai.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_comprehend_scrub.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_presidio_scrub.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/providers/test_private_ai_scrub.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/privacy/test_providers.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_browser.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_crop.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_crud.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_events.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_models.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_share.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_summary.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_utils.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_video.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/tests/openadapt/test_vision.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/legacy/workflows/release-and-publish.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/mkdocs.yml +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/config.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/openadapt/version.py +0 -0
- {openadapt-1.2.2 → openadapt-1.2.4}/uv.lock +0 -0
|
@@ -29,7 +29,11 @@ jobs:
|
|
|
29
29
|
- name: Install dependencies
|
|
30
30
|
run: |
|
|
31
31
|
python -m pip install --upgrade pip
|
|
32
|
-
|
|
32
|
+
# openadapt-ml is installed explicitly so the cross-package
|
|
33
|
+
# seam tests (tests/test_import_integrity.py and the cmd_serve
|
|
34
|
+
# contract in tests/test_cli_smoke.py) run instead of skipping.
|
|
35
|
+
# Issue #999 shipped because this seam was never tested in CI.
|
|
36
|
+
pip install -e ".[dev]" openadapt-ml
|
|
33
37
|
|
|
34
38
|
- name: Lint with ruff
|
|
35
39
|
run: |
|
|
@@ -40,3 +44,6 @@ jobs:
|
|
|
40
44
|
run: |
|
|
41
45
|
python -c "from openadapt.cli import main; print('CLI import OK')"
|
|
42
46
|
python -c "from openadapt.version import __version__; print(f'Version: {__version__}')"
|
|
47
|
+
|
|
48
|
+
- name: Run tests
|
|
49
|
+
run: pytest tests/ -v
|
|
@@ -54,3 +54,21 @@ jobs:
|
|
|
54
54
|
poetry config pypi-token.pypi $PYPI_TOKEN
|
|
55
55
|
poetry build
|
|
56
56
|
poetry publish --no-interaction --skip-existing
|
|
57
|
+
|
|
58
|
+
# Releases in openadapt-ml failed silently for 3 months (Mar-Jun
|
|
59
|
+
# 2026) while PyPI went stale; see issue #999. Fail loudly instead.
|
|
60
|
+
- name: File issue on release failure
|
|
61
|
+
if: failure()
|
|
62
|
+
env:
|
|
63
|
+
GH_TOKEN: ${{ secrets.ADMIN_TOKEN }}
|
|
64
|
+
run: |
|
|
65
|
+
TITLE="Release workflow failed on main"
|
|
66
|
+
BODY="The release workflow failed: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
67
|
+
|
|
68
|
+
Until this is fixed, merged fix/feat commits are NOT being published to PyPI, and users install stale versions."
|
|
69
|
+
EXISTING=$(gh issue list --repo "${{ github.repository }}" --state open --search "in:title \"$TITLE\"" --json number --jq '.[0].number // empty')
|
|
70
|
+
if [ -n "$EXISTING" ]; then
|
|
71
|
+
gh issue comment "$EXISTING" --repo "${{ github.repository }}" --body "$BODY"
|
|
72
|
+
else
|
|
73
|
+
gh issue create --repo "${{ github.repository }}" --title "$TITLE" --body "$BODY"
|
|
74
|
+
fi
|
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v1.2.4 (2026-06-12)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Serve Namespace and lazy-import bugs; add CLI smoke and seam tests
|
|
10
|
+
([#1002](https://github.com/OpenAdaptAI/OpenAdapt/pull/1002),
|
|
11
|
+
[`7e4d3ce`](https://github.com/OpenAdaptAI/OpenAdapt/commit/7e4d3ce38423ee224d303f204ef9b94025820c11))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## v1.2.3 (2026-06-12)
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
- Honor --output in serve, clear error for unresolvable configs
|
|
19
|
+
([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
|
|
20
|
+
[`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
|
|
21
|
+
|
|
22
|
+
- Repair broken openadapt-ml imports in serve and train CLI commands
|
|
23
|
+
([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
|
|
24
|
+
[`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
|
|
25
|
+
|
|
26
|
+
### Code Style
|
|
27
|
+
|
|
28
|
+
- Ruff format cli.py ([#1001](https://github.com/OpenAdaptAI/OpenAdapt/pull/1001),
|
|
29
|
+
[`37db8d4`](https://github.com/OpenAdaptAI/OpenAdapt/commit/37db8d4862097efaa57608bdd4972a72f0e57a7b))
|
|
30
|
+
|
|
31
|
+
|
|
5
32
|
## v1.2.2 (2026-03-04)
|
|
6
33
|
|
|
7
34
|
### Bug Fixes
|
|
@@ -59,11 +59,10 @@ def __getattr__(name: str):
|
|
|
59
59
|
return locals()[name]
|
|
60
60
|
|
|
61
61
|
# ML package (heavy - only import if explicitly requested)
|
|
62
|
-
if name
|
|
63
|
-
from openadapt_ml import QwenVLAdapter # noqa: F401
|
|
64
|
-
from openadapt_ml.training import Trainer # noqa: F401
|
|
62
|
+
if name == "QwenVLAdapter":
|
|
63
|
+
from openadapt_ml.models.qwen_vl import QwenVLAdapter # noqa: F401
|
|
65
64
|
|
|
66
|
-
return
|
|
65
|
+
return QwenVLAdapter
|
|
67
66
|
|
|
68
67
|
# Grounding package (optional)
|
|
69
68
|
if name in ("Grounder", "OmniGrounder", "GeminiGrounder"):
|
|
@@ -115,7 +114,6 @@ __all__ = [
|
|
|
115
114
|
"HTMLBuilder",
|
|
116
115
|
# From ml
|
|
117
116
|
"QwenVLAdapter",
|
|
118
|
-
"Trainer",
|
|
119
117
|
# From grounding (optional)
|
|
120
118
|
"Grounder",
|
|
121
119
|
"OmniGrounder",
|
|
@@ -196,23 +196,49 @@ def train_start(
|
|
|
196
196
|
try:
|
|
197
197
|
click.echo("Starting training...")
|
|
198
198
|
click.echo(f" Capture: {capture}")
|
|
199
|
-
click.echo(f" Model: {model}")
|
|
200
199
|
click.echo(f" Output: {output}")
|
|
201
200
|
|
|
202
|
-
# Import and run training
|
|
203
|
-
|
|
201
|
+
# Import and run training. The model is determined by the config
|
|
202
|
+
# file; --model is kept for backward compatibility only.
|
|
203
|
+
from openadapt_ml.scripts.train import main as train_main
|
|
204
|
+
|
|
205
|
+
if not config:
|
|
206
|
+
from openadapt_ml.cloud.local import detect_device
|
|
207
|
+
|
|
208
|
+
if "cuda" in detect_device():
|
|
209
|
+
config = "configs/qwen3vl_capture.yaml"
|
|
210
|
+
else:
|
|
211
|
+
config = "configs/qwen3vl_capture_4bit.yaml"
|
|
212
|
+
try:
|
|
213
|
+
from openadapt_ml.cloud.local import resolve_config_path
|
|
214
|
+
|
|
215
|
+
config = str(resolve_config_path(config))
|
|
216
|
+
except ImportError:
|
|
217
|
+
# Older openadapt-ml without resolve_config_path; use as-is.
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
from pathlib import Path
|
|
221
|
+
|
|
222
|
+
if not Path(config).exists():
|
|
223
|
+
click.echo(f"Error: config not found: {config}", err=True)
|
|
224
|
+
click.echo(
|
|
225
|
+
"Upgrade openadapt-ml so bundled configs resolve, or pass "
|
|
226
|
+
"--config with a path to a training config YAML.",
|
|
227
|
+
err=True,
|
|
228
|
+
)
|
|
229
|
+
sys.exit(1)
|
|
230
|
+
click.echo(f" Config: {config}")
|
|
204
231
|
|
|
205
232
|
train_main(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
config=config,
|
|
233
|
+
config_path=config,
|
|
234
|
+
capture_path=capture,
|
|
209
235
|
output_dir=output,
|
|
210
236
|
open_dashboard=open,
|
|
211
237
|
)
|
|
212
238
|
|
|
213
|
-
except ImportError:
|
|
214
|
-
click.echo("Error: openadapt-ml
|
|
215
|
-
click.echo(
|
|
239
|
+
except ImportError as e:
|
|
240
|
+
click.echo(f"Error: failed to import openadapt-ml ({e}).", err=True)
|
|
241
|
+
click.echo('Install with: pip install "openadapt-ml[training]"', err=True)
|
|
216
242
|
sys.exit(1)
|
|
217
243
|
|
|
218
244
|
|
|
@@ -405,16 +431,32 @@ def serve(port: int, output: str, open: bool):
|
|
|
405
431
|
click.echo(f"Starting server on port {port}...")
|
|
406
432
|
click.echo(f"Serving from: {output}")
|
|
407
433
|
|
|
408
|
-
|
|
434
|
+
import argparse
|
|
435
|
+
from pathlib import Path
|
|
409
436
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
437
|
+
from openadapt_ml.cloud import local as oa_local
|
|
438
|
+
|
|
439
|
+
# cmd_serve resolves the 'current' run against the module-level
|
|
440
|
+
# TRAINING_OUTPUT constant; point it at the requested directory
|
|
441
|
+
# so --output is honored.
|
|
442
|
+
oa_local.TRAINING_OUTPUT = Path(output)
|
|
443
|
+
|
|
444
|
+
sys.exit(
|
|
445
|
+
oa_local.cmd_serve(
|
|
446
|
+
argparse.Namespace(
|
|
447
|
+
port=port,
|
|
448
|
+
benchmark=None,
|
|
449
|
+
no_regenerate=False,
|
|
450
|
+
start_page=None,
|
|
451
|
+
quiet=False,
|
|
452
|
+
open=open,
|
|
453
|
+
)
|
|
454
|
+
)
|
|
414
455
|
)
|
|
415
456
|
|
|
416
|
-
except ImportError:
|
|
417
|
-
click.echo("Error: openadapt-ml
|
|
457
|
+
except ImportError as e:
|
|
458
|
+
click.echo(f"Error: failed to import openadapt-ml ({e}).", err=True)
|
|
459
|
+
click.echo('Install with: pip install "openadapt-ml[training]"', err=True)
|
|
418
460
|
sys.exit(1)
|
|
419
461
|
|
|
420
462
|
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""CLI smoke and seam-contract tests.
|
|
2
|
+
|
|
3
|
+
Issue #999: `openadapt serve` and `openadapt train start` were broken
|
|
4
|
+
for months while CI stayed green, because cli.py's imports of
|
|
5
|
+
openadapt-ml only execute inside command bodies and the broad
|
|
6
|
+
`except ImportError` handlers reported every failure as
|
|
7
|
+
"openadapt-ml not installed".
|
|
8
|
+
|
|
9
|
+
Three layers of defense here:
|
|
10
|
+
|
|
11
|
+
1. test_every_command_help — walks the whole Click tree and renders
|
|
12
|
+
--help for every command, so any module-level wiring error fails CI.
|
|
13
|
+
2. Contract tests — monkeypatch the openadapt-ml entry points and
|
|
14
|
+
assert cli.py calls them the way they're actually shaped today.
|
|
15
|
+
3. test_cmd_serve_reads_only_provided_args — parses the installed
|
|
16
|
+
openadapt-ml's cmd_serve and asserts every `args.<attr>` it reads is
|
|
17
|
+
provided by cli.py's Namespace, so the seam can't drift silently in
|
|
18
|
+
either direction.
|
|
19
|
+
|
|
20
|
+
The openadapt-ml-dependent tests skip when it isn't installed; CI
|
|
21
|
+
installs it so they always run there.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import ast
|
|
27
|
+
import sys
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
import click
|
|
31
|
+
import pytest
|
|
32
|
+
from click.testing import CliRunner
|
|
33
|
+
|
|
34
|
+
from openadapt.cli import main as cli_main
|
|
35
|
+
|
|
36
|
+
# Namespace attributes cli.py's serve command provides to cmd_serve.
|
|
37
|
+
# Keep in sync with openadapt/cli.py::serve.
|
|
38
|
+
SERVE_NAMESPACE_ATTRS = {
|
|
39
|
+
"port",
|
|
40
|
+
"benchmark",
|
|
41
|
+
"no_regenerate",
|
|
42
|
+
"start_page",
|
|
43
|
+
"quiet",
|
|
44
|
+
"open",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _iter_commands(group, prefix=()):
|
|
49
|
+
yield prefix, group
|
|
50
|
+
if isinstance(group, click.Group):
|
|
51
|
+
for name, cmd in group.commands.items():
|
|
52
|
+
yield from _iter_commands(cmd, prefix + (name,))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_every_command_help():
|
|
56
|
+
"""Render --help for every command in the tree."""
|
|
57
|
+
runner = CliRunner()
|
|
58
|
+
failures = []
|
|
59
|
+
for path, _cmd in _iter_commands(cli_main):
|
|
60
|
+
args = list(path) + ["--help"]
|
|
61
|
+
result = runner.invoke(cli_main, args)
|
|
62
|
+
if result.exit_code != 0:
|
|
63
|
+
failures.append(f"{' '.join(args)!r} exited {result.exit_code}")
|
|
64
|
+
assert not failures, "Commands whose --help failed:\n " + "\n ".join(failures)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_version_command():
|
|
68
|
+
runner = CliRunner()
|
|
69
|
+
result = runner.invoke(cli_main, ["version"])
|
|
70
|
+
assert result.exit_code == 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
# Seam contracts with openadapt-ml
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _require_openadapt_ml():
|
|
79
|
+
return pytest.importorskip("openadapt_ml", reason="openadapt-ml not installed")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def test_train_start_calls_real_entry_point(monkeypatch, tmp_path):
|
|
83
|
+
"""`openadapt train start` must call scripts.train.main with kwargs
|
|
84
|
+
that exist in its signature."""
|
|
85
|
+
_require_openadapt_ml()
|
|
86
|
+
import inspect
|
|
87
|
+
|
|
88
|
+
from openadapt_ml.scripts import train as train_module
|
|
89
|
+
|
|
90
|
+
real_params = set(inspect.signature(train_module.main).parameters)
|
|
91
|
+
calls = []
|
|
92
|
+
|
|
93
|
+
def fake_main(**kwargs):
|
|
94
|
+
unknown = set(kwargs) - real_params
|
|
95
|
+
assert not unknown, (
|
|
96
|
+
f"cli.py passes kwargs {sorted(unknown)} that "
|
|
97
|
+
f"openadapt_ml.scripts.train.main does not accept "
|
|
98
|
+
f"(it takes {sorted(real_params)})"
|
|
99
|
+
)
|
|
100
|
+
calls.append(kwargs)
|
|
101
|
+
|
|
102
|
+
monkeypatch.setattr(train_module, "main", fake_main)
|
|
103
|
+
|
|
104
|
+
capture_dir = tmp_path / "my-capture"
|
|
105
|
+
capture_dir.mkdir()
|
|
106
|
+
config = tmp_path / "config.yaml"
|
|
107
|
+
config.write_text("model:\n name: test\n")
|
|
108
|
+
|
|
109
|
+
runner = CliRunner()
|
|
110
|
+
result = runner.invoke(
|
|
111
|
+
cli_main,
|
|
112
|
+
[
|
|
113
|
+
"train",
|
|
114
|
+
"start",
|
|
115
|
+
"--capture",
|
|
116
|
+
str(capture_dir),
|
|
117
|
+
"--config",
|
|
118
|
+
str(config),
|
|
119
|
+
"--no-open",
|
|
120
|
+
],
|
|
121
|
+
)
|
|
122
|
+
assert result.exit_code == 0, result.output
|
|
123
|
+
assert len(calls) == 1
|
|
124
|
+
kwargs = calls[0]
|
|
125
|
+
assert kwargs["config_path"] == str(config)
|
|
126
|
+
assert kwargs["capture_path"] == str(capture_dir)
|
|
127
|
+
assert kwargs["open_dashboard"] is False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def test_serve_calls_cmd_serve_with_expected_namespace(monkeypatch):
|
|
131
|
+
"""`openadapt serve` must call cmd_serve with the agreed Namespace."""
|
|
132
|
+
_require_openadapt_ml()
|
|
133
|
+
from openadapt_ml.cloud import local as oa_local
|
|
134
|
+
|
|
135
|
+
received = []
|
|
136
|
+
|
|
137
|
+
def fake_cmd_serve(args):
|
|
138
|
+
received.append(args)
|
|
139
|
+
return 0
|
|
140
|
+
|
|
141
|
+
monkeypatch.setattr(oa_local, "cmd_serve", fake_cmd_serve)
|
|
142
|
+
|
|
143
|
+
runner = CliRunner()
|
|
144
|
+
result = runner.invoke(cli_main, ["serve", "--port", "8123", "--no-open"])
|
|
145
|
+
assert result.exit_code == 0, result.output
|
|
146
|
+
assert len(received) == 1
|
|
147
|
+
ns = received[0]
|
|
148
|
+
assert ns.port == 8123
|
|
149
|
+
assert ns.open is False # --no-open passes through to cmd_serve
|
|
150
|
+
for attr in SERVE_NAMESPACE_ATTRS:
|
|
151
|
+
assert hasattr(ns, attr), f"Namespace missing {attr}"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_serve_honors_output_directory(monkeypatch, tmp_path):
|
|
155
|
+
"""--output must repoint openadapt-ml's TRAINING_OUTPUT."""
|
|
156
|
+
_require_openadapt_ml()
|
|
157
|
+
from openadapt_ml.cloud import local as oa_local
|
|
158
|
+
|
|
159
|
+
monkeypatch.setattr(oa_local, "cmd_serve", lambda args: 0)
|
|
160
|
+
|
|
161
|
+
runner = CliRunner()
|
|
162
|
+
out = tmp_path / "runs"
|
|
163
|
+
result = runner.invoke(cli_main, ["serve", "--output", str(out), "--no-open"])
|
|
164
|
+
assert result.exit_code == 0, result.output
|
|
165
|
+
assert Path(oa_local.TRAINING_OUTPUT) == out
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def test_cmd_serve_reads_only_provided_args():
|
|
169
|
+
"""Every `args.<attr>` cmd_serve reads must be in cli.py's Namespace.
|
|
170
|
+
|
|
171
|
+
This is the direction the contract can silently drift: openadapt-ml
|
|
172
|
+
adds a new required Namespace attribute and cli.py doesn't provide
|
|
173
|
+
it. Parse the installed cmd_serve and check.
|
|
174
|
+
"""
|
|
175
|
+
ml = _require_openadapt_ml()
|
|
176
|
+
local_path = Path(next(iter(ml.__path__))) / "cloud" / "local.py"
|
|
177
|
+
tree = ast.parse(local_path.read_text(encoding="utf-8"))
|
|
178
|
+
cmd_serve = next(
|
|
179
|
+
(
|
|
180
|
+
node
|
|
181
|
+
for node in tree.body
|
|
182
|
+
if isinstance(node, ast.FunctionDef) and node.name == "cmd_serve"
|
|
183
|
+
),
|
|
184
|
+
None,
|
|
185
|
+
)
|
|
186
|
+
assert cmd_serve is not None, "cmd_serve not found in openadapt-ml"
|
|
187
|
+
|
|
188
|
+
args_param = cmd_serve.args.args[0].arg
|
|
189
|
+
read_attrs = {
|
|
190
|
+
node.attr
|
|
191
|
+
for node in ast.walk(cmd_serve)
|
|
192
|
+
if isinstance(node, ast.Attribute)
|
|
193
|
+
and isinstance(node.value, ast.Name)
|
|
194
|
+
and node.value.id == args_param
|
|
195
|
+
}
|
|
196
|
+
missing = read_attrs - SERVE_NAMESPACE_ATTRS
|
|
197
|
+
assert not missing, (
|
|
198
|
+
f"openadapt-ml's cmd_serve reads args attributes "
|
|
199
|
+
f"{sorted(missing)} that openadapt's serve command does not "
|
|
200
|
+
f"provide; update openadapt/cli.py (and SERVE_NAMESPACE_ATTRS)"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_import_error_messages_not_masked(monkeypatch):
|
|
205
|
+
"""Internal ImportErrors must surface the real error, not claim
|
|
206
|
+
openadapt-ml isn't installed."""
|
|
207
|
+
_require_openadapt_ml()
|
|
208
|
+
|
|
209
|
+
import builtins
|
|
210
|
+
|
|
211
|
+
real_import = builtins.__import__
|
|
212
|
+
|
|
213
|
+
def broken_import(name, *args, **kwargs):
|
|
214
|
+
if name == "openadapt_ml.cloud" or name.startswith("openadapt_ml.cloud."):
|
|
215
|
+
raise ImportError(
|
|
216
|
+
"cannot import name 'definitely_phantom' from "
|
|
217
|
+
"'openadapt_ml.cloud.local'"
|
|
218
|
+
)
|
|
219
|
+
return real_import(name, *args, **kwargs)
|
|
220
|
+
|
|
221
|
+
monkeypatch.setattr(builtins, "__import__", broken_import)
|
|
222
|
+
monkeypatch.delitem(sys.modules, "openadapt_ml.cloud.local", raising=False)
|
|
223
|
+
monkeypatch.delitem(sys.modules, "openadapt_ml.cloud", raising=False)
|
|
224
|
+
|
|
225
|
+
runner = CliRunner()
|
|
226
|
+
result = runner.invoke(cli_main, ["serve", "--no-open"])
|
|
227
|
+
assert result.exit_code != 0
|
|
228
|
+
assert "definitely_phantom" in result.output, (
|
|
229
|
+
"The underlying ImportError must appear in the CLI output; "
|
|
230
|
+
f"got: {result.output}"
|
|
231
|
+
)
|