osprey-optimizer 2026.11.0__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.
- osprey_optimizer-2026.11.0/.gitignore +226 -0
- osprey_optimizer-2026.11.0/LICENSE +28 -0
- osprey_optimizer-2026.11.0/PKG-INFO +52 -0
- osprey_optimizer-2026.11.0/README.md +25 -0
- osprey_optimizer-2026.11.0/pyproject.toml +57 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/__init__.py +16 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/_version.py +24 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/__init__.py +12 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/dependencies.py +58 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/environment_ops.py +294 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/job_control.py +416 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/job_status.py +71 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/job_tracker.py +524 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/main.py +289 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/manual_authorization.py +210 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/optimization_lifecycle.py +329 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/optimization_status.py +157 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/owner.py +96 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/__init__.py +0 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/environments.py +218 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/jobs.py +306 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/models.py +64 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/optimization.py +39 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/results.py +245 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/routers/run_config.py +142 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/runner.py +58 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/security.py +53 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/start_gates.py +61 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/api/summary.py +286 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/config/__init__.py +0 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/config/logging.py +38 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/environments/__init__.py +1 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/environments/connector_env.py +413 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/environments/interface.py +404 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/environments/spec.py +231 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/environments/write_authority.py +108 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/events.py +177 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/__init__.py +5 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/api.py +261 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/config.py +254 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/enums.py +98 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/exceptions.py +149 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/process_scope.py +23 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/protocols.py +417 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/state.py +44 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/testing.py +28 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/models/types.py +75 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/__init__.py +1 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/best_point.py +113 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/coercion.py +45 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/evaluation.py +173 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/generators/__init__.py +11 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/generators/baxus.py +631 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/runner.py +354 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/state.py +401 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/surrogate/__init__.py +5 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/surrogate/constructor.py +235 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/surrogate/wrapper.py +162 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/types.py +29 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/optimization/xopt_backend.py +591 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/results.py +601 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/__init__.py +0 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/bounds_resolver.py +167 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/draft_resolution.py +108 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/execution.py +567 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/orchestration.py +286 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/plugin_registry.py +221 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/result_pipeline.py +75 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/services/write_authorization.py +500 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/__init__.py +0 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/cancellation.py +220 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/control.py +35 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/interval_thread.py +78 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/job_keys.py +57 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/json_safe.py +35 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/log_capture.py +64 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/numeric.py +14 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/process.py +88 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/redis_client.py +95 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/redis_state_store.py +149 -0
- osprey_optimizer-2026.11.0/src/osprey_optimizer/utils/serialization.py +24 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Scratch notes (local idea capture)
|
|
2
|
+
scratch/
|
|
3
|
+
|
|
4
|
+
# NFS temporary files
|
|
5
|
+
.nfs*
|
|
6
|
+
|
|
7
|
+
# Byte-compiled / optimized / DLL files
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.py[cod]
|
|
10
|
+
*$py.class
|
|
11
|
+
|
|
12
|
+
# C extensions
|
|
13
|
+
*.so
|
|
14
|
+
|
|
15
|
+
# Distribution / packaging
|
|
16
|
+
.Python
|
|
17
|
+
/build/
|
|
18
|
+
develop-eggs/
|
|
19
|
+
/dist/
|
|
20
|
+
downloads/
|
|
21
|
+
eggs/
|
|
22
|
+
.eggs/
|
|
23
|
+
lib/
|
|
24
|
+
lib64/
|
|
25
|
+
parts/
|
|
26
|
+
sdist/
|
|
27
|
+
var/
|
|
28
|
+
wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
|
|
33
|
+
# PyInstaller
|
|
34
|
+
*.manifest
|
|
35
|
+
*.spec
|
|
36
|
+
|
|
37
|
+
# Installer logs
|
|
38
|
+
pip-log.txt
|
|
39
|
+
pip-delete-this-directory.txt
|
|
40
|
+
|
|
41
|
+
# Unit test / coverage reports
|
|
42
|
+
htmlcov/
|
|
43
|
+
.tox/
|
|
44
|
+
.coverage
|
|
45
|
+
.coverage*
|
|
46
|
+
.cache
|
|
47
|
+
nosetests.xml
|
|
48
|
+
coverage.xml
|
|
49
|
+
coverage.json
|
|
50
|
+
*.cover
|
|
51
|
+
.hypothesis/
|
|
52
|
+
|
|
53
|
+
# CI diagnostics drop (per-worker event logs, stack dumps, container logs).
|
|
54
|
+
# Written by _harness/ci_diagnostics.py and .github/actions/capture-ci-diagnostics
|
|
55
|
+
# whenever OSPREY_CI_DIAG_DIR is set; uploaded as an artifact, never committed.
|
|
56
|
+
/ci-diag/
|
|
57
|
+
.pytest_cache/
|
|
58
|
+
.mypy_cache/
|
|
59
|
+
# The import graph lint-imports (import-linter) caches between runs.
|
|
60
|
+
.import_linter_cache/
|
|
61
|
+
|
|
62
|
+
# Jupyter Notebook
|
|
63
|
+
.ipynb_checkpoints
|
|
64
|
+
|
|
65
|
+
# Environment directories
|
|
66
|
+
.env
|
|
67
|
+
.venv
|
|
68
|
+
env/
|
|
69
|
+
venv/
|
|
70
|
+
ENV/
|
|
71
|
+
env.bak/
|
|
72
|
+
venv.bak/
|
|
73
|
+
|
|
74
|
+
# IDE specific files
|
|
75
|
+
.idea/
|
|
76
|
+
.vscode/
|
|
77
|
+
*.swp
|
|
78
|
+
*.swo
|
|
79
|
+
|
|
80
|
+
# OS specific files
|
|
81
|
+
.DS_Store
|
|
82
|
+
.DS_Store?
|
|
83
|
+
._*
|
|
84
|
+
.Spotlight-V100
|
|
85
|
+
.Trashes
|
|
86
|
+
ehthumbs.db
|
|
87
|
+
Thumbs.db
|
|
88
|
+
|
|
89
|
+
# Data, models, and results
|
|
90
|
+
!data/.gitkeep
|
|
91
|
+
# models/ - Removed this to allow tracking model_config.py
|
|
92
|
+
!models/.gitkeep
|
|
93
|
+
results/
|
|
94
|
+
!results/.gitkeep
|
|
95
|
+
# Any source dir named results/ is SOURCE, not ML output — the broad unanchored
|
|
96
|
+
# results/ ignore above must not swallow it (this negation is deliberately
|
|
97
|
+
# path-independent: pinning it to one package broke when the bluesky-web
|
|
98
|
+
# sidecar moved services/ -> interfaces/, silently dropping the panel from the move).
|
|
99
|
+
!src/**/results/
|
|
100
|
+
# Benchmark model-matrix run exhaust (#259) — regenerable from scripts/benchmark/.
|
|
101
|
+
# All generated artifacts (dashboard.html, results_box/, live_updater.log) live
|
|
102
|
+
# under one output dir co-located with the tooling, keeping the repo root clean.
|
|
103
|
+
scripts/benchmark/_out/
|
|
104
|
+
*.h5
|
|
105
|
+
*.pkl
|
|
106
|
+
*.pt
|
|
107
|
+
*.pth
|
|
108
|
+
*.onnx
|
|
109
|
+
*.mlmodel
|
|
110
|
+
|
|
111
|
+
# Logs
|
|
112
|
+
logs/
|
|
113
|
+
*.log
|
|
114
|
+
!tests/deployment/fixtures/*.log
|
|
115
|
+
tensorboard/
|
|
116
|
+
|
|
117
|
+
# Temporary files
|
|
118
|
+
tmp/
|
|
119
|
+
temp/
|
|
120
|
+
|
|
121
|
+
*.jpg
|
|
122
|
+
*.gif
|
|
123
|
+
*.bmp
|
|
124
|
+
*.tiff
|
|
125
|
+
*.ico
|
|
126
|
+
# The demo template's CANOPY screens ship their images.
|
|
127
|
+
!src/osprey/templates/apps/demo/data/canopy/library/screens/**/images/*.jpg
|
|
128
|
+
|
|
129
|
+
# Landing-page demo video: recorded takes are never committed; the docs build
|
|
130
|
+
# downloads the MP4s from the release manifest.json names. The posters and
|
|
131
|
+
# manifest.json are committed, so the posters must override the `*.jpg` rule.
|
|
132
|
+
docs/demo-video/
|
|
133
|
+
docs/source/_static/demo/*.mp4
|
|
134
|
+
!docs/source/_static/demo/*-poster.jpg
|
|
135
|
+
|
|
136
|
+
# Credentials
|
|
137
|
+
.env
|
|
138
|
+
|
|
139
|
+
delete_me*
|
|
140
|
+
valves.json
|
|
141
|
+
*.code-workspace
|
|
142
|
+
|
|
143
|
+
# Agent data directories
|
|
144
|
+
_agent_data/*
|
|
145
|
+
# Track only the Codex marketplace manifest; never Codex plugin state.
|
|
146
|
+
.agents/*
|
|
147
|
+
!.agents/plugins/
|
|
148
|
+
.agents/plugins/*
|
|
149
|
+
!.agents/plugins/marketplace.json
|
|
150
|
+
|
|
151
|
+
# Local coding-agent guidance (kept out of git; see /CLAUDE.md below)
|
|
152
|
+
AGENTS.md
|
|
153
|
+
|
|
154
|
+
# Sample logbook data (large JSONL files)
|
|
155
|
+
logbook_*.jsonl
|
|
156
|
+
|
|
157
|
+
# Auto-generated documentation
|
|
158
|
+
_autosummary/
|
|
159
|
+
docs/build/
|
|
160
|
+
|
|
161
|
+
# PID files
|
|
162
|
+
*.pid
|
|
163
|
+
|
|
164
|
+
# Development services and applications (keep locally but not in git)
|
|
165
|
+
/.claude
|
|
166
|
+
_ISSUES
|
|
167
|
+
/CLAUDE.md
|
|
168
|
+
.mcp.json
|
|
169
|
+
|
|
170
|
+
# Git worktrees
|
|
171
|
+
.worktrees/
|
|
172
|
+
|
|
173
|
+
# Generated benchmark databases
|
|
174
|
+
data/benchmarks/cross_paradigm/tier*/
|
|
175
|
+
|
|
176
|
+
# OSPREY workspace (runtime data, not tracked — now covered by _agent_data/* above)
|
|
177
|
+
|
|
178
|
+
# Vendor assets (fetched at build time via `osprey vendor fetch`)
|
|
179
|
+
src/osprey/interfaces/artifacts/static/js/vendor/
|
|
180
|
+
src/osprey/interfaces/artifacts/static/css/vendor/
|
|
181
|
+
src/osprey/interfaces/web_terminal/static/vendor/*
|
|
182
|
+
# The dock engine is tracked: vendored from CANOPY's screen runtime at a pinned commit.
|
|
183
|
+
!src/osprey/interfaces/web_terminal/static/vendor/dock-engine.mjs
|
|
184
|
+
!src/osprey/interfaces/web_terminal/static/vendor/dock-engine.d.mts
|
|
185
|
+
src/osprey/interfaces/bluesky_web/panels/bluesky/vendor/
|
|
186
|
+
src/osprey/interfaces/optimizer_web/panels/optimizer/vendor/
|
|
187
|
+
# The okf panel's own vendored marked.min.js is tracked; only DOMPurify is fetched.
|
|
188
|
+
src/osprey/interfaces/okf_panel/static/vendor/purify.min.js
|
|
189
|
+
tests/e2e/claude_code/benchmark_results/
|
|
190
|
+
|
|
191
|
+
# Model files staged by hand for hosts that cannot reach the model host. They
|
|
192
|
+
# reach the qmd sidecar over the read-only mount `services.qmd.models_dir`
|
|
193
|
+
# names, never through a build context — but the staging directory itself can
|
|
194
|
+
# sit anywhere, this tree included. Gigabytes of GGUF, never source — keep them
|
|
195
|
+
# out of git and out of the build (see also the hatch exclude in pyproject.toml)
|
|
196
|
+
**/prefetched-models/
|
|
197
|
+
|
|
198
|
+
# Playwright MCP browser-session cache (page snapshots, console logs)
|
|
199
|
+
.playwright-mcp/
|
|
200
|
+
|
|
201
|
+
# Node.js (dev-only JS toolchain; not part of the Python wheel)
|
|
202
|
+
node_modules/
|
|
203
|
+
|
|
204
|
+
# Working directory gitlab-ci-local writes when the deploy goldens are checked
|
|
205
|
+
# against a real pipeline parser. Created wherever the check is run from.
|
|
206
|
+
.gitlab-ci-local/
|
|
207
|
+
|
|
208
|
+
# Version stamp written by the hatch-vcs build hook. Committing it would recreate
|
|
209
|
+
# the stale-literal problem the git-derived version exists to remove. It is still
|
|
210
|
+
# packaged into the wheel and sdist — the hook registers it as a build artifact.
|
|
211
|
+
src/osprey/_version.py
|
|
212
|
+
packages/osprey-connectors/src/osprey_connectors/_version.py
|
|
213
|
+
packages/osprey-optimizer/src/osprey_optimizer/_version.py
|
|
214
|
+
packages/pyaml-cs-osprey/src/pyaml_cs_osprey/_version.py
|
|
215
|
+
|
|
216
|
+
# feature-scaffolding logs (not committed)
|
|
217
|
+
.claude/.logs/
|
|
218
|
+
|
|
219
|
+
# Process scaffolding — never committed (specs/plans live here uncommitted)
|
|
220
|
+
docs/superpowers/
|
|
221
|
+
|
|
222
|
+
# Locally scaffolded deployment project. Carries a real .env, build output and
|
|
223
|
+
# run data; belongs to the working copy, never to the repo. Anchored to the root
|
|
224
|
+
# so the pattern cannot swallow a same-named path elsewhere in the tree.
|
|
225
|
+
/my-control-assistant/
|
|
226
|
+
/osprey-demo/
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: osprey-optimizer
|
|
3
|
+
Version: 2026.11.0
|
|
4
|
+
Summary: Xopt-driven machine optimization service for OSPREY
|
|
5
|
+
License: BSD-3-Clause
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: osprey-connectors>=2026.11.11
|
|
9
|
+
Requires-Dist: pydantic>=2.12.5
|
|
10
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
11
|
+
Provides-Extra: service
|
|
12
|
+
Requires-Dist: botorch==0.17.2; extra == 'service'
|
|
13
|
+
Requires-Dist: fastapi>=0.141.1; extra == 'service'
|
|
14
|
+
Requires-Dist: gpytorch==1.15.2; extra == 'service'
|
|
15
|
+
Requires-Dist: joblib>=1.5.2; extra == 'service'
|
|
16
|
+
Requires-Dist: numpy>=2.2.6; extra == 'service'
|
|
17
|
+
Requires-Dist: pandas>=2.2.3; extra == 'service'
|
|
18
|
+
Requires-Dist: polars>=2.0.0; extra == 'service'
|
|
19
|
+
Requires-Dist: python-multipart>=0.0.32; extra == 'service'
|
|
20
|
+
Requires-Dist: redis>=5.0.4; extra == 'service'
|
|
21
|
+
Requires-Dist: scikit-learn>=1.8.0; extra == 'service'
|
|
22
|
+
Requires-Dist: starlette; extra == 'service'
|
|
23
|
+
Requires-Dist: torch==2.13.0; extra == 'service'
|
|
24
|
+
Requires-Dist: uvicorn[standard]>=0.52.1; extra == 'service'
|
|
25
|
+
Requires-Dist: xopt==3.1.2; extra == 'service'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# osprey-optimizer
|
|
29
|
+
|
|
30
|
+
The OSPREY optimizer service: Xopt-driven tuning runs against a control
|
|
31
|
+
system, with every write going through an OSPREY connector, so the write
|
|
32
|
+
switch, channel limits and `max_step` apply to each one. An optimization
|
|
33
|
+
environment is a YAML file of setpoint/readback channels and observables;
|
|
34
|
+
Python environments register on the `osprey.optimizer.environments`
|
|
35
|
+
entry-point group and are opt-in: the service loads only those named in
|
|
36
|
+
`OPTIMIZER_PLUGINS` (comma-separated). A plugin must reach the machine through
|
|
37
|
+
`ConnectorInterface`; that is not yet enforced for plugin code.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
pip install osprey-optimizer # models and environment files only
|
|
43
|
+
pip install "osprey-optimizer[service]" # the engine and its HTTP service
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The base install is what the OSPREY framework imports: the request, config
|
|
47
|
+
and status models, and the environment-file format. It does not load the
|
|
48
|
+
search stack. The `service` extra adds Xopt, PyTorch, BoTorch, Redis and
|
|
49
|
+
FastAPI, and is what the optimizer's container image installs. For a
|
|
50
|
+
CPU-only PyTorch, add `--extra-index-url https://download.pytorch.org/whl/cpu`.
|
|
51
|
+
|
|
52
|
+
The service app is `osprey_optimizer.api.main:app`.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# osprey-optimizer
|
|
2
|
+
|
|
3
|
+
The OSPREY optimizer service: Xopt-driven tuning runs against a control
|
|
4
|
+
system, with every write going through an OSPREY connector, so the write
|
|
5
|
+
switch, channel limits and `max_step` apply to each one. An optimization
|
|
6
|
+
environment is a YAML file of setpoint/readback channels and observables;
|
|
7
|
+
Python environments register on the `osprey.optimizer.environments`
|
|
8
|
+
entry-point group and are opt-in: the service loads only those named in
|
|
9
|
+
`OPTIMIZER_PLUGINS` (comma-separated). A plugin must reach the machine through
|
|
10
|
+
`ConnectorInterface`; that is not yet enforced for plugin code.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
pip install osprey-optimizer # models and environment files only
|
|
16
|
+
pip install "osprey-optimizer[service]" # the engine and its HTTP service
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The base install is what the OSPREY framework imports: the request, config
|
|
20
|
+
and status models, and the environment-file format. It does not load the
|
|
21
|
+
search stack. The `service` extra adds Xopt, PyTorch, BoTorch, Redis and
|
|
22
|
+
FastAPI, and is what the optimizer's container image installs. For a
|
|
23
|
+
CPU-only PyTorch, add `--extra-index-url https://download.pytorch.org/whl/cpu`.
|
|
24
|
+
|
|
25
|
+
The service app is `osprey_optimizer.api.main:app`.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "osprey-optimizer"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Xopt-driven machine optimization service for OSPREY"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = {text = "BSD-3-Clause"}
|
|
12
|
+
# The base is the optimizer's contracts: the request, config and status models
|
|
13
|
+
# and the environment-file format. The framework imports these (MCP tool
|
|
14
|
+
# schemas, approval previews, the build-time environment check), so they must
|
|
15
|
+
# load without the search stack below.
|
|
16
|
+
dependencies = [
|
|
17
|
+
"osprey-connectors>=2026.11.11",
|
|
18
|
+
"pydantic>=2.12.5",
|
|
19
|
+
"PyYAML>=6.0.2",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
# The engine and its HTTP service: installed only in the optimizer's own image.
|
|
24
|
+
# Torch and the BoTorch stack are gigabytes. The workspace resolves torch from
|
|
25
|
+
# the CPU wheel index (root pyproject.toml, tool.uv.sources); a pip install from
|
|
26
|
+
# PyPI has to pass that index itself.
|
|
27
|
+
service = [
|
|
28
|
+
"xopt==3.1.2",
|
|
29
|
+
"torch==2.13.0",
|
|
30
|
+
"botorch==0.17.2",
|
|
31
|
+
"gpytorch==1.15.2",
|
|
32
|
+
"polars>=2.0.0",
|
|
33
|
+
"pandas>=2.2.3",
|
|
34
|
+
"numpy>=2.2.6",
|
|
35
|
+
"scikit-learn>=1.8.0",
|
|
36
|
+
"joblib>=1.5.2",
|
|
37
|
+
"redis>=5.0.4",
|
|
38
|
+
"fastapi>=0.141.1",
|
|
39
|
+
"starlette", # imported directly by the app (middleware, responses)
|
|
40
|
+
"uvicorn[standard]>=0.52.1",
|
|
41
|
+
# FastAPI parses the model upload's form body with it and refuses to build
|
|
42
|
+
# that route without it, so the app does not import.
|
|
43
|
+
"python-multipart>=0.0.32",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.hatch.version]
|
|
47
|
+
source = "vcs"
|
|
48
|
+
# Versions with the framework's calendar stream from the same v-tags (unlike
|
|
49
|
+
# osprey-connectors, which has its own osprey-connectors-v* stream): one tag
|
|
50
|
+
# builds the framework and optimizer wheels, and they carry the same number.
|
|
51
|
+
raw-options = { root = "../..", version_scheme = "post-release", git_describe_command = "git describe --dirty --tags --long --abbrev=40 --match v[0-9]*" }
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.hooks.vcs]
|
|
54
|
+
version-file = "src/osprey_optimizer/_version.py"
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/osprey_optimizer"]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Optimizer service: Xopt-driven tuning jobs behind a FastAPI job API.
|
|
2
|
+
|
|
3
|
+
Ported from tuning_scripts at commit 1bac27a1.
|
|
4
|
+
|
|
5
|
+
The base install carries the contracts: ``models`` and ``environments`` load
|
|
6
|
+
with pydantic, PyYAML and osprey-connectors only, and the OSPREY framework
|
|
7
|
+
imports them. The search stack (xopt, torch, botorch, polars, redis, fastapi)
|
|
8
|
+
is the ``service`` extra, installed only in the optimizer's image.
|
|
9
|
+
|
|
10
|
+
Sub-packages:
|
|
11
|
+
- models: request/response models, environment protocols, enums
|
|
12
|
+
- environments: environment files and the connector-driven environment
|
|
13
|
+
- api: FastAPI app, routers, job tracking and control (needs ``service``)
|
|
14
|
+
- optimization: phase runner, evaluator, Xopt backend, custom generators
|
|
15
|
+
- services: execution and orchestration inside the job worker
|
|
16
|
+
"""
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '2026.11.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2026, 11, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""The optimizer's HTTP service. Needs the ``service`` extra."""
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
|
|
5
|
+
_SERVICE_ROOTS = ("fastapi", "redis", "polars", "xopt", "torch")
|
|
6
|
+
|
|
7
|
+
_missing = [name for name in _SERVICE_ROOTS if importlib.util.find_spec(name) is None]
|
|
8
|
+
if _missing:
|
|
9
|
+
raise ImportError(
|
|
10
|
+
f"osprey_optimizer.api needs the optimizer's service extra (missing: {', '.join(_missing)}). "
|
|
11
|
+
'Install it with: pip install "osprey-optimizer[service]"'
|
|
12
|
+
)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""FastAPI dependency callables for shared singletons.
|
|
2
|
+
|
|
3
|
+
Each function reads from ``request.app.state``, which is populated by the
|
|
4
|
+
lifespan handler in ``main.py``. Use them with ``Depends()`` in endpoint
|
|
5
|
+
signatures so that routers stay decoupled from initialization logic.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from fastapi import Depends, Query, Request
|
|
12
|
+
|
|
13
|
+
from osprey_optimizer.api.job_status import load_job_meta
|
|
14
|
+
from osprey_optimizer.api.job_tracker import JobMeta, JobTracker
|
|
15
|
+
from osprey_optimizer.models.config import ControlTarget, ExecutionMode, machine_config
|
|
16
|
+
from osprey_optimizer.services.plugin_registry import EnvironmentRegistry
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_job_tracker(request: Request) -> JobTracker:
|
|
20
|
+
return request.app.state.job_tracker # type: ignore[no-any-return]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def require_job_meta(job_id: str, tracker: JobTracker = Depends(get_job_tracker)) -> JobMeta:
|
|
24
|
+
"""Resolve the path job's metadata once (404 if unknown, 500 if corrupt).
|
|
25
|
+
|
|
26
|
+
Endpoints under ``/jobs/{job_id}`` inject this instead of re-checking
|
|
27
|
+
existence and re-reading the record: FastAPI caches it for the request, so
|
|
28
|
+
the type/creation-time checks they used to make one call each now share a
|
|
29
|
+
single Redis read.
|
|
30
|
+
"""
|
|
31
|
+
return load_job_meta(tracker, job_id)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_environment_registry(request: Request) -> EnvironmentRegistry:
|
|
35
|
+
return request.app.state.environment_registry # type: ignore[no-any-return]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass(frozen=True)
|
|
39
|
+
class Machine:
|
|
40
|
+
"""The machine a request reaches, as the request named it."""
|
|
41
|
+
|
|
42
|
+
target: ControlTarget
|
|
43
|
+
execution_mode: ExecutionMode | None = None
|
|
44
|
+
|
|
45
|
+
def env_config(self) -> dict[str, Any]:
|
|
46
|
+
return machine_config(self.target, self.execution_mode)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def require_machine(
|
|
50
|
+
target: ControlTarget = Query(
|
|
51
|
+
description="The machine this call reaches: va, standin or live. No default."
|
|
52
|
+
),
|
|
53
|
+
execution_mode: ExecutionMode | None = Query(
|
|
54
|
+
default=None, description="readonly: reads only; every write is refused."
|
|
55
|
+
),
|
|
56
|
+
) -> Machine:
|
|
57
|
+
"""Every endpoint that reaches a machine names it; there is no ambient target."""
|
|
58
|
+
return Machine(target=target, execution_mode=execution_mode)
|