sapiopycommons 2025.5.12a519__tar.gz → 2025.5.13a523__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.

Potentially problematic release.


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

Files changed (110) hide show
  1. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/PKG-INFO +1 -1
  2. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/pyproject.toml +1 -1
  3. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/tool_service_base.py +70 -23
  4. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/.gitignore +0 -0
  5. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/LICENSE +0 -0
  6. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/README.md +0 -0
  7. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/__init__.py +0 -0
  8. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/__init__.py +0 -0
  9. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +0 -0
  10. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +0 -0
  11. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +0 -0
  12. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +0 -0
  13. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +0 -0
  14. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +0 -0
  15. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.py +0 -0
  16. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +0 -0
  17. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +0 -0
  18. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_pb2.py +0 -0
  19. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_pb2.pyi +0 -0
  20. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +0 -0
  21. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.py +0 -0
  22. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +0 -0
  23. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +0 -0
  24. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +0 -0
  25. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +0 -0
  26. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +0 -0
  27. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +0 -0
  28. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +0 -0
  29. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +0 -0
  30. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +0 -0
  31. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +0 -0
  32. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +0 -0
  33. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/ai/protobuf_utils.py +0 -0
  34. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/callbacks/__init__.py +0 -0
  35. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/callbacks/callback_util.py +0 -0
  36. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/callbacks/field_builder.py +0 -0
  37. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/chem/IndigoMolecules.py +0 -0
  38. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/chem/Molecules.py +0 -0
  39. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/chem/__init__.py +0 -0
  40. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/customreport/__init__.py +0 -0
  41. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/customreport/auto_pagers.py +0 -0
  42. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/customreport/column_builder.py +0 -0
  43. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/customreport/custom_report_builder.py +0 -0
  44. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/customreport/term_builder.py +0 -0
  45. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/datatype/__init__.py +0 -0
  46. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/datatype/attachment_util.py +0 -0
  47. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/datatype/data_fields.py +0 -0
  48. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/datatype/pseudo_data_types.py +0 -0
  49. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/eln/__init__.py +0 -0
  50. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/eln/experiment_handler.py +0 -0
  51. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/eln/experiment_report_util.py +0 -0
  52. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/eln/experiment_tags.py +0 -0
  53. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/eln/plate_designer.py +0 -0
  54. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/__init__.py +0 -0
  55. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/complex_data_loader.py +0 -0
  56. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_bridge.py +0 -0
  57. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_bridge_handler.py +0 -0
  58. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_data_handler.py +0 -0
  59. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_util.py +0 -0
  60. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_validator.py +0 -0
  61. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/files/file_writer.py +0 -0
  62. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/flowcyto/flow_cyto.py +0 -0
  63. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/flowcyto/flowcyto_data.py +0 -0
  64. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/__init__.py +0 -0
  65. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/accession_service.py +0 -0
  66. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/aliases.py +0 -0
  67. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/audit_log.py +0 -0
  68. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/custom_report_util.py +0 -0
  69. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/directive_util.py +0 -0
  70. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/exceptions.py +0 -0
  71. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/html_formatter.py +0 -0
  72. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/popup_util.py +0 -0
  73. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/sapio_links.py +0 -0
  74. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/storage_util.py +0 -0
  75. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/general/time_util.py +0 -0
  76. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/multimodal/multimodal.py +0 -0
  77. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/multimodal/multimodal_data.py +0 -0
  78. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/processtracking/__init__.py +0 -0
  79. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/processtracking/custom_workflow_handler.py +0 -0
  80. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/processtracking/endpoints.py +0 -0
  81. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/recordmodel/__init__.py +0 -0
  82. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/recordmodel/record_handler.py +0 -0
  83. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/rules/__init__.py +0 -0
  84. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/rules/eln_rule_handler.py +0 -0
  85. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/rules/on_save_rule_handler.py +0 -0
  86. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/samples/aliquot.py +0 -0
  87. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/sftpconnect/__init__.py +0 -0
  88. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/sftpconnect/sftp_builder.py +0 -0
  89. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/webhook/__init__.py +0 -0
  90. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/webhook/webhook_context.py +0 -0
  91. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/webhook/webhook_handlers.py +0 -0
  92. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/src/sapiopycommons/webhook/webservice_handlers.py +0 -0
  93. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/AF-A0A009IHW8-F1-model_v4.cif +0 -0
  94. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/_do_not_add_init_py_here +0 -0
  95. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/accession_test.py +0 -0
  96. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/aliquot_test.py +0 -0
  97. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/bio_reg_test.py +0 -0
  98. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/chem_test.py +0 -0
  99. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/chem_test_curation_queue.py +0 -0
  100. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/curation_queue_test.sdf +0 -0
  101. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/data_type_models.py +0 -0
  102. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto/101_DEN084Y5_15_E01_008_clean.fcs +0 -0
  103. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto/101_DEN084Y5_15_E03_009_clean.fcs +0 -0
  104. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto/101_DEN084Y5_15_E05_010_clean.fcs +0 -0
  105. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto/8_color_ICS.wsp +0 -0
  106. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto/COVID19_W_001_O.fcs +0 -0
  107. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/flowcyto_test.py +0 -0
  108. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/kappa.chains.fasta +0 -0
  109. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/mafft_test.py +0 -0
  110. {sapiopycommons-2025.5.12a519 → sapiopycommons-2025.5.13a523}/tests/test.gb +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.5.12a519
3
+ Version: 2025.5.13a523
4
4
  Summary: Official Sapio Python API Utilities Package
5
5
  Project-URL: Homepage, https://github.com/sapiosciences
6
6
  Author-email: Jonathan Steck <jsteck@sapiosciences.com>, Yechen Qiao <yqiao@sapiosciences.com>
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sapiopycommons"
7
- version='2025.05.12a519'
7
+ version='2025.05.13a523'
8
8
  authors = [
9
9
  { name="Jonathan Steck", email="jsteck@sapiosciences.com" },
10
10
  { name="Yechen Qiao", email="yqiao@sapiosciences.com" },
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import logging
4
5
  import traceback
5
6
  from abc import abstractmethod, ABC
7
+ from logging import Logger
6
8
  from typing import Any, Iterable, Sequence
7
9
 
8
10
  from grpc import ServicerContext
9
- from sapiopylib.rest.User import SapioUser
11
+ from sapiopylib.rest.User import SapioUser, ensure_logger_initialized
10
12
  from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition
11
13
 
12
14
  from sapiopycommons.ai.api.fielddefinitions.proto.fields_pb2 import FieldValueMapPbo, FieldValuePbo
@@ -305,8 +307,8 @@ class ToolServiceBase(ToolServiceServicer, ABC):
305
307
  tool.setup(user, request, context)
306
308
  results: list[SapioToolResult] = tool.run(user)
307
309
  return True, results, tool.logs
308
- except Exception:
309
- tool.log_message(traceback.format_exc())
310
+ except Exception as e:
311
+ tool.log_exception("Exception occurred during tool execution.", e)
310
312
  return False, [], tool.logs
311
313
 
312
314
 
@@ -321,6 +323,7 @@ class ToolBase(ABC):
321
323
  outputs: list[ToolOutputDetailsPbo]
322
324
  configs: list[VeloxFieldDefPbo]
323
325
  logs: list[str]
326
+ logger: Logger
324
327
 
325
328
  user: SapioUser
326
329
  request: ProcessStepRequestPbo
@@ -341,6 +344,8 @@ class ToolBase(ABC):
341
344
  self.outputs = []
342
345
  self.configs = []
343
346
  self.logs = []
347
+ self.logger = logging.getLogger(f"ToolBase.{self.name}")
348
+ ensure_logger_initialized(self.logger)
344
349
 
345
350
  def setup(self, user: SapioUser, request: ProcessStepRequestPbo, context: ServicerContext) -> None:
346
351
  """
@@ -432,8 +437,8 @@ class ToolBase(ABC):
432
437
  """
433
438
  self.configs.append(ProtobufUtils.field_def_to_pbo(field))
434
439
 
435
- def add_boolean_config_field(self, field_name: str, display_name: str, description: str, default_value: bool) \
436
- -> None:
440
+ def add_boolean_config_field(self, field_name: str, display_name: str, description: str, default_value: bool,
441
+ optional: bool = False) -> None:
437
442
  """
438
443
  Add a boolean configuration field to the tool. This field will be used to configure the tool in the plan
439
444
  manager.
@@ -442,13 +447,14 @@ class ToolBase(ABC):
442
447
  :param display_name: The display name of the field.
443
448
  :param description: The description of the field.
444
449
  :param default_value: The default value of the field.
450
+ :param optional: If true, this field is optional. If false, this field is required.
445
451
  """
446
452
  self.configs.append(VeloxFieldDefPbo(
447
453
  data_field_type=FieldTypePbo.BOOLEAN,
448
454
  data_field_name=field_name,
449
455
  display_name=display_name,
450
456
  description=description,
451
- required=True,
457
+ required=not optional,
452
458
  editable=True,
453
459
  boolean_properties=BooleanPropertiesPbo(
454
460
  default_value=default_value
@@ -456,7 +462,8 @@ class ToolBase(ABC):
456
462
  ))
457
463
 
458
464
  def add_double_config_field(self, field_name: str, display_name: str, description: str, default_value: float,
459
- min_value: float = -10.**120, max_value: float = 10.**120, precision: int = 2) -> None:
465
+ min_value: float = -10.**120, max_value: float = 10.**120, precision: int = 2,
466
+ optional: bool = False) -> None:
460
467
  """
461
468
  Add a double configuration field to the tool. This field will be used to configure the tool in the plan
462
469
  manager.
@@ -468,13 +475,14 @@ class ToolBase(ABC):
468
475
  :param min_value: The minimum value of the field.
469
476
  :param max_value: The maximum value of the field.
470
477
  :param precision: The precision of the field.
478
+ :param optional: If true, this field is optional. If false, this field is required.
471
479
  """
472
480
  self.configs.append(VeloxFieldDefPbo(
473
481
  data_field_type=FieldTypePbo.DOUBLE,
474
482
  data_field_name=field_name,
475
483
  display_name=display_name,
476
484
  description=description,
477
- required=True,
485
+ required=not optional,
478
486
  editable=True,
479
487
  double_properties=DoublePropertiesPbo(
480
488
  default_value=default_value,
@@ -485,7 +493,8 @@ class ToolBase(ABC):
485
493
  ))
486
494
 
487
495
  def add_integer_config_field(self, field_name: str, display_name: str, description: str,
488
- default_value: int, min_value: int = -2**31, max_value: int = 2**31-1) -> None:
496
+ default_value: int, min_value: int = -2**31, max_value: int = 2**31-1,
497
+ optional: bool = False) -> None:
489
498
  """
490
499
  Add an integer configuration field to the tool. This field will be used to configure the tool in the plan
491
500
  manager.
@@ -496,13 +505,14 @@ class ToolBase(ABC):
496
505
  :param default_value: The default value of the field.
497
506
  :param min_value: The minimum value of the field.
498
507
  :param max_value: The maximum value of the field.
508
+ :param optional: If true, this field is optional. If false, this field is required.
499
509
  """
500
510
  self.configs.append(VeloxFieldDefPbo(
501
511
  data_field_type=FieldTypePbo.INTEGER,
502
512
  data_field_name=field_name,
503
513
  display_name=display_name,
504
514
  description=description,
505
- required=True,
515
+ required=not optional,
506
516
  editable=True,
507
517
  integer_properties=IntegerPropertiesPbo(
508
518
  default_value=default_value,
@@ -512,7 +522,7 @@ class ToolBase(ABC):
512
522
  ))
513
523
 
514
524
  def add_string_config_field(self, field_name: str, display_name: str, description: str,
515
- default_value: str, max_length: int = 1000) -> None:
525
+ default_value: str, max_length: int = 1000, optional: bool = False) -> None:
516
526
  """
517
527
  Add a string configuration field to the tool. This field will be used to configure the tool in the plan
518
528
  manager.
@@ -522,13 +532,14 @@ class ToolBase(ABC):
522
532
  :param description: The description of the field.
523
533
  :param default_value: The default value of the field.
524
534
  :param max_length: The maximum length of the field.
535
+ :param optional: If true, this field is optional. If false, this field is required.
525
536
  """
526
537
  self.configs.append(VeloxFieldDefPbo(
527
538
  data_field_type=FieldTypePbo.STRING,
528
539
  data_field_name=field_name,
529
540
  display_name=display_name,
530
541
  description=description,
531
- required=True,
542
+ required=not optional,
532
543
  editable=True,
533
544
  string_properties=StringPropertiesPbo(
534
545
  default_value=default_value,
@@ -537,7 +548,7 @@ class ToolBase(ABC):
537
548
  ))
538
549
 
539
550
  def add_list_config_field(self, field_name: str, display_name: str, description: str, default_value: str,
540
- allowed_values: list[str], direct_edit: bool = False) -> None:
551
+ allowed_values: list[str], direct_edit: bool = False, optional: bool = False) -> None:
541
552
  """
542
553
  Add a list configuration field to the tool. This field will be used to configure the tool in the plan
543
554
  manager.
@@ -549,13 +560,14 @@ class ToolBase(ABC):
549
560
  :param allowed_values: The list of allowed values for the field.
550
561
  :param direct_edit: If true, the user can enter a value that is not in the list of allowed values. If false,
551
562
  the user can only select from the list of allowed values.
563
+ :param optional: If true, this field is optional. If false, this field is required.
552
564
  """
553
565
  self.configs.append(VeloxFieldDefPbo(
554
566
  data_field_type=FieldTypePbo.SELECTION,
555
567
  data_field_name=field_name,
556
568
  display_name=display_name,
557
569
  description=description,
558
- required=True,
570
+ required=not optional,
559
571
  editable=True,
560
572
  selection_properties=SelectionPropertiesPbo(
561
573
  default_value=default_value,
@@ -565,8 +577,8 @@ class ToolBase(ABC):
565
577
  ))
566
578
 
567
579
  def add_multi_list_config_field(self, field_name: str, display_name: str, description: str,
568
- default_value: list[str], allowed_values: list[str], direct_edit: bool = False) \
569
- -> None:
580
+ default_value: list[str], allowed_values: list[str], direct_edit: bool = False,
581
+ optional: bool = False) -> None:
570
582
  """
571
583
  Add a multi-select list configuration field to the tool. This field will be used to configure the tool in the
572
584
  plan manager.
@@ -578,13 +590,14 @@ class ToolBase(ABC):
578
590
  :param allowed_values: The list of allowed values for the field.
579
591
  :param direct_edit: If true, the user can enter a value that is not in the list of allowed values. If false,
580
592
  the user can only select from the list of allowed values.
593
+ :param optional: If true, this field is optional. If false, this field is required.
581
594
  """
582
595
  self.configs.append(VeloxFieldDefPbo(
583
596
  data_field_type=FieldTypePbo.SELECTION,
584
597
  data_field_name=field_name,
585
598
  display_name=display_name,
586
599
  description=description,
587
- required=True,
600
+ required=not optional,
588
601
  editable=True,
589
602
  selection_properties=SelectionPropertiesPbo(
590
603
  default_value=",".join(default_value),
@@ -624,16 +637,50 @@ class ToolBase(ABC):
624
637
  """
625
638
  pass
626
639
 
627
- def log_message(self, message: str, verbose: bool = False) -> None:
640
+ def log_info(self, message: str) -> None:
641
+ """
642
+ Log an info message for this tool. If verbose logging is enabled, this message will be included in the logs
643
+ returned to the caller.
644
+ .
645
+
646
+ :param message: The message to log.
647
+ """
648
+ msg = f"INFO: {self.name}: {message}"
649
+ if self.verbose_logging:
650
+ self.logs.append(msg)
651
+ self.logger.info(msg)
652
+
653
+ def log_warning(self, message: str) -> None:
654
+ """
655
+ Log a warning message for this tool. This message will be included in the logs returned to the caller.
656
+
657
+ :param message: The message to log.
658
+ """
659
+ msg = f"WARNING: {self.name}: {message}"
660
+ self.logs.append(msg)
661
+ self.logger.warning(msg)
662
+
663
+ def log_error(self, message: str) -> None:
664
+ """
665
+ Log an error message for this tool. This message will be included in the logs returned to the caller.
666
+
667
+ :param message: The message to log.
668
+ """
669
+ msg = f"ERROR: {self.name}: {message}"
670
+ self.logs.append(msg)
671
+ self.logger.error(msg)
672
+
673
+ def log_exception(self, message: str, e: Exception) -> None:
628
674
  """
629
- Log a message for this tool. This message will be included in the logs returned to the caller.
675
+ Log an exception for this tool. This message will be included in the logs returned to the caller.
630
676
 
631
677
  :param message: The message to log.
632
- :param verbose: If true, the message will only be logged if verbose logging is enabled. If false, the message
633
- will be logged regardless of the verbose logging setting.
678
+ :param e: The exception to log.
634
679
  """
635
- if not verbose or self.verbose_logging:
636
- self.logs.append(f"{self.name}: {message}")
680
+ msg = f"EXCEPTION: {self.name}: {message} - {e}"
681
+ self.logs.append(msg)
682
+ msg += "\n" + traceback.format_exc()
683
+ self.logger.error(msg)
637
684
 
638
685
  def get_input_binary(self, index: int = 0) -> list[bytes]:
639
686
  """