sapiopycommons 2025.7.18a620__tar.gz → 2025.7.21a630__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.
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/PKG-INFO +2 -2
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/pyproject.toml +2 -2
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.py +16 -14
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2.pyi +22 -4
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/protobuf_utils.py +1 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/test_client.py +1 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/tool_service_base.py +143 -66
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/callbacks/callback_util.py +665 -332
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/callbacks/field_builder.py +2 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/chem/IndigoMolecules.py +29 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/chem/Molecules.py +3 -3
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/customreport/auto_pagers.py +26 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/customreport/term_builder.py +1 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/datatype/pseudo_data_types.py +349 -326
- sapiopycommons-2025.7.21a630/src/sapiopycommons/eln/experiment_cache.py +188 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/eln/experiment_handler.py +408 -767
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/eln/experiment_report_util.py +11 -6
- sapiopycommons-2025.7.21a630/src/sapiopycommons/eln/experiment_step_factory.py +476 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/eln/plate_designer.py +7 -2
- sapiopycommons-2025.7.21a630/src/sapiopycommons/eln/step_creation.py +236 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_util.py +7 -5
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/accession_service.py +2 -2
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/aliases.py +3 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/audit_log.py +7 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/custom_report_util.py +12 -0
- sapiopycommons-2025.7.21a630/src/sapiopycommons/general/data_structure_util.py +115 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/processtracking/custom_workflow_handler.py +11 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/processtracking/endpoints.py +27 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/recordmodel/record_handler.py +783 -389
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/rules/eln_rule_handler.py +8 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/rules/on_save_rule_handler.py +8 -1
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/webhook/webhook_handlers.py +9 -4
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/webhook/webservice_handlers.py +2 -2
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/.gitignore +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/LICENSE +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/README.md +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_output_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/proto/step_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/script/proto/script_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/entry_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/plan/tool/proto/tool_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2.pyi +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/api/session/proto/sapio_conn_info_pb2_grpc.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/callbacks/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/chem/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/customreport/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/customreport/column_builder.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/customreport/custom_report_builder.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/datatype/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/datatype/attachment_util.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/datatype/data_fields.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/eln/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/eln/experiment_tags.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/complex_data_loader.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_bridge.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_bridge_handler.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_data_handler.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_validator.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/files/file_writer.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/flowcyto/flow_cyto.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/flowcyto/flowcyto_data.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/directive_util.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/exceptions.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/html_formatter.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/popup_util.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/sapio_links.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/storage_util.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/general/time_util.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/multimodal/multimodal.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/multimodal/multimodal_data.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/processtracking/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/recordmodel/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/rules/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/samples/aliquot.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/sftpconnect/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/sftpconnect/sftp_builder.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/webhook/__init__.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/webhook/webhook_context.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/AF-A0A009IHW8-F1-model_v4.cif +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/_do_not_add_init_py_here +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/accession_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/aliquot_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/bio_reg_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/chem_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/chem_test_curation_queue.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/curation_queue_test.sdf +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/data_type_models.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto/101_DEN084Y5_15_E01_008_clean.fcs +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto/101_DEN084Y5_15_E03_009_clean.fcs +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto/101_DEN084Y5_15_E05_010_clean.fcs +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto/8_color_ICS.wsp +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto/COVID19_W_001_O.fcs +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/flowcyto_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/kappa.chains.fasta +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/mafft_test.py +0 -0
- {sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/tests/test.gb +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sapiopycommons
|
|
3
|
-
Version: 2025.7.
|
|
3
|
+
Version: 2025.7.21a630
|
|
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>
|
|
@@ -17,7 +17,7 @@ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Requires-Python: >=3.10
|
|
19
19
|
Requires-Dist: databind>=4.5
|
|
20
|
-
Requires-Dist: sapiopylib>=
|
|
20
|
+
Requires-Dist: sapiopylib>=2025.4.17.264
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sapiopycommons"
|
|
7
|
-
version='2025.07.
|
|
7
|
+
version='2025.07.21a630'
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Jonathan Steck", email="jsteck@sapiosciences.com" },
|
|
10
10
|
{ name="Yechen Qiao", email="yqiao@sapiosciences.com" },
|
|
@@ -14,7 +14,7 @@ license = "MPL-2.0"
|
|
|
14
14
|
readme = "README.md"
|
|
15
15
|
requires-python = ">=3.10"
|
|
16
16
|
dependencies = [
|
|
17
|
-
'sapiopylib>=
|
|
17
|
+
'sapiopylib>=2025.4.17.264', 'databind>=4.5'
|
|
18
18
|
]
|
|
19
19
|
classifiers = [
|
|
20
20
|
"Intended Audience :: Developers",
|
|
@@ -34,7 +34,7 @@ from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import *
|
|
|
34
34
|
from sapiopycommons.ai.api.plan.proto.step_pb2 import *
|
|
35
35
|
from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import *
|
|
36
36
|
|
|
37
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n0sapiopycommons/ai/api/plan/tool/proto/tool.proto\x1a\x39sapiopycommons/ai/api/fielddefinitions/proto/fields.proto\x1a\x42sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def.proto\x1a\x31sapiopycommons/ai/api/plan/tool/proto/entry.proto\x1a+sapiopycommons/ai/api/plan/proto/step.proto\x1a\x39sapiopycommons/ai/api/session/proto/sapio_conn_info.proto\"R\n\x13\x45xampleContainerPbo\x12\x16\n\x0ctext_example\x18\x01 \x01(\tH\x00\x12\x18\n\x0e\x62inary_example\x18\x02 \x01(\x0cH\x00\x42\t\n\x07\x65xample\"\xe9\x01\n\x13ToolIoConfigBasePbo\x12\x14\n\x0c\x63ontent_type\x18\x01 \x01(\t\x12\x11\n\tio_number\x18\x02 \x01(\x05\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x1e\n\x16\x64\x65precated_old_example\x18\x05 \x01(\t\x12/\n\x11structure_example\x18\x06 \x01(\x0b\x32\x14.ExampleContainerPbo\x12-\n\x0ftesting_example\x18\x07 \x01(\x0b\x32\x14.ExampleContainerPbo\"\xd9\x02\n\x13ToolInputDetailsPbo\x12)\n\x0b\x62\x61se_config\x18\x01 \x01(\x0b\x32\x14.ToolIoConfigBasePbo\x12\x12\n\nvalidation\x18\x02 \x01(\t\x12\x1c\n\x0fmin_input_count\x18\x03 \x01(\x05H\x00\x88\x01\x01\x12\x1c\n\x0fmax_input_count\x18\x04 \x01(\x05H\x01\x88\x01\x01\x12\r\n\x05paged\x18\x05 \x01(\x08\x12\x1a\n\rmin_page_size\x18\x06 \x01(\x05H\x02\x88\x01\x01\x12\x1a\n\rmax_page_size\x18\x07 \x01(\x05H\x03\x88\x01\x01\x12\x1e\n\x11max_request_bytes\x18\x08 \x01(\x05H\x04\x88\x01\x01\x42\x12\n\x10_min_input_countB\x12\n\x10_max_input_countB\x10\n\x0e_min_page_sizeB\x10\n\x0e_max_page_sizeB\x14\n\x12_max_request_bytes\"A\n\x14ToolOutputDetailsPbo\x12)\n\x0b\x62\x61se_config\x18\x01 \x01(\x0b\x32\x14.ToolIoConfigBasePbo\"\
|
|
37
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n0sapiopycommons/ai/api/plan/tool/proto/tool.proto\x1a\x39sapiopycommons/ai/api/fielddefinitions/proto/fields.proto\x1a\x42sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def.proto\x1a\x31sapiopycommons/ai/api/plan/tool/proto/entry.proto\x1a+sapiopycommons/ai/api/plan/proto/step.proto\x1a\x39sapiopycommons/ai/api/session/proto/sapio_conn_info.proto\"R\n\x13\x45xampleContainerPbo\x12\x16\n\x0ctext_example\x18\x01 \x01(\tH\x00\x12\x18\n\x0e\x62inary_example\x18\x02 \x01(\x0cH\x00\x42\t\n\x07\x65xample\"\xe9\x01\n\x13ToolIoConfigBasePbo\x12\x14\n\x0c\x63ontent_type\x18\x01 \x01(\t\x12\x11\n\tio_number\x18\x02 \x01(\x05\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x04 \x01(\t\x12\x1e\n\x16\x64\x65precated_old_example\x18\x05 \x01(\t\x12/\n\x11structure_example\x18\x06 \x01(\x0b\x32\x14.ExampleContainerPbo\x12-\n\x0ftesting_example\x18\x07 \x01(\x0b\x32\x14.ExampleContainerPbo\"\xd9\x02\n\x13ToolInputDetailsPbo\x12)\n\x0b\x62\x61se_config\x18\x01 \x01(\x0b\x32\x14.ToolIoConfigBasePbo\x12\x12\n\nvalidation\x18\x02 \x01(\t\x12\x1c\n\x0fmin_input_count\x18\x03 \x01(\x05H\x00\x88\x01\x01\x12\x1c\n\x0fmax_input_count\x18\x04 \x01(\x05H\x01\x88\x01\x01\x12\r\n\x05paged\x18\x05 \x01(\x08\x12\x1a\n\rmin_page_size\x18\x06 \x01(\x05H\x02\x88\x01\x01\x12\x1a\n\rmax_page_size\x18\x07 \x01(\x05H\x03\x88\x01\x01\x12\x1e\n\x11max_request_bytes\x18\x08 \x01(\x05H\x04\x88\x01\x01\x42\x12\n\x10_min_input_countB\x12\n\x10_max_input_countB\x10\n\x0e_min_page_sizeB\x10\n\x0e_max_page_sizeB\x14\n\x12_max_request_bytes\"A\n\x14ToolOutputDetailsPbo\x12)\n\x0b\x62\x61se_config\x18\x01 \x01(\x0b\x32\x14.ToolIoConfigBasePbo\"\xd5\x03\n\x15ProcessStepRequestPbo\x12+\n\nsapio_user\x18\x01 \x01(\x0b\x32\x17.SapioConnectionInfoPbo\x12\x11\n\ttool_name\x18\x02 \x01(\t\x12\x18\n\x10plan_instance_id\x18\x03 \x01(\x03\x12\x18\n\x10step_instance_id\x18\x04 \x01(\x03\x12\x15\n\rinvocation_id\x18\x05 \x01(\x03\x12%\n\rinput_configs\x18\x06 \x03(\x0b\x32\x0e.StepIoInfoPbo\x12&\n\x0eoutput_configs\x18\x07 \x03(\x0b\x32\x0e.StepIoInfoPbo\x12J\n\x13\x63onfig_field_values\x18\x08 \x03(\x0b\x32-.ProcessStepRequestPbo.ConfigFieldValuesEntry\x12\x0f\n\x07\x64ry_run\x18\t \x01(\x08\x12\x17\n\x0fverbose_logging\x18\n \x01(\x08\x12\"\n\x05input\x18\xff\x0f \x03(\x0b\x32\x12.StepInputBatchPbo\x1aH\n\x16\x43onfigFieldValuesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x1d\n\x05value\x18\x02 \x01(\x0b\x32\x0e.FieldValuePbo:\x02\x38\x01\"\xbc\x01\n\x16ProcessStepResponsePbo\x12-\n\x06status\x18\x01 \x01(\x0e\x32\x1d.ProcessStepResponseStatusPbo\x12\x16\n\x0estatus_message\x18\x02 \x01(\t\x12\'\n\x0bnew_records\x18\xfd\x0f \x03(\x0b\x32\x11.FieldValueMapPbo\x12\x0c\n\x03log\x18\xfe\x0f \x03(\t\x12$\n\x06output\x18\xff\x0f \x03(\x0b\x32\x13.StepOutputBatchPbo\"I\n\x15ToolDetailsRequestPbo\x12\x30\n\x0fsapio_conn_info\x18\x01 \x01(\x0b\x32\x17.SapioConnectionInfoPbo\"\xd8\x01\n\x0eToolDetailsPbo\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x1d\n\x15output_data_type_name\x18\x04 \x01(\t\x12+\n\rinput_configs\x18\x05 \x03(\x0b\x32\x14.ToolInputDetailsPbo\x12-\n\x0eoutput_configs\x18\x06 \x03(\x0b\x32\x15.ToolOutputDetailsPbo\x12(\n\rconfig_fields\x18\x07 \x03(\x0b\x32\x11.VeloxFieldDefPbo\"_\n\x16ToolDetailsResponsePbo\x12\x1e\n\x16tool_framework_version\x18\x01 \x01(\x05\x12%\n\x0ctool_details\x18\x02 \x03(\x0b\x32\x0f.ToolDetailsPbo*E\n\x1cProcessStepResponseStatusPbo\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07SUCCESS\x10\x01\x12\x0b\n\x07\x46\x41ILURE\x10\x02\x32\x90\x01\n\x0bToolService\x12\x41\n\x0eGetToolDetails\x12\x16.ToolDetailsRequestPbo\x1a\x17.ToolDetailsResponsePbo\x12>\n\x0bProcessData\x12\x16.ProcessStepRequestPbo\x1a\x17.ProcessStepResponsePboB!\n\x1d\x63om.velox.api.plan.tool.protoP\x01P\x00P\x01P\x02P\x03P\x04\x62\x06proto3')
|
|
38
38
|
|
|
39
39
|
_globals = globals()
|
|
40
40
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -44,6 +44,8 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
44
44
|
_globals['DESCRIPTOR']._serialized_options = b'\n\035com.velox.api.plan.tool.protoP\001'
|
|
45
45
|
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._loaded_options = None
|
|
46
46
|
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._serialized_options = b'8\001'
|
|
47
|
+
_globals['_PROCESSSTEPRESPONSESTATUSPBO']._serialized_start=2123
|
|
48
|
+
_globals['_PROCESSSTEPRESPONSESTATUSPBO']._serialized_end=2192
|
|
47
49
|
_globals['_EXAMPLECONTAINERPBO']._serialized_start=334
|
|
48
50
|
_globals['_EXAMPLECONTAINERPBO']._serialized_end=416
|
|
49
51
|
_globals['_TOOLIOCONFIGBASEPBO']._serialized_start=419
|
|
@@ -53,17 +55,17 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
53
55
|
_globals['_TOOLOUTPUTDETAILSPBO']._serialized_start=1002
|
|
54
56
|
_globals['_TOOLOUTPUTDETAILSPBO']._serialized_end=1067
|
|
55
57
|
_globals['_PROCESSSTEPREQUESTPBO']._serialized_start=1070
|
|
56
|
-
_globals['_PROCESSSTEPREQUESTPBO']._serialized_end=
|
|
57
|
-
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._serialized_start=
|
|
58
|
-
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._serialized_end=
|
|
59
|
-
_globals['_PROCESSSTEPRESPONSEPBO']._serialized_start=
|
|
60
|
-
_globals['_PROCESSSTEPRESPONSEPBO']._serialized_end=
|
|
61
|
-
_globals['_TOOLDETAILSREQUESTPBO']._serialized_start=
|
|
62
|
-
_globals['_TOOLDETAILSREQUESTPBO']._serialized_end=
|
|
63
|
-
_globals['_TOOLDETAILSPBO']._serialized_start=
|
|
64
|
-
_globals['_TOOLDETAILSPBO']._serialized_end=
|
|
65
|
-
_globals['_TOOLDETAILSRESPONSEPBO']._serialized_start=
|
|
66
|
-
_globals['_TOOLDETAILSRESPONSEPBO']._serialized_end=
|
|
67
|
-
_globals['_TOOLSERVICE']._serialized_start=
|
|
68
|
-
_globals['_TOOLSERVICE']._serialized_end=
|
|
58
|
+
_globals['_PROCESSSTEPREQUESTPBO']._serialized_end=1539
|
|
59
|
+
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._serialized_start=1467
|
|
60
|
+
_globals['_PROCESSSTEPREQUESTPBO_CONFIGFIELDVALUESENTRY']._serialized_end=1539
|
|
61
|
+
_globals['_PROCESSSTEPRESPONSEPBO']._serialized_start=1542
|
|
62
|
+
_globals['_PROCESSSTEPRESPONSEPBO']._serialized_end=1730
|
|
63
|
+
_globals['_TOOLDETAILSREQUESTPBO']._serialized_start=1732
|
|
64
|
+
_globals['_TOOLDETAILSREQUESTPBO']._serialized_end=1805
|
|
65
|
+
_globals['_TOOLDETAILSPBO']._serialized_start=1808
|
|
66
|
+
_globals['_TOOLDETAILSPBO']._serialized_end=2024
|
|
67
|
+
_globals['_TOOLDETAILSRESPONSEPBO']._serialized_start=2026
|
|
68
|
+
_globals['_TOOLDETAILSRESPONSEPBO']._serialized_end=2121
|
|
69
|
+
_globals['_TOOLSERVICE']._serialized_start=2195
|
|
70
|
+
_globals['_TOOLSERVICE']._serialized_end=2339
|
|
69
71
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -4,6 +4,7 @@ from sapiopycommons.ai.api.plan.tool.proto import entry_pb2 as _entry_pb2
|
|
|
4
4
|
from sapiopycommons.ai.api.plan.proto import step_pb2 as _step_pb2
|
|
5
5
|
from sapiopycommons.ai.api.session.proto import sapio_conn_info_pb2 as _sapio_conn_info_pb2
|
|
6
6
|
from google.protobuf.internal import containers as _containers
|
|
7
|
+
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
|
7
8
|
from google.protobuf import descriptor as _descriptor
|
|
8
9
|
from google.protobuf import message as _message
|
|
9
10
|
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
|
|
@@ -110,6 +111,15 @@ IMAGE: _entry_pb2.DataTypePbo
|
|
|
110
111
|
SESSION_TOKEN: _sapio_conn_info_pb2.SapioUserSecretTypePbo
|
|
111
112
|
PASSWORD: _sapio_conn_info_pb2.SapioUserSecretTypePbo
|
|
112
113
|
|
|
114
|
+
class ProcessStepResponseStatusPbo(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
115
|
+
__slots__ = ()
|
|
116
|
+
UNKNOWN: _ClassVar[ProcessStepResponseStatusPbo]
|
|
117
|
+
SUCCESS: _ClassVar[ProcessStepResponseStatusPbo]
|
|
118
|
+
FAILURE: _ClassVar[ProcessStepResponseStatusPbo]
|
|
119
|
+
UNKNOWN: ProcessStepResponseStatusPbo
|
|
120
|
+
SUCCESS: ProcessStepResponseStatusPbo
|
|
121
|
+
FAILURE: ProcessStepResponseStatusPbo
|
|
122
|
+
|
|
113
123
|
class ExampleContainerPbo(_message.Message):
|
|
114
124
|
__slots__ = ("text_example", "binary_example")
|
|
115
125
|
TEXT_EXAMPLE_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -163,7 +173,7 @@ class ToolOutputDetailsPbo(_message.Message):
|
|
|
163
173
|
def __init__(self, base_config: _Optional[_Union[ToolIoConfigBasePbo, _Mapping]] = ...) -> None: ...
|
|
164
174
|
|
|
165
175
|
class ProcessStepRequestPbo(_message.Message):
|
|
166
|
-
__slots__ = ("sapio_user", "tool_name", "plan_instance_id", "step_instance_id", "invocation_id", "input_configs", "output_configs", "config_field_values", "input")
|
|
176
|
+
__slots__ = ("sapio_user", "tool_name", "plan_instance_id", "step_instance_id", "invocation_id", "input_configs", "output_configs", "config_field_values", "dry_run", "verbose_logging", "input")
|
|
167
177
|
class ConfigFieldValuesEntry(_message.Message):
|
|
168
178
|
__slots__ = ("key", "value")
|
|
169
179
|
KEY_FIELD_NUMBER: _ClassVar[int]
|
|
@@ -179,6 +189,8 @@ class ProcessStepRequestPbo(_message.Message):
|
|
|
179
189
|
INPUT_CONFIGS_FIELD_NUMBER: _ClassVar[int]
|
|
180
190
|
OUTPUT_CONFIGS_FIELD_NUMBER: _ClassVar[int]
|
|
181
191
|
CONFIG_FIELD_VALUES_FIELD_NUMBER: _ClassVar[int]
|
|
192
|
+
DRY_RUN_FIELD_NUMBER: _ClassVar[int]
|
|
193
|
+
VERBOSE_LOGGING_FIELD_NUMBER: _ClassVar[int]
|
|
182
194
|
INPUT_FIELD_NUMBER: _ClassVar[int]
|
|
183
195
|
sapio_user: _sapio_conn_info_pb2.SapioConnectionInfoPbo
|
|
184
196
|
tool_name: str
|
|
@@ -188,18 +200,24 @@ class ProcessStepRequestPbo(_message.Message):
|
|
|
188
200
|
input_configs: _containers.RepeatedCompositeFieldContainer[_step_pb2.StepIoInfoPbo]
|
|
189
201
|
output_configs: _containers.RepeatedCompositeFieldContainer[_step_pb2.StepIoInfoPbo]
|
|
190
202
|
config_field_values: _containers.MessageMap[str, _fields_pb2.FieldValuePbo]
|
|
203
|
+
dry_run: bool
|
|
204
|
+
verbose_logging: bool
|
|
191
205
|
input: _containers.RepeatedCompositeFieldContainer[_entry_pb2.StepInputBatchPbo]
|
|
192
|
-
def __init__(self, sapio_user: _Optional[_Union[_sapio_conn_info_pb2.SapioConnectionInfoPbo, _Mapping]] = ..., tool_name: _Optional[str] = ..., plan_instance_id: _Optional[int] = ..., step_instance_id: _Optional[int] = ..., invocation_id: _Optional[int] = ..., input_configs: _Optional[_Iterable[_Union[_step_pb2.StepIoInfoPbo, _Mapping]]] = ..., output_configs: _Optional[_Iterable[_Union[_step_pb2.StepIoInfoPbo, _Mapping]]] = ..., config_field_values: _Optional[_Mapping[str, _fields_pb2.FieldValuePbo]] = ..., input: _Optional[_Iterable[_Union[_entry_pb2.StepInputBatchPbo, _Mapping]]] = ...) -> None: ...
|
|
206
|
+
def __init__(self, sapio_user: _Optional[_Union[_sapio_conn_info_pb2.SapioConnectionInfoPbo, _Mapping]] = ..., tool_name: _Optional[str] = ..., plan_instance_id: _Optional[int] = ..., step_instance_id: _Optional[int] = ..., invocation_id: _Optional[int] = ..., input_configs: _Optional[_Iterable[_Union[_step_pb2.StepIoInfoPbo, _Mapping]]] = ..., output_configs: _Optional[_Iterable[_Union[_step_pb2.StepIoInfoPbo, _Mapping]]] = ..., config_field_values: _Optional[_Mapping[str, _fields_pb2.FieldValuePbo]] = ..., dry_run: bool = ..., verbose_logging: bool = ..., input: _Optional[_Iterable[_Union[_entry_pb2.StepInputBatchPbo, _Mapping]]] = ...) -> None: ...
|
|
193
207
|
|
|
194
208
|
class ProcessStepResponsePbo(_message.Message):
|
|
195
|
-
__slots__ = ("new_records", "log", "output")
|
|
209
|
+
__slots__ = ("status", "status_message", "new_records", "log", "output")
|
|
210
|
+
STATUS_FIELD_NUMBER: _ClassVar[int]
|
|
211
|
+
STATUS_MESSAGE_FIELD_NUMBER: _ClassVar[int]
|
|
196
212
|
NEW_RECORDS_FIELD_NUMBER: _ClassVar[int]
|
|
197
213
|
LOG_FIELD_NUMBER: _ClassVar[int]
|
|
198
214
|
OUTPUT_FIELD_NUMBER: _ClassVar[int]
|
|
215
|
+
status: ProcessStepResponseStatusPbo
|
|
216
|
+
status_message: str
|
|
199
217
|
new_records: _containers.RepeatedCompositeFieldContainer[_fields_pb2.FieldValueMapPbo]
|
|
200
218
|
log: _containers.RepeatedScalarFieldContainer[str]
|
|
201
219
|
output: _containers.RepeatedCompositeFieldContainer[_entry_pb2.StepOutputBatchPbo]
|
|
202
|
-
def __init__(self, new_records: _Optional[_Iterable[_Union[_fields_pb2.FieldValueMapPbo, _Mapping]]] = ..., log: _Optional[_Iterable[str]] = ..., output: _Optional[_Iterable[_Union[_entry_pb2.StepOutputBatchPbo, _Mapping]]] = ...) -> None: ...
|
|
220
|
+
def __init__(self, status: _Optional[_Union[ProcessStepResponseStatusPbo, str]] = ..., status_message: _Optional[str] = ..., new_records: _Optional[_Iterable[_Union[_fields_pb2.FieldValueMapPbo, _Mapping]]] = ..., log: _Optional[_Iterable[str]] = ..., output: _Optional[_Iterable[_Union[_entry_pb2.StepOutputBatchPbo, _Mapping]]] = ...) -> None: ...
|
|
203
221
|
|
|
204
222
|
class ToolDetailsRequestPbo(_message.Message):
|
|
205
223
|
__slots__ = ("sapio_conn_info",)
|
|
@@ -22,6 +22,7 @@ from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import DataTypePbo
|
|
|
22
22
|
from sapiopycommons.general.aliases import FieldValue
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
# FR-47422: Created class.
|
|
25
26
|
class ProtobufUtils:
|
|
26
27
|
@staticmethod
|
|
27
28
|
def content_type_str(content_type: DataTypePbo) -> str:
|
{sapiopycommons-2025.7.18a620 → sapiopycommons-2025.7.21a630}/src/sapiopycommons/ai/test_client.py
RENAMED
|
@@ -13,6 +13,7 @@ from sapiopycommons.ai.api.plan.tool.proto.tool_pb2_grpc import ToolServiceStub
|
|
|
13
13
|
from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import SapioConnectionInfoPbo, SapioUserSecretTypePbo
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
# FR-47422: Created class.
|
|
16
17
|
class ToolOutput:
|
|
17
18
|
"""
|
|
18
19
|
A class for holding the output of a TestClient that calls a ToolService. ToolOutput objects an be
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import base64
|
|
4
|
+
import io
|
|
3
5
|
import json
|
|
4
6
|
import logging
|
|
7
|
+
import re
|
|
5
8
|
import traceback
|
|
6
9
|
from abc import abstractmethod, ABC
|
|
7
10
|
from logging import Logger
|
|
@@ -19,13 +22,15 @@ from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import StepOutputBatchPbo,
|
|
|
19
22
|
StepJsonContainerPbo, StepTextContainerPbo, StepInputBatchPbo
|
|
20
23
|
from sapiopycommons.ai.api.plan.tool.proto.tool_pb2 import ToolDetailsRequestPbo, ToolDetailsResponsePbo, \
|
|
21
24
|
ToolDetailsPbo, ProcessStepRequestPbo, ProcessStepResponsePbo, ToolOutputDetailsPbo, ToolIoConfigBasePbo, \
|
|
22
|
-
ToolInputDetailsPbo, ExampleContainerPbo
|
|
25
|
+
ToolInputDetailsPbo, ExampleContainerPbo, ProcessStepResponseStatusPbo
|
|
23
26
|
from sapiopycommons.ai.api.plan.tool.proto.tool_pb2_grpc import ToolServiceServicer
|
|
24
27
|
from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import SapioUserSecretTypePbo, SapioConnectionInfoPbo
|
|
25
28
|
from sapiopycommons.ai.protobuf_utils import ProtobufUtils
|
|
29
|
+
from sapiopycommons.files.file_util import FileUtil
|
|
26
30
|
from sapiopycommons.general.aliases import FieldMap, FieldValue
|
|
27
31
|
|
|
28
32
|
|
|
33
|
+
# FR-47422: Created classes.
|
|
29
34
|
class SapioToolResult(ABC):
|
|
30
35
|
"""
|
|
31
36
|
A class representing a result from a Sapio tool. Instantiate one of the subclasses to create a result object.
|
|
@@ -194,84 +199,71 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
194
199
|
def GetToolDetails(self, request: ToolDetailsRequestPbo, context: ServicerContext) -> ToolDetailsResponsePbo:
|
|
195
200
|
try:
|
|
196
201
|
# Get the tool details from the registered tools.
|
|
197
|
-
details: list[ToolDetailsPbo] =
|
|
202
|
+
details: list[ToolDetailsPbo] = []
|
|
203
|
+
for tool in self._initialize_tools():
|
|
204
|
+
details.append(tool.to_pbo())
|
|
198
205
|
return ToolDetailsResponsePbo(tool_framework_version=self.tool_version(), tool_details=details)
|
|
199
206
|
except Exception:
|
|
200
|
-
#
|
|
207
|
+
# Woe to you if you somehow cause an exception to be raised when just initializing your tools.
|
|
208
|
+
# There's no way to log this.
|
|
201
209
|
return ToolDetailsResponsePbo()
|
|
202
210
|
|
|
203
211
|
def ProcessData(self, request: ProcessStepRequestPbo, context: ServicerContext) -> ProcessStepResponsePbo:
|
|
204
212
|
try:
|
|
205
213
|
# Convert the SapioConnectionInfo proto object to a SapioUser object.
|
|
206
|
-
user = self.
|
|
207
|
-
# Get the tool results from the registered tool matching the request
|
|
214
|
+
user = self._create_user(request.sapio_user)
|
|
215
|
+
# Get the tool results from the registered tool matching the request.
|
|
216
|
+
success, msg, results, logs = self.run(user, request, context)
|
|
217
|
+
# Convert the results to protobuf objects.
|
|
208
218
|
output_data: list[StepOutputBatchPbo] = []
|
|
209
219
|
new_records: list[FieldValueMapPbo] = []
|
|
210
|
-
# TODO: Make use of the success value after the response object has a field for it.
|
|
211
|
-
success, results, logs = self.run(user, request, context)
|
|
212
220
|
for result in results:
|
|
213
221
|
data: StepOutputBatchPbo | list[FieldValueMapPbo] = result.to_proto()
|
|
214
222
|
if isinstance(data, StepOutputBatchPbo):
|
|
215
223
|
output_data.append(data)
|
|
216
224
|
else:
|
|
217
225
|
new_records.extend(data)
|
|
218
|
-
# Return a ProcessStepResponse proto object containing the
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
# Return a ProcessStepResponse proto object containing the results to the caller.
|
|
227
|
+
status = ProcessStepResponseStatusPbo.SUCCESS if success else ProcessStepResponseStatusPbo.FAILURE
|
|
228
|
+
return ProcessStepResponsePbo(status=status, status_message=msg, output=output_data, log=logs,
|
|
229
|
+
new_records=new_records)
|
|
230
|
+
except Exception as e:
|
|
231
|
+
# This try/except should never be needed, as the tool should handle its own exceptions, but better safe
|
|
232
|
+
# than sorry.
|
|
233
|
+
return ProcessStepResponsePbo(status=ProcessStepResponseStatusPbo.FAILURE,
|
|
234
|
+
status_message=f"CRITICAL ERROR: {e}",
|
|
235
|
+
log=[traceback.format_exc()])
|
|
223
236
|
|
|
224
237
|
@staticmethod
|
|
225
|
-
def
|
|
238
|
+
def _create_user(info: SapioConnectionInfoPbo, timeout_seconds: int = 60) -> SapioUser:
|
|
226
239
|
"""
|
|
227
240
|
Create a SapioUser object from the given SapioConnectionInfo proto object.
|
|
228
241
|
|
|
229
242
|
:param info: The SapioConnectionInfo proto object.
|
|
230
243
|
:param timeout_seconds: The request timeout for calls made from this user object.
|
|
231
244
|
"""
|
|
232
|
-
# TODO: Have a customizable request timeout? Would need to be added to the request object.
|
|
233
|
-
# TODO: How should the RMI hosts and port be used in the connection info?
|
|
234
245
|
user = SapioUser(info.webservice_url, True, timeout_seconds, guid=info.app_guid)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
246
|
+
match info.secret_type:
|
|
247
|
+
case SapioUserSecretTypePbo.SESSION_TOKEN:
|
|
248
|
+
user.api_token = info.secret
|
|
249
|
+
case SapioUserSecretTypePbo.PASSWORD:
|
|
250
|
+
secret: str = info.secret
|
|
251
|
+
if secret.startswith("Basic "):
|
|
252
|
+
secret = secret[6:]
|
|
253
|
+
credentials: list[str] = base64.b64decode(secret).decode().split(":")
|
|
254
|
+
user.username = credentials[0]
|
|
255
|
+
user.password = credentials[1]
|
|
256
|
+
case _:
|
|
257
|
+
raise Exception(f"Unexpected secret type: {info.secret_type}")
|
|
242
258
|
return user
|
|
243
259
|
|
|
244
260
|
@staticmethod
|
|
245
261
|
def tool_version() -> int:
|
|
246
262
|
"""
|
|
247
|
-
:return: The version of this
|
|
263
|
+
:return: The version of this set of tools.
|
|
248
264
|
"""
|
|
249
265
|
return 1
|
|
250
266
|
|
|
251
|
-
def _get_tools(self) -> list[ToolBase]:
|
|
252
|
-
"""
|
|
253
|
-
return: Get instances of the tools registered with this service.
|
|
254
|
-
"""
|
|
255
|
-
# This is complaining about the name and description not being filled from ToolBase,
|
|
256
|
-
# but none of the provided tools should have any init parameters.
|
|
257
|
-
# noinspection PyArgumentList
|
|
258
|
-
tools: list[ToolBase] = [x() for x in self.register_tools()]
|
|
259
|
-
if not tools:
|
|
260
|
-
raise Exception("No tools registered with this service.")
|
|
261
|
-
return tools
|
|
262
|
-
|
|
263
|
-
def _get_tool(self, name: str) -> ToolBase:
|
|
264
|
-
"""
|
|
265
|
-
Get a specific tool instance by its name.
|
|
266
|
-
|
|
267
|
-
:param name: The name of the tool to retrieve.
|
|
268
|
-
:return: The tool object corresponding to the given name.
|
|
269
|
-
"""
|
|
270
|
-
tools: dict[str, ToolBase] = {x.name: x for x in self._get_tools()}
|
|
271
|
-
if name not in tools:
|
|
272
|
-
raise Exception(f"Tool \"{name}\" not found in registered tools.")
|
|
273
|
-
return tools[name]
|
|
274
|
-
|
|
275
267
|
@abstractmethod
|
|
276
268
|
def register_tools(self) -> list[type[ToolBase]]:
|
|
277
269
|
"""
|
|
@@ -282,19 +274,20 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
282
274
|
"""
|
|
283
275
|
pass
|
|
284
276
|
|
|
285
|
-
def
|
|
277
|
+
def _initialize_tools(self) -> list[ToolBase]:
|
|
286
278
|
"""
|
|
287
|
-
Get
|
|
288
|
-
|
|
289
|
-
:return: A ToolDetailsResponse object containing the tool details.
|
|
279
|
+
return: Get instances of the tools registered with this service.
|
|
290
280
|
"""
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
281
|
+
# This is complaining about the name and description not being filled from ToolBase,
|
|
282
|
+
# but none of the provided tools should have any init parameters.
|
|
283
|
+
# noinspection PyArgumentList
|
|
284
|
+
tools: list[ToolBase] = [x() for x in self.register_tools()]
|
|
285
|
+
if not tools:
|
|
286
|
+
raise Exception("No tools registered with this service.")
|
|
287
|
+
return tools
|
|
295
288
|
|
|
296
289
|
def run(self, user: SapioUser, request: ProcessStepRequestPbo, context: ServicerContext) \
|
|
297
|
-
-> tuple[bool, list[SapioToolResult], list[str]]:
|
|
290
|
+
-> tuple[bool, str, list[SapioToolResult], list[str]]:
|
|
298
291
|
"""
|
|
299
292
|
Execute a tool from this service.
|
|
300
293
|
|
|
@@ -302,16 +295,38 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
302
295
|
system.
|
|
303
296
|
:param request: The request object containing the input data.
|
|
304
297
|
:param context: The gRPC context.
|
|
305
|
-
:return: Whether or not the tool succeeded, the results of the tool, and any logs
|
|
306
|
-
|
|
307
|
-
|
|
298
|
+
:return: Whether or not the tool succeeded, the status message, the results of the tool, and any logs
|
|
299
|
+
generated by the tool.
|
|
300
|
+
"""
|
|
301
|
+
# Locate the tool named in the request.
|
|
302
|
+
tool: ToolBase | None = None
|
|
303
|
+
for t in self._initialize_tools():
|
|
304
|
+
if t.name == request.tool_name:
|
|
305
|
+
tool = t
|
|
306
|
+
break
|
|
307
|
+
if not tool:
|
|
308
|
+
return False, f"Tool \"{request.tool_name}\" not found in the registered tools for this service.", [], []
|
|
309
|
+
|
|
308
310
|
try:
|
|
311
|
+
# Setup the tool with details from the request.
|
|
309
312
|
tool.setup(user, request, context)
|
|
310
|
-
|
|
311
|
-
|
|
313
|
+
# Validate that the provided inputs match the tool's expected inputs.
|
|
314
|
+
msg: str = tool.validate_input()
|
|
315
|
+
# If there is no error message, then the inputs are valid.
|
|
316
|
+
success: bool = not bool(msg)
|
|
317
|
+
# If this is a dry run, then provide the fixed dry run output.
|
|
318
|
+
# Otherwise, if the inputs were successfully validated, then the tool is executed normally.
|
|
319
|
+
results: list[SapioToolResult] = []
|
|
320
|
+
if request.dry_run:
|
|
321
|
+
results = tool.dry_run_output()
|
|
322
|
+
elif success:
|
|
323
|
+
results = tool.run(user)
|
|
324
|
+
# Update the status message to reflect the successful execution of the tool.
|
|
325
|
+
msg = f"{tool.name} successfully completed."
|
|
326
|
+
return success, msg, results, tool.logs
|
|
312
327
|
except Exception as e:
|
|
313
328
|
tool.log_exception("Exception occurred during tool execution.", e)
|
|
314
|
-
return False, [], tool.logs
|
|
329
|
+
return False, str(e), [], tool.logs
|
|
315
330
|
|
|
316
331
|
|
|
317
332
|
class ToolBase(ABC):
|
|
@@ -363,8 +378,7 @@ class ToolBase(ABC):
|
|
|
363
378
|
self.user = user
|
|
364
379
|
self.request = request
|
|
365
380
|
self.context = context
|
|
366
|
-
|
|
367
|
-
self.verbose_logging = False
|
|
381
|
+
self.verbose_logging = request.verbose_logging
|
|
368
382
|
|
|
369
383
|
def add_input(self, content_type: DataTypePbo, display_name: str, description: str,
|
|
370
384
|
structure_example: str | bytes | None = None, validation: str | None = None,
|
|
@@ -651,6 +665,69 @@ class ToolBase(ABC):
|
|
|
651
665
|
config_fields=self.configs
|
|
652
666
|
)
|
|
653
667
|
|
|
668
|
+
@abstractmethod
|
|
669
|
+
def validate_input(self) -> str | None:
|
|
670
|
+
"""
|
|
671
|
+
Validate the request given to this tool. If the request is validly formatted, this method should return None.
|
|
672
|
+
If the request is not valid, this method should return an error message indicating what is wrong with the
|
|
673
|
+
request.
|
|
674
|
+
|
|
675
|
+
This method should not perform any actual processing of the request. It should only validate the inputs and
|
|
676
|
+
configurations provided in the request.
|
|
677
|
+
|
|
678
|
+
The request inputs can be accessed using the self.get_input_*() methods.
|
|
679
|
+
The request settings can be accessed using the self.get_config_fields() method.
|
|
680
|
+
The request itself can be accessed using self.request.
|
|
681
|
+
|
|
682
|
+
:return: A tuple containing a boolean indicating whether the request is valid and a message describing the
|
|
683
|
+
result of the validation.
|
|
684
|
+
"""
|
|
685
|
+
pass
|
|
686
|
+
|
|
687
|
+
def dry_run_output(self) -> list[SapioToolResult]:
|
|
688
|
+
"""
|
|
689
|
+
Provide fixed results for a dry run of this tool. This method should not perform any actual processing of the
|
|
690
|
+
request. It should only return example outputs that can be used to test the next tool in the plan.
|
|
691
|
+
|
|
692
|
+
The default implementation of this method looks at the testing_example field of each output configuration
|
|
693
|
+
and returns a SapioToolResult object based on the content type of the output.
|
|
694
|
+
|
|
695
|
+
:return: A list of SapioToolResult objects containing example outputs for this tool. Each result in the list
|
|
696
|
+
corresponds to a separate output from the tool.
|
|
697
|
+
"""
|
|
698
|
+
results: list[SapioToolResult] = []
|
|
699
|
+
for output in self.outputs:
|
|
700
|
+
example: Any = output.base_config.testing_example
|
|
701
|
+
match output.base_config.content_type:
|
|
702
|
+
case DataTypePbo.BINARY:
|
|
703
|
+
example: bytes
|
|
704
|
+
results.append(BinaryResult(binary_data=[example]))
|
|
705
|
+
case DataTypePbo.CSV:
|
|
706
|
+
example: str
|
|
707
|
+
results.append(CsvResult(FileUtil.tokenize_csv(example.encode())[0]))
|
|
708
|
+
case DataTypePbo.IMAGE:
|
|
709
|
+
example: bytes
|
|
710
|
+
# We can't know what the actual image format is, so just assume PNG. If this is wrong and having
|
|
711
|
+
# the correct image format is necessary for testing, then the tool should override this method to
|
|
712
|
+
# provide the correct format.
|
|
713
|
+
results.append(ImageResult(image_format="PNG", image_data=[example]))
|
|
714
|
+
case DataTypePbo.JSON:
|
|
715
|
+
# The example may be in the JSONL format instead of plain JSON, so we need to use Pandas to parse
|
|
716
|
+
# the example into plain JSON.
|
|
717
|
+
example: str
|
|
718
|
+
# Format the JSONL in a way that Pandas likes. Collapse everything into a single line, and then
|
|
719
|
+
# split it back into multiple lines where each line is a single JSON list or dictionary.
|
|
720
|
+
example = re.sub("([]}])\s*([\[{])", r"\1\n\2", example.replace("\n", "")).strip()
|
|
721
|
+
# Read the JSONL into a Pandas DataFrame and convert it back to plain JSON.
|
|
722
|
+
import pandas as pd
|
|
723
|
+
with io.StringIO(example) as stream:
|
|
724
|
+
example = pd.read_json(path_or_buf=stream, lines=True).to_json()
|
|
725
|
+
results.append(JsonResult(json_data=[json.loads(example)]))
|
|
726
|
+
case DataTypePbo.TEXT:
|
|
727
|
+
example: str
|
|
728
|
+
results.append(TextResult(text_data=[example]))
|
|
729
|
+
return results
|
|
730
|
+
|
|
654
731
|
@abstractmethod
|
|
655
732
|
def run(self, user: SapioUser) -> list[SapioToolResult]:
|
|
656
733
|
"""
|
|
@@ -662,8 +739,8 @@ class ToolBase(ABC):
|
|
|
662
739
|
|
|
663
740
|
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
664
741
|
system.
|
|
665
|
-
:return: A
|
|
666
|
-
separate output from the tool. Field map results do not appear as tool output in the plan manager, instead
|
|
742
|
+
:return: A list of SapioToolResult objects containing the response data. Each result in the list corresponds to
|
|
743
|
+
a separate output from the tool. Field map results do not appear as tool output in the plan manager, instead
|
|
667
744
|
appearing as records related to the plan step during the run.
|
|
668
745
|
"""
|
|
669
746
|
pass
|