ivoryos 1.3.5a0__py3-none-any.whl → 1.3.6__py3-none-any.whl

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.

Potentially problematic release.


This version of ivoryos might be problematic. Click here for more details.

ivoryos/__init__.py CHANGED
@@ -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
  ]
@@ -30,7 +30,7 @@ class AxOptimizer(OptimizerBase):
30
30
  @staticmethod
31
31
  def _create_generator_mapping():
32
32
  """Create a mapping from string values to Generator enum members."""
33
- from ax.modelbridge import Generators
33
+ from ax.adapter import Generators
34
34
  return {member.value: member for member in Generators}
35
35
 
36
36
  def _convert_parameter_to_ax_format(self, parameter_space):
@@ -96,8 +96,8 @@ class AxOptimizer(OptimizerBase):
96
96
  step_2 = optimizer_config.get("step_2", {})
97
97
  step_1_generator = step_1.get("model", "Sobol")
98
98
  step_2_generator = step_2.get("model", "BOTorch")
99
- generator_1 = GenerationStep(model=generators.get(step_1_generator), num_trials=step_1.get("num_samples", 5))
100
- generator_2 = GenerationStep(model=generators.get(step_2_generator), num_trials=step_2.get("num_samples", -1))
99
+ generator_1 = GenerationStep(generator=generators.get(step_1_generator), num_trials=step_1.get("num_samples", 5))
100
+ generator_2 = GenerationStep(generator=generators.get(step_2_generator), num_trials=step_2.get("num_samples", -1))
101
101
  return GenerationStrategy(steps=[generator_1, generator_2])
102
102
 
103
103
  def suggest(self, n=1):
@@ -5,7 +5,7 @@ from abc import ABC, abstractmethod
5
5
 
6
6
 
7
7
  class OptimizerBase(ABC):
8
- def __init__(self, experiment_name:str, parameter_space: list, objective_config: dict, optimizer_config: dict):
8
+ def __init__(self, experiment_name:str, parameter_space: list, objective_config: dict, optimizer_config: dict, datapath:str=None):
9
9
  """
10
10
  :param experiment_name: arbitrary name
11
11
  :param parameter_space: list of parameter names
@@ -29,6 +29,7 @@ class OptimizerBase(ABC):
29
29
  self.parameter_space = parameter_space
30
30
  self.objective_config = objective_config
31
31
  self.optimizer_config = optimizer_config
32
+ self.datapath = datapath
32
33
 
33
34
  @abstractmethod
34
35
  def suggest(self, n=1):
@@ -2,8 +2,10 @@
2
2
 
3
3
  from ivoryos.optimizer.ax_optimizer import AxOptimizer
4
4
  from ivoryos.optimizer.baybe_optimizer import BaybeOptimizer
5
+ from ivoryos.optimizer.nimo_optimizer import NIMOOptimizer
5
6
 
6
7
  OPTIMIZER_REGISTRY = {
7
8
  "ax": AxOptimizer,
8
- "baybe": BaybeOptimizer
9
+ "baybe": BaybeOptimizer,
10
+ "nimo": NIMOOptimizer,
9
11
  }
@@ -87,8 +87,11 @@ def experiment_builder():
87
87
 
88
88
  # edit_action_info = session.get("edit_action")
89
89
 
90
-
91
- exec_string = script.python_script if script.python_script else script.compile(current_app.config['SCRIPT_FOLDER'])
90
+ try:
91
+ exec_string = script.python_script if script.python_script else script.compile(current_app.config['SCRIPT_FOLDER'])
92
+ except Exception as e:
93
+ exec_string = {}
94
+ flash(f"Error in Python script: {e}")
92
95
  session['python_code'] = exec_string
93
96
 
94
97
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
@@ -382,7 +385,13 @@ def methods_handler(instrument: str = ''):
382
385
  success = False
383
386
  msg = [f"{field}: {', '.join(messages)}" for field, messages in form.errors.items()]
384
387
  utils.post_script_file(script)
385
- exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
388
+ #TODO
389
+ try:
390
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
391
+ except Exception as e:
392
+ exec_string = {}
393
+ msg = f"Compilation failed: {str(e)}"
394
+ # exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
386
395
  session['python_code'] = exec_string
387
396
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
388
397
  html = render_template("components/canvas_main.html", script=script, buttons_dict=design_buttons)
@@ -23,12 +23,16 @@ def get_step(uuid: int):
23
23
  """
24
24
  script = utils.get_script_file()
25
25
  action = script.find_by_uuid(uuid)
26
- if request.method == 'GET':
27
- # forms = create_form_from_action(action, script=script)
26
+ if action is None:
27
+ return jsonify({"warning": "Step not found, please refresh the page."}), 404
28
+
29
+ elif request.method == 'GET':
30
+ forms = create_form_from_action(action, script=script)
28
31
  # session['edit_action'] = action
29
32
  return render_template("components/edit_action_form.html",
30
33
  action=action,
31
- forms=create_form_from_action(action, script=script))
34
+ forms=forms)
35
+
32
36
 
33
37
 
34
38
  @steps.post("/draft/steps/<int:uuid>")
@@ -47,6 +51,7 @@ def save_step(uuid: int):
47
51
  """
48
52
  script = utils.get_script_file()
49
53
  action = script.find_by_uuid(uuid)
54
+ warning = None
50
55
  if action is not None:
51
56
  forms = create_form_from_action(action, script=script)
52
57
  kwargs = {field.name: field.data for field in forms if field.name != 'csrf_token'}
@@ -55,14 +60,19 @@ def save_step(uuid: int):
55
60
  kwargs = script.validate_variables(kwargs)
56
61
  script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as)
57
62
  else:
58
- flash(forms.errors)
63
+ warning = f"Compilation failed: {str(forms.errors)}"
59
64
  utils.post_script_file(script)
60
- exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
65
+ try:
66
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
67
+ except Exception as e:
68
+ exec_string = {}
69
+ warning = f"Compilation failed: {str(e)}"
61
70
  session['python_code'] = exec_string
62
71
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
63
72
  return render_template("components/canvas_main.html",
64
- script=script,
65
- buttons_dict=design_buttons)
73
+ script=script,
74
+ buttons_dict=design_buttons,
75
+ warning=warning)
66
76
 
67
77
  @steps.delete("/draft/steps/<int:uuid>")
68
78
  def delete_step(uuid: int):
@@ -82,12 +92,17 @@ def delete_step(uuid: int):
82
92
  if request.method == 'DELETE':
83
93
  script.delete_action(uuid)
84
94
  utils.post_script_file(script)
85
- exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
95
+ warning = None
96
+ try:
97
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
98
+ except Exception as e:
99
+ exec_string = {}
100
+ warning = f"Compilation failed: {str(e)}"
86
101
  session['python_code'] = exec_string
87
102
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
88
103
  return render_template("components/canvas_main.html",
89
104
  script=script,
90
- buttons_dict=design_buttons)
105
+ buttons_dict=design_buttons, warning=warning)
91
106
 
92
107
 
93
108
  @steps.route("/draft/steps/<int:uuid>/duplicate", methods=["POST"], strict_slashes=False,)
@@ -107,13 +122,18 @@ def duplicate_action(uuid: int):
107
122
  script = utils.get_script_file()
108
123
  script.duplicate_action(uuid)
109
124
  utils.post_script_file(script)
110
- exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
125
+ warning = None
126
+ try:
127
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
128
+ except Exception as e:
129
+ exec_string = {}
130
+ warning = f"Compilation failed: {str(e)}"
111
131
  session['python_code'] = exec_string
112
132
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
113
133
 
114
134
  return render_template("components/canvas_main.html",
115
135
  script=script,
116
- buttons_dict=design_buttons)
136
+ buttons_dict=design_buttons, warning=warning)
117
137
 
118
138
 
119
139
  @steps.route("/draft/steps/order", methods=['POST'])
@@ -133,13 +153,18 @@ def update_list():
133
153
  script = utils.get_script_file()
134
154
  script.currently_editing_order = order.split(",", len(script.currently_editing_script))
135
155
  script.sort_actions()
156
+ warning = None
136
157
 
137
158
  utils.post_script_file(script)
138
- exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
159
+ try:
160
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
161
+ except Exception as e:
162
+ exec_string = {}
163
+ warning = f"Compilation failed: {str(e)}"
139
164
  session['python_code'] = exec_string
140
165
 
141
166
  # Return the updated canvas HTML instead of JSON
142
167
  design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
143
168
  return render_template("components/canvas_main.html",
144
169
  script=script,
145
- buttons_dict=design_buttons)
170
+ buttons_dict=design_buttons, warning=warning)
@@ -31,4 +31,9 @@
31
31
  </div>
32
32
  <div class="python-code-wrapper" id="python-code-wrapper">
33
33
  {% include 'components/python_code_overlay.html' %}
34
- </div>
34
+ </div>
35
+
36
+
37
+ {% if warning %}
38
+ <div id="warning" style="display:none;">{{ warning }}</div>
39
+ {% endif %}
@@ -6,6 +6,7 @@
6
6
  <i class="bi bi-arrow-return-left"></i>
7
7
  </a>
8
8
  </div>
9
+ {% if action %}
9
10
  <h5> {{ action['action'] | format_name }} </h5>
10
11
  <form role="form" method='POST' name="{{instrument}}"
11
12
  action="{{ url_for('design.design_steps.get_step', uuid=action['uuid']) }}"
@@ -36,3 +37,4 @@
36
37
  <button type="submit" class="btn btn-primary">Save</button>
37
38
  <button type="button" class="btn btn-primary" id="back">Back</button>
38
39
  </form>
40
+ {% endif %}
ivoryos/server.py CHANGED
@@ -50,6 +50,7 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
50
50
  blueprint_plugins: Union[list, Blueprint] = [],
51
51
  exclude_names: list = [],
52
52
  notification_handler=None,
53
+ optimizer_registry: dict = None,
53
54
  ):
54
55
  """
55
56
  Start ivoryOS app server.
@@ -91,7 +92,10 @@ def run(module=None, host="0.0.0.0", port=None, debug=None, llm_server=None, mod
91
92
  app.config["LOGGERS_PATH"] = logger_output_name or app.config["LOGGERS_PATH"] # default.log
92
93
  logger_path = os.path.join(app.config["OUTPUT_FOLDER"], app.config["LOGGERS_PATH"])
93
94
  dummy_deck_path = os.path.join(app.config["OUTPUT_FOLDER"], app.config["DUMMY_DECK"])
94
- global_config.optimizers = OPTIMIZER_REGISTRY
95
+ if optimizer_registry:
96
+ global_config.optimizers = optimizer_registry
97
+ else:
98
+ global_config.optimizers = OPTIMIZER_REGISTRY
95
99
  if module:
96
100
  app.config["MODULE"] = module
97
101
  app.config["OFF_LINE"] = False
@@ -103,6 +103,12 @@ function submitEditForm(event) {
103
103
  document.getElementById('instrument-panel').innerHTML = previousHtmlState;
104
104
  previousHtmlState = null; // Clear the stored state
105
105
  }
106
+ const parser = new DOMParser();
107
+ const doc = parser.parseFromString(html, 'text/html');
108
+ const warningDiv = doc.querySelector('#warning');
109
+ if (warningDiv && warningDiv.textContent.trim()) {
110
+ alert(warningDiv.textContent.trim()); // or use a nicer toast
111
+ }
106
112
  }
107
113
  })
108
114
  .catch(error => {
@@ -149,6 +155,13 @@ function duplicateAction(uuid) {
149
155
  .then(response => response.text())
150
156
  .then(html => {
151
157
  updateActionCanvas(html);
158
+
159
+ const parser = new DOMParser();
160
+ const doc = parser.parseFromString(html, 'text/html');
161
+ const warningDiv = doc.querySelector('#warning');
162
+ if (warningDiv && warningDiv.textContent.trim()) {
163
+ alert(warningDiv.textContent.trim()); // or use a nicer toast
164
+ }
152
165
  })
153
166
  .catch(error => console.error('Error:', error));
154
167
  }
@@ -159,33 +172,50 @@ function editAction(uuid) {
159
172
  return;
160
173
  }
161
174
 
162
- // Save current state before fetching new content
163
175
  previousHtmlState = document.getElementById('instrument-panel').innerHTML;
164
176
 
165
177
  fetch(scriptStepUrl.replace('0', uuid), {
166
- method: 'GET',
178
+ method: 'GET', // no need for Content-Type on GET
167
179
  headers: {
168
180
  'Content-Type': 'application/json'
169
181
  }
170
182
  })
171
- .then(response => response.text())
183
+ .then(response => {
184
+ if (!response.ok) {
185
+ return response.json().then(err => {
186
+ if (err.warning) {
187
+ alert(err.warning); // <-- should fire now
188
+ }
189
+ // restore panel so user isn't stuck
190
+ if (previousHtmlState) {
191
+ document.getElementById('instrument-panel').innerHTML = previousHtmlState;
192
+ previousHtmlState = null;
193
+ }
194
+ throw new Error("Step fetch failed: " + response.status);
195
+ });
196
+ }
197
+ return response.text();
198
+ })
172
199
  .then(html => {
173
200
  document.getElementById('instrument-panel').innerHTML = html;
174
201
 
175
- // Add click handler for back button
176
- document.getElementById('back').addEventListener('click', function(e) {
177
- e.preventDefault();
178
- if (previousHtmlState) {
179
- document.getElementById('instrument-panel').innerHTML = previousHtmlState;
180
- previousHtmlState = null; // Clear the stored state
181
- }
182
- });
202
+ const backButton = document.getElementById('back');
203
+ if (backButton) {
204
+ backButton.addEventListener('click', function(e) {
205
+ e.preventDefault();
206
+ if (previousHtmlState) {
207
+ document.getElementById('instrument-panel').innerHTML = previousHtmlState;
208
+ previousHtmlState = null;
209
+ }
210
+ });
211
+ }
183
212
  })
184
213
  .catch(error => console.error('Error:', error));
185
214
  }
186
215
 
187
216
 
188
217
 
218
+
189
219
  function deleteAction(uuid) {
190
220
  if (!uuid) {
191
221
  console.error('Invalid UUID');
@@ -202,6 +232,13 @@ function deleteAction(uuid) {
202
232
  .then(html => {
203
233
  // Find the first list element's content and replace it
204
234
  updateActionCanvas(html);
235
+ // Optionally, check if a warning element exists
236
+ const parser = new DOMParser();
237
+ const doc = parser.parseFromString(html, 'text/html');
238
+ const warningDiv = doc.querySelector('#warning');
239
+ if (warningDiv && warningDiv.textContent.trim()) {
240
+ alert(warningDiv.textContent.trim()); // or use a nicer toast
241
+ }
205
242
  })
206
243
  .catch(error => console.error('Error:', error));
207
244
  }
@@ -209,7 +209,7 @@ def parse_optimization_form(form_data: Dict[str, str]):
209
209
  parameter["bounds"] = bounds
210
210
 
211
211
  elif value == "choice":
212
- choices_field = f"{param_name}_choices"
212
+ choices_field = f"{param_name}_value"
213
213
  if choices_field in form_data and form_data[choices_field]:
214
214
  # Split choices by comma and clean whitespace
215
215
  choices = [choice.strip() for choice in form_data[choices_field].split(',')]
@@ -644,12 +644,21 @@ class Script(db.Model):
644
644
  args_str = args_str.replace(f"'#{args[arg][1:]}'", args[arg][1:])
645
645
  elif isinstance(args[arg], dict):
646
646
  # print(args[arg])
647
- variables = self.get_variables()
647
+ if not args[arg]:
648
+ continue
649
+ # Extract the variable name (first key in the dict)
648
650
  value = next(iter(args[arg]))
649
- if value not in variables:
650
- raise ValueError(f"Variable ({value}) is not defined.")
651
- args_str = args_str.replace(f"{args[arg]}", next(iter(args[arg])))
652
- # elif self._is_variable(arg):
651
+ var_type = args[arg].get(value)
652
+
653
+ # Only process if it's a function_output variable reference
654
+ if var_type == "function_output":
655
+ variables = self.get_variables()
656
+ if value not in variables:
657
+ raise ValueError(f"Variable ({value}) is not defined.")
658
+ # Replace the dict string representation with just the variable name
659
+ args_str = args_str.replace(f"{args[arg]}", value)
660
+
661
+ # elif self._is_variable(arg):
653
662
  # print("is variable")
654
663
  # args_str = args_str.replace(f"'{args[arg]}'", args[arg])
655
664
  return args_str
ivoryos/utils/form.py CHANGED
@@ -405,7 +405,7 @@ def create_form_from_action(action: dict, script=None, design=True):
405
405
  for name, param_type in arg_types.items():
406
406
  # formatted_param_name = format_name(name)
407
407
  value = args.get(name, "")
408
- if type(value) is dict:
408
+ if type(value) is dict and value:
409
409
  value = next(iter(value))
410
410
  field_kwargs = {
411
411
  "label": name,
@@ -556,9 +556,13 @@ def _action_button(action: dict, variables: dict):
556
556
  arg_list = []
557
557
  for k, v in action['args'].items():
558
558
  if isinstance(v, dict):
559
- value = next(iter(v)) # Extract the first key if it's a dict
560
- # show warning color for variable calling when there is no definition
561
- style = "background-color: khaki" if value not in variables.keys() else ""
559
+ if not v:
560
+ value = v # Keep the original value if not a dict
561
+ else:
562
+ value = next(iter(v)) # Extract the first key if it's a dict
563
+ # show warning color for variable calling when there is no definition
564
+
565
+ style = "background-color: khaki" if v.get(value) == "function_output" and value not in variables.keys() else ""
562
566
  else:
563
567
  value = v # Keep the original value if not a dict
564
568
  arg_list.append(f"{k} = {value}") # Format the key-value pair
@@ -195,11 +195,12 @@ class ScriptRunner:
195
195
 
196
196
  # Update exec_locals with the returned locals
197
197
  exec_locals.update(result_locals)
198
- exec_locals.pop("__async_exec_wrapper", None)
198
+
199
199
 
200
200
  else:
201
- print("just exec synchronously")
201
+ # print("just exec synchronously")
202
202
  exec(line, exec_globals, exec_locals)
203
+ exec_globals.update(exec_locals)
203
204
  # return locals_dict
204
205
  # exec(line, exec_globals, exec_locals)
205
206
  # step.run_error = False
@@ -217,6 +218,7 @@ class ScriptRunner:
217
218
 
218
219
  step.run_error = True
219
220
  self.toggle_pause()
221
+ exec_locals.pop("__async_exec_wrapper", None)
220
222
  step.end_time = datetime.now()
221
223
  step.output = exec_locals
222
224
  db.session.commit()
ivoryos/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.3.5a0"
1
+ __version__ = "1.3.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ivoryos
3
- Version: 1.3.5a0
3
+ Version: 1.3.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
@@ -17,9 +18,21 @@ Requires-Dist: Flask-WTF
17
18
  Requires-Dist: SQLAlchemy-Utils
18
19
  Requires-Dist: python-dotenv
19
20
  Requires-Dist: astor; python_version < "3.9"
21
+ Provides-Extra: optimizer-ax
22
+ Requires-Dist: ax-platform; extra == "optimizer-ax"
23
+ Provides-Extra: optimizer-baybe
24
+ Requires-Dist: baybe; extra == "optimizer-baybe"
25
+ Provides-Extra: optimizer-nimo
26
+ Requires-Dist: nimo; extra == "optimizer-nimo"
20
27
  Provides-Extra: optimizer
21
- Requires-Dist: ax-platform; extra == "optimizer"
28
+ Requires-Dist: ax-platform>=1.1.2; extra == "optimizer"
22
29
  Requires-Dist: baybe; extra == "optimizer"
30
+ Provides-Extra: doc
31
+ Requires-Dist: sphinx; extra == "doc"
32
+ Requires-Dist: sphinx-rtd-theme; extra == "doc"
33
+ Requires-Dist: sphinxcontrib-httpdomain; extra == "doc"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest; extra == "dev"
23
36
  Dynamic: license-file
24
37
 
25
38
  [![Documentation Status](https://readthedocs.org/projects/ivoryos/badge/?version=latest)](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
@@ -1,13 +1,13 @@
1
- ivoryos/__init__.py,sha256=Or4kPfDSQA5WYrQdnBlWl_dA4wwjhEqNkuE5XPX3bqI,358
1
+ ivoryos/__init__.py,sha256=gEvBO2y5TRq06Itjjej3iAcq73UsihqKPWcb2HykPwM,463
2
2
  ivoryos/app.py,sha256=G6kzEOVzCduj7Fc2r1rMbMFHgDzZQV0lC20Oxps7RSM,4839
3
3
  ivoryos/config.py,sha256=y3RxNjiIola9tK7jg-mHM8EzLMwiLwOzoisXkDvj0gA,2174
4
- ivoryos/server.py,sha256=5tXrgG16lm6Fl-Q-ZHxiGQQoyZQFxRhdDf6idNYqhNg,6985
4
+ ivoryos/server.py,sha256=Idr41Boa8rPsh3bVJ8xy2Flwfxa1Xu6f2T0oMp4qBEk,7121
5
5
  ivoryos/socket_handlers.py,sha256=VWVWiIdm4jYAutwGu6R0t1nK5MuMyOCL0xAnFn06jWQ,1302
6
- ivoryos/version.py,sha256=6_TWXwv9gjZoVnzn72CakHZpbe6qkvg_TQ50w9uFBsk,24
7
- ivoryos/optimizer/ax_optimizer.py,sha256=PoSu8hrDFFpqyhRBnaSMswIUsDfEX6sPWt8NEZ_sobs,7112
8
- ivoryos/optimizer/base_optimizer.py,sha256=JTbUharZKn0t8_BDbAFuwZIbT1VOnX1Xuog1pJuU8hY,1992
6
+ ivoryos/version.py,sha256=5ZbAQtod5QalTI1C2N07edlxplzG_Q2XvGOSyOok4uA,22
7
+ ivoryos/optimizer/ax_optimizer.py,sha256=k7RzhNMjh3MseOE-_FADVX72lYLDyXz-XE3juSBRWTk,7116
8
+ ivoryos/optimizer/base_optimizer.py,sha256=gNBX9m3RxoYklwEBkqeDGZlU7c6e9e5kN0ZeTtnxnCE,2044
9
9
  ivoryos/optimizer/baybe_optimizer.py,sha256=EdrrRiYO-IOx610cPXiQhH4qG8knUP0uiZ0YoyaGIU8,7954
10
- ivoryos/optimizer/registry.py,sha256=lr0cqdI2iEjw227ZPRpVkvsdYdddjeJJRzawDv77cEc,219
10
+ ivoryos/optimizer/registry.py,sha256=dLMo5cszcwa06hfBxdINQIGpkHtRe5-J3J7t76Jq6X0,306
11
11
  ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  ivoryos/routes/api/api.py,sha256=97Y7pqTwOaWgZgI5ovEPxEBm6Asrt0Iy0VhBkVp2xqA,2304
13
13
  ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -27,9 +27,9 @@ ivoryos/routes/data/templates/workflow_database.html,sha256=ofvHcovpwmJXo1SFiSrL
27
27
  ivoryos/routes/data/templates/workflow_view.html,sha256=Ti17kzlPlYTmzx5MkdsPlXJ1_k6QgMYQBM6FHjG50go,12491
28
28
  ivoryos/routes/data/templates/components/step_card.html,sha256=XWsr7qxAY76RCuQHETubWjWBlPgs2HkviH4ju6qfBKo,1923
29
29
  ivoryos/routes/design/__init__.py,sha256=zS3HXKaw0ALL5n6t_W1rUz5Uj5_tTQ-Y1VMXyzewvR0,113
30
- ivoryos/routes/design/design.py,sha256=AzipVe9paK5gR_AHZggAoiNTm76rO7i5kTeLs04I8vA,18457
30
+ ivoryos/routes/design/design.py,sha256=HPjjoGH9mzSP6TxVNUYWgwhfzkpRt5BF38agL_tJvXk,18760
31
31
  ivoryos/routes/design/design_file.py,sha256=MVIc5uGSaGxZhs86hfPjX2n0iy1OcXeLq7b9Ucdg4VQ,2115
32
- ivoryos/routes/design/design_step.py,sha256=zW6kOhX-zJbtX1x5NaVPm79HZjKBzAWevmqJ2Y3qqpg,5218
32
+ ivoryos/routes/design/design_step.py,sha256=M3l37kP1kU4_bolLBU1MWJgEW0LUXojo9UdQgysZyXs,5943
33
33
  ivoryos/routes/design/templates/experiment_builder.html,sha256=hh-d2tOc_40gww5WfUYIf8sM3qBaALZnR8Sx7Ja4tpU,1623
34
34
  ivoryos/routes/design/templates/components/action_form.html,sha256=kXJOrJLbFsMHHWVSuMQHpt1xFrUMnwgzTG8e6Qfn0Cg,3042
35
35
  ivoryos/routes/design/templates/components/actions_panel.html,sha256=jHTR58saTUIZInBdC-vLc1ZTbStLiULeWbupjB4hQzo,977
@@ -37,9 +37,9 @@ ivoryos/routes/design/templates/components/autofill_toggle.html,sha256=CRVQUHoQT
37
37
  ivoryos/routes/design/templates/components/canvas.html,sha256=bKLCJaG1B36Yy9Vsnz4P5qiX4BPdfaGe9JeQQzu9rsI,268
38
38
  ivoryos/routes/design/templates/components/canvas_footer.html,sha256=5VRRacMZbzx0hUej0NPP-PmXM_AtUqduHzDS7a60cQY,435
39
39
  ivoryos/routes/design/templates/components/canvas_header.html,sha256=7iIzLDGHX7MnmBbf98nWtLDprbeIgoNV4dJUO1zE4Tc,3598
40
- ivoryos/routes/design/templates/components/canvas_main.html,sha256=9inYO700zRa09lfQI2NY4FJGGeTh-9rvX4ltjj0LK3k,1432
40
+ ivoryos/routes/design/templates/components/canvas_main.html,sha256=nLEtp3U2YtfJwob1kR8ua8-UVdu9hwc6z1L5UMNVz8c,1524
41
41
  ivoryos/routes/design/templates/components/deck_selector.html,sha256=ryTRpljYezo0AzGLCJu_qOMokjjnft3GIxddmNGtBA0,657
42
- ivoryos/routes/design/templates/components/edit_action_form.html,sha256=Dz7FnnOK4PYptAHNy9_WFCU1RZTSV61-1lNHHOSRJNs,1876
42
+ ivoryos/routes/design/templates/components/edit_action_form.html,sha256=idhUKOqewIxgqMKYKLutqOjopKQVLvddB6uufoBA3Lo,1912
43
43
  ivoryos/routes/design/templates/components/instruments_panel.html,sha256=tRKd-wOqKjaMJCLuGgRmHtxIgSjklhBkuX8arm5aTCU,4268
44
44
  ivoryos/routes/design/templates/components/modals.html,sha256=6Dl8I8oD4ln7kK8C5e92pFVVH5KDte-vVTL0U_6NSTg,306
45
45
  ivoryos/routes/design/templates/components/python_code_overlay.html,sha256=GUHgsmUWQf0P1Fbg5W0OJC34TXCUIMQVUkS7KDoauyI,1264
@@ -74,7 +74,7 @@ ivoryos/static/logo.webp,sha256=lXgfQR-4mHTH83k7VV9iB54-oC2ipe6uZvbwdOnLETc,1497
74
74
  ivoryos/static/style.css,sha256=zQVx35A5g6JMJ-K84-6fSKtzXGjp_p5ZVG6KLHPM2IE,4021
75
75
  ivoryos/static/gui_annotation/Slide1.png,sha256=Lm4gdOkUF5HIUFaB94tl6koQVkzpitKj43GXV_XYMMc,121727
76
76
  ivoryos/static/gui_annotation/Slide2.PNG,sha256=z3wQ9oVgg4JTWVLQGKK_KhtepRHUYP1e05XUWGT2A0I,118761
77
- ivoryos/static/js/action_handlers.js,sha256=UJHKFhYRNQRBo0AHLCIxhWxt8OSgYeyLynzPIPNhbeY,5125
77
+ ivoryos/static/js/action_handlers.js,sha256=MdYfXLRNSMAkfO_lkDb8Mr--MlZA7SluEQ5AB3Jqw7k,6704
78
78
  ivoryos/static/js/db_delete.js,sha256=l67fqUaN_FVDaL7v91Hd7LyRbxnqXx9nyjF34-7aewY,561
79
79
  ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,483
80
80
  ivoryos/static/js/script_metadata.js,sha256=m8VYZ8OGT2oTx1kXMXq60bKQI9WCbJNkzcFDzLvRuGc,1188
@@ -84,20 +84,20 @@ ivoryos/static/js/sortable_design.js,sha256=ASc9P6_423Mczeg6QH6LVtyxLyWhpxWJP2nE
84
84
  ivoryos/static/js/ui_state.js,sha256=XYsOcfGlduqLlqHySvPrRrR50CiAsml51duqneigsRY,3368
85
85
  ivoryos/templates/base.html,sha256=cl5w6E8yskbUzdiJFal6fZjnPuFNKEzc7BrrbRd6bMI,8581
86
86
  ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
- ivoryos/utils/bo_campaign.py,sha256=Fil-zT7JexL_p9XqyWByjAk42XB1R9XUKN8CdV5bi6c,9714
87
+ ivoryos/utils/bo_campaign.py,sha256=AqTE4aIUWL26P0-o1qvL2ms4MjYzNQABNxZFisxBsyg,9712
88
88
  ivoryos/utils/client_proxy.py,sha256=74G3HAuq50iEHkSvlMZFmQaukm613FbRgOdzO_T3dMg,10191
89
- ivoryos/utils/db_models.py,sha256=i1fLiWFnese2xqAfWipN9eUDHeuy6eIYE9_cY6YZ6NU,31553
89
+ ivoryos/utils/db_models.py,sha256=TbOydX7rC1jGfei2mVYaexlE3lyq1Igb1VQuHJlMRKQ,31945
90
90
  ivoryos/utils/decorators.py,sha256=p1Bdl3dCeaHNv6-cCCUOZMiFu9kRaqqQnkFJUkzPoJE,991
91
- ivoryos/utils/form.py,sha256=Ej9tx06KZZ5fPQm1ho1byotNocF3u24aatc2ZyI0rK4,22301
91
+ ivoryos/utils/form.py,sha256=f1yXHlOQX1YnJ2j_UW6iHmh4pTAGAs9sAlhyQB8yBIo,22505
92
92
  ivoryos/utils/global_config.py,sha256=leYoEXvAS0AH4xQpYsqu4HI9CJ9-wiLM-pIh_bEG4Ak,3087
93
93
  ivoryos/utils/llm_agent.py,sha256=-lVCkjPlpLues9sNTmaT7bT4sdhWvV2DiojNwzB2Lcw,6422
94
94
  ivoryos/utils/py_to_json.py,sha256=ZtejHgwdEAUCVVMYeVNR8G7ceLINue294q6WpiJ6jn0,9734
95
- ivoryos/utils/script_runner.py,sha256=8mbgPod3j-qOUPnDdbzFkKOn3ROyt-WedkqC01DXON8,20701
95
+ ivoryos/utils/script_runner.py,sha256=gIYdTEFNWZFmPf9cf31y3wAUKUeJk_qnjohYDKevWNw,20749
96
96
  ivoryos/utils/serilize.py,sha256=lkBhkz8r2bLmz2_xOb0c4ptSSOqjIu6krj5YYK4Nvj8,6784
97
97
  ivoryos/utils/task_runner.py,sha256=xiMzK8gQ0mHsg0A1Ah8fmXe3azpaJh4hJiQJLHA11ZQ,3682
98
98
  ivoryos/utils/utils.py,sha256=dIc4BO55eS3lCA0nhbIncS5d7sLaKZy5hJS1I_Sm45o,14949
99
- ivoryos-1.3.5a0.dist-info/licenses/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
100
- ivoryos-1.3.5a0.dist-info/METADATA,sha256=ss3QiOlGF-riNBwIyI8jQumEfxfkIS9Z7134bJABl00,8023
101
- ivoryos-1.3.5a0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
102
- ivoryos-1.3.5a0.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
103
- ivoryos-1.3.5a0.dist-info/RECORD,,
99
+ ivoryos-1.3.6.dist-info/licenses/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
100
+ ivoryos-1.3.6.dist-info/METADATA,sha256=wUfp7SCz5Vtw7CrpuoKeirxfuf71F6deGzjBlx2Zuj8,8516
101
+ ivoryos-1.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
102
+ ivoryos-1.3.6.dist-info/top_level.txt,sha256=FRIWWdiEvRKqw-XfF_UK3XV0CrnNb6EmVbEgjaVazRM,8
103
+ ivoryos-1.3.6.dist-info/RECORD,,