ivoryos 1.3.2__tar.gz → 1.4.6__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.
Files changed (140) hide show
  1. {ivoryos-1.3.2/ivoryos.egg-info → ivoryos-1.4.6}/PKG-INFO +108 -47
  2. ivoryos-1.3.2/PKG-INFO → ivoryos-1.4.6/README.md +89 -67
  3. ivoryos-1.4.6/docs/source/conf.py +84 -0
  4. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/__init__.py +6 -2
  5. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/app.py +31 -6
  6. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/optimizer/ax_optimizer.py +55 -28
  7. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/optimizer/base_optimizer.py +20 -1
  8. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/optimizer/baybe_optimizer.py +27 -17
  9. ivoryos-1.4.6/ivoryos/optimizer/nimo_optimizer.py +173 -0
  10. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/optimizer/registry.py +3 -1
  11. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/auth/auth.py +26 -1
  12. ivoryos-1.4.6/ivoryos/routes/auth/templates/change_password.html +32 -0
  13. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/control.py +2 -2
  14. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/control_new_device.py +21 -11
  15. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/data/data.py +27 -9
  16. ivoryos-1.4.6/ivoryos/routes/data/templates/components/step_card.html +78 -0
  17. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/data/templates/workflow_view.html +14 -5
  18. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/design.py +46 -4
  19. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/design_step.py +40 -14
  20. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/canvas_main.html +6 -1
  21. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/edit_action_form.html +18 -3
  22. ivoryos-1.4.6/ivoryos/routes/design/templates/components/info_modal.html +318 -0
  23. ivoryos-1.4.6/ivoryos/routes/design/templates/components/python_code_overlay.html +56 -0
  24. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/experiment_builder.html +3 -0
  25. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/execute.py +76 -20
  26. ivoryos-1.4.6/ivoryos/routes/execute/templates/components/logging_panel.html +56 -0
  27. ivoryos-1.4.6/ivoryos/routes/execute/templates/components/run_tabs.html +60 -0
  28. ivoryos-1.4.6/ivoryos/routes/execute/templates/components/tab_bayesian.html +520 -0
  29. ivoryos-1.4.6/ivoryos/routes/execute/templates/components/tab_configuration.html +383 -0
  30. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/templates/components/tab_repeat.html +6 -2
  31. ivoryos-1.4.6/ivoryos/routes/execute/templates/experiment_run.html +30 -0
  32. ivoryos-1.4.6/ivoryos/routes/main/main.py +70 -0
  33. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/server.py +35 -23
  34. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/socket_handlers.py +1 -1
  35. ivoryos-1.4.6/ivoryos/static/ivoryos_logo.png +0 -0
  36. ivoryos-1.4.6/ivoryos/static/js/action_handlers.js +378 -0
  37. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/sortable_design.js +1 -0
  38. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/ui_state.js +1 -3
  39. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/templates/base.html +61 -2
  40. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/bo_campaign.py +18 -17
  41. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/client_proxy.py +11 -6
  42. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/db_models.py +204 -49
  43. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/decorators.py +1 -0
  44. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/form.py +40 -16
  45. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/global_config.py +11 -0
  46. ivoryos-1.4.6/ivoryos/utils/nest_script.py +314 -0
  47. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/py_to_json.py +54 -10
  48. ivoryos-1.4.6/ivoryos/utils/script_runner.py +770 -0
  49. ivoryos-1.4.6/ivoryos/utils/task_runner.py +131 -0
  50. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/utils.py +24 -3
  51. ivoryos-1.4.6/ivoryos/version.py +1 -0
  52. ivoryos-1.4.6/ivoryos.egg-info/PKG-INFO +262 -0
  53. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos.egg-info/SOURCES.txt +18 -2
  54. ivoryos-1.4.6/ivoryos.egg-info/requires.txt +35 -0
  55. ivoryos-1.4.6/ivoryos.egg-info/top_level.txt +4 -0
  56. {ivoryos-1.3.2 → ivoryos-1.4.6}/pyproject.toml +18 -1
  57. ivoryos-1.4.6/tests/__init__.py +0 -0
  58. ivoryos-1.4.6/tests/conftest.py +133 -0
  59. ivoryos-1.4.6/tests/integration/__init__.py +0 -0
  60. ivoryos-1.4.6/tests/integration/test_route_auth.py +80 -0
  61. ivoryos-1.4.6/tests/integration/test_route_control.py +94 -0
  62. ivoryos-1.4.6/tests/integration/test_route_database.py +61 -0
  63. ivoryos-1.4.6/tests/integration/test_route_design.py +36 -0
  64. ivoryos-1.4.6/tests/integration/test_route_main.py +35 -0
  65. ivoryos-1.4.6/tests/integration/test_sockets.py +26 -0
  66. ivoryos-1.4.6/tests/unit/test_type_conversion.py +42 -0
  67. ivoryos-1.4.6/tests/unit/test_util.py +3 -0
  68. ivoryos-1.3.2/README.md +0 -177
  69. ivoryos-1.3.2/ivoryos/routes/api/api.py +0 -57
  70. ivoryos-1.3.2/ivoryos/routes/data/templates/components/step_card.html +0 -42
  71. ivoryos-1.3.2/ivoryos/routes/design/templates/components/python_code_overlay.html +0 -39
  72. ivoryos-1.3.2/ivoryos/routes/execute/templates/components/logging_panel.html +0 -31
  73. ivoryos-1.3.2/ivoryos/routes/execute/templates/components/run_tabs.html +0 -17
  74. ivoryos-1.3.2/ivoryos/routes/execute/templates/components/tab_bayesian.html +0 -398
  75. ivoryos-1.3.2/ivoryos/routes/execute/templates/components/tab_configuration.html +0 -98
  76. ivoryos-1.3.2/ivoryos/routes/execute/templates/experiment_run.html +0 -294
  77. ivoryos-1.3.2/ivoryos/routes/main/main.py +0 -42
  78. ivoryos-1.3.2/ivoryos/static/js/action_handlers.js +0 -213
  79. ivoryos-1.3.2/ivoryos/utils/script_runner.py +0 -460
  80. ivoryos-1.3.2/ivoryos/utils/task_runner.py +0 -89
  81. ivoryos-1.3.2/ivoryos/version.py +0 -1
  82. ivoryos-1.3.2/ivoryos.egg-info/requires.txt +0 -15
  83. ivoryos-1.3.2/ivoryos.egg-info/top_level.txt +0 -1
  84. {ivoryos-1.3.2 → ivoryos-1.4.6}/LICENSE +0 -0
  85. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/config.py +0 -0
  86. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/__init__.py +0 -0
  87. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/auth/__init__.py +0 -0
  88. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/auth/templates/login.html +0 -0
  89. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/auth/templates/signup.html +0 -0
  90. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/__init__.py +0 -0
  91. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/control_file.py +0 -0
  92. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/templates/controllers.html +0 -0
  93. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/templates/controllers_new.html +0 -0
  94. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/control/utils.py +0 -0
  95. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/data/__init__.py +0 -0
  96. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/data/templates/workflow_database.html +0 -0
  97. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/__init__.py +0 -0
  98. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/design_file.py +0 -0
  99. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/action_form.html +0 -0
  100. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/actions_panel.html +0 -0
  101. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/autofill_toggle.html +0 -0
  102. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/canvas.html +0 -0
  103. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/canvas_footer.html +0 -0
  104. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/canvas_header.html +0 -0
  105. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/deck_selector.html +0 -0
  106. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/instruments_panel.html +0 -0
  107. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals/drop_modal.html +0 -0
  108. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals/json_modal.html +0 -0
  109. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals/new_script_modal.html +0 -0
  110. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals/rename_modal.html +0 -0
  111. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals/saveas_modal.html +0 -0
  112. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/modals.html +0 -0
  113. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/sidebar.html +0 -0
  114. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/design/templates/components/text_to_code_panel.html +0 -0
  115. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/__init__.py +0 -0
  116. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/execute_file.py +0 -0
  117. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/templates/components/error_modal.html +0 -0
  118. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/templates/components/progress_panel.html +0 -0
  119. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/execute/templates/components/run_panel.html +0 -0
  120. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/library/__init__.py +0 -0
  121. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/library/library.py +0 -0
  122. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/library/templates/library.html +0 -0
  123. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/main/__init__.py +0 -0
  124. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/main/templates/help.html +0 -0
  125. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/routes/main/templates/home.html +0 -0
  126. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/favicon.ico +0 -0
  127. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/gui_annotation/Slide1.png +0 -0
  128. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
  129. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/db_delete.js +0 -0
  130. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/overlay.js +0 -0
  131. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/script_metadata.js +0 -0
  132. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/socket_handler.js +0 -0
  133. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/js/sortable_card.js +0 -0
  134. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/logo.webp +0 -0
  135. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/static/style.css +0 -0
  136. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/__init__.py +0 -0
  137. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/llm_agent.py +0 -0
  138. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos/utils/serilize.py +0 -0
  139. {ivoryos-1.3.2 → ivoryos-1.4.6}/ivoryos.egg-info/dependency_links.txt +0 -0
  140. {ivoryos-1.3.2 → ivoryos-1.4.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ivoryos
3
- Version: 1.3.2
3
+ Version: 1.4.6
4
4
  Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
5
5
  Author-email: Ivory Zhang <ivoryzhang@chem.ubc.ca>
6
6
  License: MIT
@@ -9,6 +9,7 @@ Requires-Python: >=3.7
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
11
  Requires-Dist: bcrypt
12
+ Requires-Dist: Flask[async]
12
13
  Requires-Dist: Flask-Login
13
14
  Requires-Dist: Flask-Session
14
15
  Requires-Dist: Flask-SocketIO
@@ -16,10 +17,24 @@ Requires-Dist: Flask-SQLAlchemy
16
17
  Requires-Dist: Flask-WTF
17
18
  Requires-Dist: SQLAlchemy-Utils
18
19
  Requires-Dist: python-dotenv
20
+ Requires-Dist: pandas
19
21
  Requires-Dist: astor; python_version < "3.9"
20
- Provides-Extra: optimizer
21
- Requires-Dist: ax-platform; extra == "optimizer"
22
- Requires-Dist: baybe; extra == "optimizer"
22
+ Provides-Extra: optimizer-ax
23
+ Requires-Dist: ax-platform; extra == "optimizer-ax"
24
+ Provides-Extra: optimizer-baybe
25
+ Requires-Dist: baybe; extra == "optimizer-baybe"
26
+ Provides-Extra: optimizer-nimo
27
+ Requires-Dist: nimo; extra == "optimizer-nimo"
28
+ Provides-Extra: optimizers
29
+ Requires-Dist: ax-platform>=1.1.2; extra == "optimizers"
30
+ Requires-Dist: baybe>=0.14.0; extra == "optimizers"
31
+ Requires-Dist: nimo; extra == "optimizers"
32
+ Provides-Extra: doc
33
+ Requires-Dist: sphinx; extra == "doc"
34
+ Requires-Dist: sphinx-rtd-theme; extra == "doc"
35
+ Requires-Dist: sphinxcontrib-httpdomain; extra == "doc"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest; extra == "dev"
23
38
  Dynamic: license-file
24
39
 
25
40
  [![Documentation Status](https://readthedocs.org/projects/ivoryos/badge/?version=latest)](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
@@ -28,33 +43,35 @@ Dynamic: license-file
28
43
  [![YouTube](https://img.shields.io/badge/YouTube-tutorial-red?logo=youtube)](https://youtu.be/dFfJv9I2-1g)
29
44
  [![YouTube](https://img.shields.io/badge/YouTube-demo-red?logo=youtube)](https://youtu.be/flr5ydiE96s)
30
45
  [![Published](https://img.shields.io/badge/Nature_Comm.-paper-blue)](https://www.nature.com/articles/s41467-025-60514-w)
31
- [![Discord](https://img.shields.io/discord/1313641159356059770?label=Discord&logo=discord&color=5865F2)](https://discord.gg/AX5P9EdGVX)
46
+ [![Community](https://img.shields.io/discord/1313641159356059770?label=Discord&logo=discord&color=5865F2)](https://discord.gg/AX5P9EdGVX)
32
47
 
33
- ![](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/ivoryos.png)
34
- # ivoryOS: interoperable Web UI for self-driving laboratories (SDLs)
35
- A **plug-and-play** web interface for flexible SDLs
48
+ ![ivoryos_logo.png](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/ivoryos_logo.png)
49
+
50
+ # [IvoryOS](https://ivoryos.ai): interoperable orchestrator for self-driving laboratories (SDLs)
51
+
52
+ A **plug-and-play** web interface for flexible, modular SDLs —
53
+ you focus on developing protocols, IvoryOS handles the rest.
54
+
55
+ ![code_launch_design.png](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/code_launch_design.png)
36
56
 
37
57
  ---
38
58
 
39
59
  ## Table of Contents
40
- - [Description](#description)
60
+ - [What IvoryOS does](#what-ivoryos-does)
41
61
  - [System requirements](#system-requirements)
42
62
  - [Installation](#installation)
43
- - [Quick Start](#quick-start)
44
63
  - [Features](#features)
45
64
  - [Demo](#demo)
46
65
  - [Roadmap](#roadmap)
66
+ - [Contributing](#contributing)
47
67
  - [Acknowledgements](#acknowledgements)
48
68
 
49
69
  ---
50
- ## Description
51
- Building UIs for SDLs is challenging because flexibility and modularity make them unpredictable yet accessibility is essential for **democratisation** of AI-driven scientific discovery.
52
-
53
- **IvoryOS** bridges the gap by:
54
- - Dynamically inspecting initialized Python modules (hardware APIs, high-level functions, or workflows)
55
- - Automatically displaying functions and parameters in a web UI
56
- - Allowing users to **design**, **manage**, and **execute** experimental workflows with minimal changes to existing scripts
57
- - Providing natural language support for workflow design and execution, check [IvoryOS MCP](https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp) for more details.
70
+ ## What IvoryOS Does
71
+ - Turns Python modules into UIs by dynamically inspecting your hardware APIs, functions, and workflows.
72
+ - Standardizes optimization inputs/outputs, making any optimizer plug-and-play.
73
+ - Provides a visual workflow builder for designing and running experiments.
74
+ - Adds natural-language control for creating and executing workflows, see [IvoryOS MCP](https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp) for more details.
58
75
 
59
76
  ----
60
77
  ## System Requirements
@@ -76,10 +93,13 @@ Building UIs for SDLs is challenging because flexibility and modularity make the
76
93
  - SQLAlchemy-Utils~=0.41
77
94
  - Flask-WTF~=1.2
78
95
  - python-dotenv==1.0.1
96
+ - pandas
79
97
 
80
98
  **Optional:**
81
- - ax-platform (≥1.0, Python≥3.10)
82
- - baybe
99
+ - ax-platform==1.1.2
100
+ - baybe==0.14.0
101
+ - nimo
102
+ - slack-sdk
83
103
  </details>
84
104
 
85
105
  ---
@@ -90,22 +110,31 @@ From PyPI:
90
110
  ```bash
91
111
  pip install ivoryos
92
112
  ```
93
- From source:
94
- ```bash
95
- git clone https://gitlab.com/heingroup/ivoryos.git
96
- cd ivoryos
97
- pip install -e .
98
- ```
113
+
114
+ [//]: # (From source:)
115
+
116
+ [//]: # (```bash)
117
+
118
+ [//]: # (git clone https://gitlab.com/heingroup/ivoryos.git)
119
+
120
+ [//]: # (cd ivoryos)
121
+
122
+ [//]: # (pip install -e .)
123
+
124
+ [//]: # (```)
99
125
 
100
126
 
101
127
  ## Quick start
102
- In your SDL script,
128
+ In your script, where you initialize or import your robot:
103
129
  ```python
130
+ my_robot = Robot()
131
+
104
132
  import ivoryos
105
133
 
106
134
  ivoryos.run(__name__)
107
135
  ```
108
- Login: Create an account (local DB, bcrypt password)
136
+ Then run the script and visit `http://localhost:8000` in your browser.
137
+ Use `admin` for both username and password, and start building workflows!
109
138
 
110
139
  ----
111
140
  ## Features
@@ -127,42 +156,72 @@ Add single or multiple loggers:
127
156
  ivoryos.run(__name__, logger="logger name")
128
157
  ivoryos.run(__name__, logger=["logger 1", "logger 2"])
129
158
  ```
159
+ ### Human-in-the-loop
160
+ Use `pause` in flow control to pause the workflow and send a notification with custom message handler(s).
161
+ When run into `pause`, it will pause, send a message, and wait for human's response. Example of a Slack bot:
162
+ ```python
163
+
164
+ def slack_bot(msg: str = "Hi"):
165
+ """
166
+ a function that can be used as a notification handler function("msg")
167
+ :param msg: message to send
168
+ """
169
+ from slack_sdk import WebClient
170
+
171
+ slack_token = "your slack token"
172
+ client = WebClient(token=slack_token)
173
+
174
+ my_user_id = "your user id" # replace with your actual Slack user ID
175
+
176
+ client.chat_postMessage(channel=my_user_id, text=msg)
177
+
178
+ import ivoryos
179
+ ivoryos.run(__name__, notification_handler=slack_bot)
180
+ ```
181
+
130
182
  ### Directory Structure
131
183
 
132
- Created automatically on first run:
184
+ Created automatically in the same working directory on the first run:
185
+ <details>
186
+ <summary>click to see the data folder structure</summary>
187
+
133
188
  - **`ivoryos_data/`**:
134
- - **`ivoryos_data/config_csv/`**: Batch configuration `csv`
135
- - **`ivoryos_data/pseudo_deck/`**: Offline deck `.pkl`
136
- - **`ivoryos_data/results/`**: Execution results
137
- - **`ivoryos_data/scripts/`**: Compiled workflows Python scripts
138
- - **`default.log`**: Application logs
139
- - **`ivoryos.db`**: Local database
189
+ - **`config_csv/`**: Batch configuration `csv`
190
+ - **`pseudo_deck/`**: Offline deck `.pkl`
191
+ - **`results/`**: Execution results
192
+ - **`scripts/`**: Compiled workflows Python scripts
193
+ - **`default.log`**: Application logs
194
+ - **`ivoryos.db`**: Local database
195
+ </details>
196
+
140
197
  ---
141
- ## Demo
142
- In the [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/example/abstract_sdl_example/abstract_sdl.py)
143
- ```Python
144
- ivoryos.run(__name__)
145
- ```
146
198
 
147
- * Running on all addresses (0.0.0.0)
148
- * Running on http://127.0.0.1:8000
149
- * Running on http://0.0.0.0:8000
199
+ ## Demo
200
+ Online demo at [demo.ivoryos.ai](https://demo.ivoryos.ai).
201
+ Local version in [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/community/examples/abstract_sdl_example/abstract_sdl.py)
150
202
 
151
203
  ---
152
204
 
153
205
  ## Roadmap
154
206
 
155
- - [x] Allow plugin pages ✅
156
- - [x] pause, resume, abort current and pending workflows ✅
157
207
  - [ ] dropdown input
158
208
  - [ ] snapshot version control
159
- - [ ] optimizer-agnostic
160
209
  - [ ] check batch-config file compatibility
161
210
 
162
211
  ---
163
212
 
213
+ ## Contributing
214
+
215
+ We welcome all contributions — from core improvements to new drivers, plugins, and real-world use cases.
216
+ See `CONTRIBUTING.md` for details and let us know you're interested: https://forms.gle/fPSvw5LEGrweUQUH8
217
+
218
+ ---
219
+
164
220
  ## Citing
165
221
 
222
+ <details>
223
+ <summary>Click to see citations</summary>
224
+
166
225
  If you find this project useful, please consider citing the following manuscript:
167
226
 
168
227
  > Zhang, W., Hao, L., Lai, V. et al. [IvoryOS: an interoperable web interface for orchestrating Python-based self-driving laboratories.](https://www.nature.com/articles/s41467-025-60514-w) Nat Commun 16, 5182 (2025).
@@ -196,6 +255,8 @@ For an additional perspective related to the development of the tool, please see
196
255
  url = {https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery}
197
256
  }
198
257
  ```
258
+ </details>
259
+
199
260
  ---
200
261
  ## Acknowledgements
201
- Authors acknowledge Telescope Innovations Corp., Hein Lab members for their valuable suggestions and contributions.
262
+ Authors acknowledge Telescope Innovations Corp., UBC Hein Lab, and Acceleration Consortium members for their valuable suggestions and contributions.
@@ -1,60 +1,38 @@
1
- Metadata-Version: 2.4
2
- Name: ivoryos
3
- Version: 1.3.2
4
- Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
5
- Author-email: Ivory Zhang <ivoryzhang@chem.ubc.ca>
6
- License: MIT
7
- Project-URL: Homepage, https://gitlab.com/heingroup/ivoryos
8
- Requires-Python: >=3.7
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: bcrypt
12
- Requires-Dist: Flask-Login
13
- Requires-Dist: Flask-Session
14
- Requires-Dist: Flask-SocketIO
15
- Requires-Dist: Flask-SQLAlchemy
16
- Requires-Dist: Flask-WTF
17
- Requires-Dist: SQLAlchemy-Utils
18
- Requires-Dist: python-dotenv
19
- Requires-Dist: astor; python_version < "3.9"
20
- Provides-Extra: optimizer
21
- Requires-Dist: ax-platform; extra == "optimizer"
22
- Requires-Dist: baybe; extra == "optimizer"
23
- Dynamic: license-file
24
-
25
1
  [![Documentation Status](https://readthedocs.org/projects/ivoryos/badge/?version=latest)](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
26
2
  [![PyPI version](https://img.shields.io/pypi/v/ivoryos)](https://pypi.org/project/ivoryos/)
27
3
  ![License](https://img.shields.io/pypi/l/ivoryos)
28
4
  [![YouTube](https://img.shields.io/badge/YouTube-tutorial-red?logo=youtube)](https://youtu.be/dFfJv9I2-1g)
29
5
  [![YouTube](https://img.shields.io/badge/YouTube-demo-red?logo=youtube)](https://youtu.be/flr5ydiE96s)
30
6
  [![Published](https://img.shields.io/badge/Nature_Comm.-paper-blue)](https://www.nature.com/articles/s41467-025-60514-w)
31
- [![Discord](https://img.shields.io/discord/1313641159356059770?label=Discord&logo=discord&color=5865F2)](https://discord.gg/AX5P9EdGVX)
7
+ [![Community](https://img.shields.io/discord/1313641159356059770?label=Discord&logo=discord&color=5865F2)](https://discord.gg/AX5P9EdGVX)
8
+
9
+ ![ivoryos_logo.png](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/ivoryos_logo.png)
10
+
11
+ # [IvoryOS](https://ivoryos.ai): interoperable orchestrator for self-driving laboratories (SDLs)
32
12
 
33
- ![](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/ivoryos.png)
34
- # ivoryOS: interoperable Web UI for self-driving laboratories (SDLs)
35
- A **plug-and-play** web interface for flexible SDLs
13
+ A **plug-and-play** web interface for flexible, modular SDLs —
14
+ you focus on developing protocols, IvoryOS handles the rest.
15
+
16
+ ![code_launch_design.png](https://gitlab.com/heingroup/ivoryos/raw/main/docs/source/_static/code_launch_design.png)
36
17
 
37
18
  ---
38
19
 
39
20
  ## Table of Contents
40
- - [Description](#description)
21
+ - [What IvoryOS does](#what-ivoryos-does)
41
22
  - [System requirements](#system-requirements)
42
23
  - [Installation](#installation)
43
- - [Quick Start](#quick-start)
44
24
  - [Features](#features)
45
25
  - [Demo](#demo)
46
26
  - [Roadmap](#roadmap)
27
+ - [Contributing](#contributing)
47
28
  - [Acknowledgements](#acknowledgements)
48
29
 
49
30
  ---
50
- ## Description
51
- Building UIs for SDLs is challenging because flexibility and modularity make them unpredictable yet accessibility is essential for **democratisation** of AI-driven scientific discovery.
52
-
53
- **IvoryOS** bridges the gap by:
54
- - Dynamically inspecting initialized Python modules (hardware APIs, high-level functions, or workflows)
55
- - Automatically displaying functions and parameters in a web UI
56
- - Allowing users to **design**, **manage**, and **execute** experimental workflows with minimal changes to existing scripts
57
- - Providing natural language support for workflow design and execution, check [IvoryOS MCP](https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp) for more details.
31
+ ## What IvoryOS Does
32
+ - Turns Python modules into UIs by dynamically inspecting your hardware APIs, functions, and workflows.
33
+ - Standardizes optimization inputs/outputs, making any optimizer plug-and-play.
34
+ - Provides a visual workflow builder for designing and running experiments.
35
+ - Adds natural-language control for creating and executing workflows, see [IvoryOS MCP](https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp) for more details.
58
36
 
59
37
  ----
60
38
  ## System Requirements
@@ -76,10 +54,13 @@ Building UIs for SDLs is challenging because flexibility and modularity make the
76
54
  - SQLAlchemy-Utils~=0.41
77
55
  - Flask-WTF~=1.2
78
56
  - python-dotenv==1.0.1
57
+ - pandas
79
58
 
80
59
  **Optional:**
81
- - ax-platform (≥1.0, Python≥3.10)
82
- - baybe
60
+ - ax-platform==1.1.2
61
+ - baybe==0.14.0
62
+ - nimo
63
+ - slack-sdk
83
64
  </details>
84
65
 
85
66
  ---
@@ -90,22 +71,31 @@ From PyPI:
90
71
  ```bash
91
72
  pip install ivoryos
92
73
  ```
93
- From source:
94
- ```bash
95
- git clone https://gitlab.com/heingroup/ivoryos.git
96
- cd ivoryos
97
- pip install -e .
98
- ```
74
+
75
+ [//]: # (From source:)
76
+
77
+ [//]: # (```bash)
78
+
79
+ [//]: # (git clone https://gitlab.com/heingroup/ivoryos.git)
80
+
81
+ [//]: # (cd ivoryos)
82
+
83
+ [//]: # (pip install -e .)
84
+
85
+ [//]: # (```)
99
86
 
100
87
 
101
88
  ## Quick start
102
- In your SDL script,
89
+ In your script, where you initialize or import your robot:
103
90
  ```python
91
+ my_robot = Robot()
92
+
104
93
  import ivoryos
105
94
 
106
95
  ivoryos.run(__name__)
107
96
  ```
108
- Login: Create an account (local DB, bcrypt password)
97
+ Then run the script and visit `http://localhost:8000` in your browser.
98
+ Use `admin` for both username and password, and start building workflows!
109
99
 
110
100
  ----
111
101
  ## Features
@@ -127,42 +117,72 @@ Add single or multiple loggers:
127
117
  ivoryos.run(__name__, logger="logger name")
128
118
  ivoryos.run(__name__, logger=["logger 1", "logger 2"])
129
119
  ```
120
+ ### Human-in-the-loop
121
+ Use `pause` in flow control to pause the workflow and send a notification with custom message handler(s).
122
+ When run into `pause`, it will pause, send a message, and wait for human's response. Example of a Slack bot:
123
+ ```python
124
+
125
+ def slack_bot(msg: str = "Hi"):
126
+ """
127
+ a function that can be used as a notification handler function("msg")
128
+ :param msg: message to send
129
+ """
130
+ from slack_sdk import WebClient
131
+
132
+ slack_token = "your slack token"
133
+ client = WebClient(token=slack_token)
134
+
135
+ my_user_id = "your user id" # replace with your actual Slack user ID
136
+
137
+ client.chat_postMessage(channel=my_user_id, text=msg)
138
+
139
+ import ivoryos
140
+ ivoryos.run(__name__, notification_handler=slack_bot)
141
+ ```
142
+
130
143
  ### Directory Structure
131
144
 
132
- Created automatically on first run:
145
+ Created automatically in the same working directory on the first run:
146
+ <details>
147
+ <summary>click to see the data folder structure</summary>
148
+
133
149
  - **`ivoryos_data/`**:
134
- - **`ivoryos_data/config_csv/`**: Batch configuration `csv`
135
- - **`ivoryos_data/pseudo_deck/`**: Offline deck `.pkl`
136
- - **`ivoryos_data/results/`**: Execution results
137
- - **`ivoryos_data/scripts/`**: Compiled workflows Python scripts
138
- - **`default.log`**: Application logs
139
- - **`ivoryos.db`**: Local database
150
+ - **`config_csv/`**: Batch configuration `csv`
151
+ - **`pseudo_deck/`**: Offline deck `.pkl`
152
+ - **`results/`**: Execution results
153
+ - **`scripts/`**: Compiled workflows Python scripts
154
+ - **`default.log`**: Application logs
155
+ - **`ivoryos.db`**: Local database
156
+ </details>
157
+
140
158
  ---
141
- ## Demo
142
- In the [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/example/abstract_sdl_example/abstract_sdl.py)
143
- ```Python
144
- ivoryos.run(__name__)
145
- ```
146
159
 
147
- * Running on all addresses (0.0.0.0)
148
- * Running on http://127.0.0.1:8000
149
- * Running on http://0.0.0.0:8000
160
+ ## Demo
161
+ Online demo at [demo.ivoryos.ai](https://demo.ivoryos.ai).
162
+ Local version in [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/community/examples/abstract_sdl_example/abstract_sdl.py)
150
163
 
151
164
  ---
152
165
 
153
166
  ## Roadmap
154
167
 
155
- - [x] Allow plugin pages ✅
156
- - [x] pause, resume, abort current and pending workflows ✅
157
168
  - [ ] dropdown input
158
169
  - [ ] snapshot version control
159
- - [ ] optimizer-agnostic
160
170
  - [ ] check batch-config file compatibility
161
171
 
162
172
  ---
163
173
 
174
+ ## Contributing
175
+
176
+ We welcome all contributions — from core improvements to new drivers, plugins, and real-world use cases.
177
+ See `CONTRIBUTING.md` for details and let us know you're interested: https://forms.gle/fPSvw5LEGrweUQUH8
178
+
179
+ ---
180
+
164
181
  ## Citing
165
182
 
183
+ <details>
184
+ <summary>Click to see citations</summary>
185
+
166
186
  If you find this project useful, please consider citing the following manuscript:
167
187
 
168
188
  > Zhang, W., Hao, L., Lai, V. et al. [IvoryOS: an interoperable web interface for orchestrating Python-based self-driving laboratories.](https://www.nature.com/articles/s41467-025-60514-w) Nat Commun 16, 5182 (2025).
@@ -196,6 +216,8 @@ For an additional perspective related to the development of the tool, please see
196
216
  url = {https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery}
197
217
  }
198
218
  ```
219
+ </details>
220
+
199
221
  ---
200
222
  ## Acknowledgements
201
- Authors acknowledge Telescope Innovations Corp., Hein Lab members for their valuable suggestions and contributions.
223
+ Authors acknowledge Telescope Innovations Corp., UBC Hein Lab, and Acceleration Consortium members for their valuable suggestions and contributions.
@@ -0,0 +1,84 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ import os
3
+ import sys
4
+ import urllib
5
+
6
+ import requests
7
+
8
+ # -- General configuration
9
+ sys.path.insert(0, os.path.abspath('../../'))
10
+ from ivoryos.version import __version__
11
+
12
+
13
+ # appending suite readme.rst to doc
14
+
15
+ external_readme = [
16
+ {
17
+ "name": 'plugin.rst',
18
+ "url": "https://gitlab.com/heingroup/ivoryos-suite/ivoryos-plugin-template/-/raw/main/README.rst"
19
+ },
20
+ {
21
+ "name": 'client.rst',
22
+ "url": "https://gitlab.com/heingroup/ivoryos-suite/ivoryos-client/-/raw/main/README.rst"
23
+ },
24
+ {
25
+ "name": 'mcp.rst',
26
+ "url": "https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp/-/raw/main/README.rst"
27
+ }
28
+ ]
29
+
30
+ for item in external_readme:
31
+ readme_url = item['url']
32
+ name = item['name']
33
+ output_path = os.path.join(os.path.dirname(__file__), name)
34
+ r = requests.get(readme_url, verify=False)
35
+ if not os.path.exists(output_path):
36
+ with open(output_path, "wb") as f:
37
+ f.write(r.content)
38
+
39
+ # -- Project information
40
+ project = 'ivoryOS'
41
+ copyright = '2024, Ivory Zhang'
42
+ author = 'Ivory Zhang, Lucy Hao'
43
+ version = __version__
44
+
45
+ extensions = [
46
+ 'sphinx.ext.duration',
47
+ 'sphinx.ext.doctest',
48
+ 'sphinx.ext.autosummary',
49
+ 'sphinx.ext.intersphinx',
50
+ 'sphinxcontrib.httpdomain',
51
+ 'sphinxcontrib.autohttp.flask',
52
+ 'sphinxcontrib.autohttp.flaskqref'
53
+ ]
54
+
55
+ install_requires = [
56
+ 'sphinx-autodoc-typehints'
57
+ ]
58
+ autodoc_mock_imports = ["flask_sqlalchemy", "another_hard_to_import_lib"]
59
+
60
+
61
+ intersphinx_mapping = {
62
+ 'python': ('https://docs.python.org/3/', None),
63
+ 'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
64
+ }
65
+ intersphinx_disabled_domains = ['std']
66
+
67
+ templates_path = ['_templates']
68
+
69
+ html_static_path = ['_static']
70
+ html_css_files = [
71
+ 'custom.css',
72
+ ]
73
+
74
+ html_allow_raw_html = True
75
+
76
+ # -- Options for HTML output
77
+
78
+ html_theme = 'sphinx_rtd_theme'
79
+
80
+ # -- Options for EPUB output
81
+ epub_show_urls = 'footnote'
82
+
83
+ # The master toctree document.
84
+ master_doc = 'index'
@@ -1,8 +1,8 @@
1
- from ivoryos.server import run
1
+ from ivoryos.server import run, global_config
2
2
  from ivoryos.optimizer.registry import OPTIMIZER_REGISTRY
3
3
  from ivoryos.version import __version__ as ivoryos_version
4
4
  from ivoryos.utils.decorators import block, BUILDING_BLOCKS
5
- from ivoryos.app import app
5
+ from ivoryos.app import app, create_app, socketio, db
6
6
 
7
7
  __all__ = [
8
8
  "block",
@@ -11,4 +11,8 @@ __all__ = [
11
11
  "run",
12
12
  "app",
13
13
  "ivoryos_version",
14
+ "create_app",
15
+ "socketio",
16
+ "global_config",
17
+ "db"
14
18
  ]
@@ -1,24 +1,22 @@
1
1
  import os
2
2
  import uuid
3
3
 
4
+ import bcrypt
4
5
  from flask import Flask, session, g, redirect, url_for
5
6
  from flask_login import AnonymousUserMixin
6
7
 
7
8
  from ivoryos.utils import utils
8
- from ivoryos.utils.db_models import db
9
- from ivoryos.config import Config, get_config
9
+ from ivoryos.utils.db_models import db, User
10
10
  from ivoryos.routes.auth.auth import auth, login_manager
11
11
  from ivoryos.routes.control.control import control
12
12
  from ivoryos.routes.data.data import data
13
13
  from ivoryos.routes.library.library import library
14
14
  from ivoryos.routes.design.design import design
15
15
  from ivoryos.routes.execute.execute import execute
16
- from ivoryos.routes.api.api import api
17
16
  from ivoryos.socket_handlers import socketio
18
17
  from ivoryos.routes.main.main import main
19
18
  from ivoryos.version import __version__ as ivoryos_version
20
19
  from sqlalchemy import inspect, text
21
- from flask import current_app
22
20
 
23
21
  url_prefix = os.getenv('URL_PREFIX', "/ivoryos")
24
22
  app = Flask(__name__, static_url_path=f'{url_prefix}/static', static_folder='static')
@@ -29,7 +27,7 @@ app.register_blueprint(control, url_prefix=f'{url_prefix}/instruments')
29
27
  app.register_blueprint(design, url_prefix=f'{url_prefix}')
30
28
  app.register_blueprint(execute, url_prefix=f'{url_prefix}')
31
29
  app.register_blueprint(data, url_prefix=f'{url_prefix}')
32
- app.register_blueprint(api, url_prefix=f'{url_prefix}/{api.name}')
30
+ # app.register_blueprint(api, url_prefix=f'{url_prefix}/{api.name}')
33
31
 
34
32
  def reset_old_schema(engine, db_dir):
35
33
  inspector = inspect(engine)
@@ -41,7 +39,8 @@ def reset_old_schema(engine, db_dir):
41
39
  old_workflow_run = 'workflow_runs' in tables
42
40
  old_workflow_step = 'workflow_steps' in tables
43
41
 
44
- if not has_workflow_phase:
42
+ # v1.3.4 only delete and backup when there is runs but no phases
43
+ if not has_workflow_phase and old_workflow_run:
45
44
  print("⚠️ Old workflow database detected! All previous workflows have been reset to support the new schema.")
46
45
  # Backup old DB
47
46
  db_path = os.path.join(db_dir, "ivoryos.db")
@@ -59,11 +58,36 @@ def reset_old_schema(engine, db_dir):
59
58
  conn.execute(text("DROP TABLE IF EXISTS workflow_steps"))
60
59
  if old_workflow_run:
61
60
  conn.execute(text("DROP TABLE IF EXISTS workflow_runs"))
61
+ with engine.begin() as conn:
62
+ try:
63
+ conn.execute(
64
+ text("ALTER TABLE user ADD COLUMN settings TEXT")
65
+ )
66
+ except Exception:
67
+ pass
62
68
 
63
69
  # Recreate new schema
64
70
  db.create_all() # creates workflow_runs, workflow_phases, workflow_steps
65
71
 
66
72
 
73
+ def create_admin():
74
+ """
75
+ Create an admin user with username 'admin' and password 'admin' if it doesn't exist.
76
+ """
77
+ with app.app_context():
78
+ admin_user = User.query.filter_by(username='admin').first()
79
+ if not admin_user:
80
+ print("Creating default admin user...")
81
+ admin_user = User(
82
+ username='admin',
83
+ password=bcrypt.hashpw("admin".encode('utf-8'), bcrypt.gensalt()),
84
+ )
85
+ db.session.add(admin_user)
86
+ db.session.commit()
87
+ else:
88
+ print("Admin user already exists.")
89
+
90
+
67
91
  def create_app(config_class=None):
68
92
  """
69
93
  create app, init database
@@ -81,6 +105,7 @@ def create_app(config_class=None):
81
105
  with app.app_context():
82
106
  # db.create_all()
83
107
  reset_old_schema(db.engine, app.config['OUTPUT_FOLDER'])
108
+ create_admin()
84
109
 
85
110
  # Additional setup
86
111
  utils.create_gui_dir(app.config['OUTPUT_FOLDER'])