sapiopycommons 2025.7.22a651__py3-none-any.whl → 2025.7.30a660__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 sapiopycommons might be problematic. Click here for more details.

@@ -1,5 +1,3 @@
1
- from typing import Any
2
-
3
1
  from sapiopylib.rest.pojo.Sort import SortDirection
4
2
  from sapiopylib.rest.pojo.datatype.FieldDefinition import AbstractVeloxFieldDefinition, FieldType, \
5
3
  VeloxBooleanFieldDefinition, VeloxDateFieldDefinition, VeloxAccessionFieldDefinition, VeloxActionFieldDefinition, \
@@ -435,24 +433,23 @@ class ProtobufUtils:
435
433
  )
436
434
 
437
435
  @staticmethod
438
- def field_pbo_to_value(field: Any, value: FieldValuePbo) -> FieldValue:
436
+ def field_pbo_to_value(value: FieldValuePbo) -> FieldValue:
439
437
  """
440
- Convert a StepRecordFieldValue to its corresponding Python value based on the field type.
438
+ Convert a StepRecordFieldValue to its corresponding Python value.
441
439
 
442
- :param field: The VeloxFieldDefPbo or FieldTypePbo object for the given value.
443
440
  :param value: The StepRecordFieldValue object.
444
441
  :return: The corresponding Python value.
445
442
  """
446
- field_type = field.data_field_type if hasattr(field, "data_field_type") else field
447
- match field_type:
448
- case FieldTypePbo.BOOLEAN:
449
- return value.bool_value
450
- case FieldTypePbo.DOUBLE:
451
- return value.double_value
452
- case FieldTypePbo.ENUM | FieldTypePbo.INTEGER | FieldTypePbo.LONG | FieldTypePbo.SHORT:
453
- return value.int_value
454
- case _:
455
- return value.string_value
443
+ if value.HasField("string_value"):
444
+ return value.string_value
445
+ elif value.HasField("int_value"):
446
+ return value.int_value
447
+ elif value.HasField("double_value"):
448
+ return value.double_value
449
+ elif value.HasField("bool_value"):
450
+ return value.bool_value
451
+ else:
452
+ return None
456
453
 
457
454
  @staticmethod
458
455
  def field_def_pbo_to_default_value(field_def: VeloxFieldDefPbo) -> FieldValue:
@@ -1,11 +1,10 @@
1
1
  import base64
2
2
  import json
3
- from typing import Mapping, Any
3
+ from typing import Any
4
4
 
5
5
  import grpc
6
6
  from sapiopylib.rest.User import SapioUser
7
7
 
8
- from sapiopycommons.ai.api.fielddefinitions.proto.fields_pb2 import FieldValuePbo
9
8
  from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import DataTypePbo, StepBinaryContainerPbo, StepCsvRowPbo, \
10
9
  StepCsvHeaderRowPbo, StepCsvContainerPbo, StepJsonContainerPbo, StepImageContainerPbo, StepTextContainerPbo, \
11
10
  StepItemContainerPbo, StepInputBatchPbo
@@ -13,6 +12,8 @@ from sapiopycommons.ai.api.plan.tool.proto.tool_pb2 import ProcessStepResponsePb
13
12
  ToolDetailsRequestPbo, ToolDetailsResponsePbo, ProcessStepResponseStatusPbo
14
13
  from sapiopycommons.ai.api.plan.tool.proto.tool_pb2_grpc import ToolServiceStub
15
14
  from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import SapioConnectionInfoPbo, SapioUserSecretTypePbo
15
+ from sapiopycommons.ai.protobuf_utils import ProtobufUtils
16
+ from sapiopycommons.general.aliases import FieldValue
16
17
 
17
18
 
18
19
  # FR-47422: Created class.
@@ -32,7 +33,7 @@ class ToolOutput:
32
33
  image_output: list[bytes]
33
34
  text_output: list[str]
34
35
 
35
- new_records: list[Mapping[str, FieldValuePbo]]
36
+ new_records: list[dict[str, FieldValue]]
36
37
 
37
38
  logs: list[str]
38
39
 
@@ -51,28 +52,35 @@ class ToolOutput:
51
52
  ret_val += f"\tStatus: {self.status}\n"
52
53
  ret_val += f"\tMessage: {self.message}\n"
53
54
  ret_val += "-" * 25 + "\n"
55
+
54
56
  ret_val += f"Binary Output: {len(self.binary_output)} item(s)\n"
55
57
  for binary in self.binary_output:
56
58
  ret_val += f"\t{len(binary)} byte(s)\n"
57
59
  ret_val += f"\t{binary[:50]}...\n"
60
+
58
61
  ret_val += f"CSV Output: {len(self.csv_output)} item(s)\n"
59
62
  if self.csv_output:
60
63
  ret_val += f"\tHeaders: {', '.join(self.csv_output[0].keys())}\n"
61
64
  for i, csv_row in enumerate(self.csv_output):
62
65
  ret_val += f"\t{i}: {', '.join(f'{v}' for k, v in csv_row.items())}\n"
66
+
63
67
  ret_val += f"JSON Output: {len(self.json_output)} item(s)\n"
64
68
  if self.json_output:
65
- ret_val += f"\t{json.dumps(self.json_output, indent=2)}\n"
69
+ ret_val += f"{json.dumps(self.json_output, indent=2)}\n"
70
+
66
71
  ret_val += f"Image Output: {len(self.image_output)} item(s)\n"
67
72
  for image in self.image_output:
68
73
  ret_val += f"\t{len(image)} bytes\n"
69
74
  ret_val += f"\t{image[:50]}...\n"
75
+
70
76
  ret_val += f"Text Output: {len(self.text_output)} item(s)\n"
71
77
  for text in self.text_output:
72
- ret_val += f"\t{text}...\n"
78
+ ret_val += f"\t{text}\n"
79
+
73
80
  ret_val += f"New Records: {len(self.new_records)} item(s)\n"
74
81
  for record in self.new_records:
75
- ret_val += f"\t{json.dumps(record, indent=2)}\n"
82
+ ret_val += f"{json.dumps(record, indent=2)}\n"
83
+
76
84
  ret_val += f"Logs: {len(self.logs)} item(s)\n"
77
85
  for log in self.logs:
78
86
  ret_val += f"\t{log}\n"
@@ -237,16 +245,17 @@ class TestClient:
237
245
  sapio_user=self.connection,
238
246
  tool_name=tool_name,
239
247
  config_field_values=self._config_fields,
248
+ dry_run=is_dry_run,
249
+ verbose_logging=True,
240
250
  input=[
241
251
  StepInputBatchPbo(is_partial=False, item_container=item)
242
252
  for item in self._request_inputs
243
- ],
244
- dry_run=is_dry_run,
245
- verbose_logging=True
253
+ ]
246
254
  )
247
255
  )
248
256
 
249
257
  results = ToolOutput(tool_name)
258
+
250
259
  match response.status:
251
260
  case ProcessStepResponseStatusPbo.SUCCESS:
252
261
  results.status = "Success"
@@ -255,6 +264,7 @@ class TestClient:
255
264
  case _:
256
265
  results.status = "Unknown"
257
266
  results.message = response.status_message
267
+
258
268
  for item in response.output:
259
269
  container = item.item_container
260
270
 
@@ -269,7 +279,8 @@ class TestClient:
269
279
  results.text_output.extend(container.text_container.items)
270
280
 
271
281
  for record in response.new_records:
272
- results.new_records.append(record.fields)
282
+ field_map: dict[str, Any] = {x: ProtobufUtils.field_pbo_to_value(y) for x, y in record.fields.items()}
283
+ results.new_records.append(field_map)
273
284
 
274
285
  results.logs.extend(response.log)
275
286
 
@@ -289,14 +289,18 @@ class ToolServiceBase(ToolServiceServicer, ABC):
289
289
  generated by the tool.
290
290
  """
291
291
  # Locate the tool named in the request.
292
- tool: ToolBase | None = None
293
- for t in self.register_tools():
294
- if t.name() == request.tool_name:
295
- tool = t()
296
- break
297
- if not tool:
298
- return False, f"Tool \"{request.tool_name}\" not found in the registered tools for this service.", [], []
299
-
292
+ find_tool: str = request.tool_name
293
+ registered_tools: dict[str, type[ToolBase]] = {t.name(): t for t in self.register_tools()}
294
+ if find_tool not in registered_tools:
295
+ # If the tool is not found, list all of the registered tools for this service so that the LLM can correct
296
+ # the tool it is requesting.
297
+ all_tool_names: str = "\n".join(registered_tools.keys())
298
+ msg: str = (f"Tool \"{find_tool}\" not found in the registered tools for this service. The registered tools "
299
+ f"for this service are: \n{all_tool_names}")
300
+ return False, msg, [], []
301
+
302
+ # Instantiate the tool class.
303
+ tool: ToolBase = registered_tools[find_tool]()
300
304
  try:
301
305
  # Setup the tool with details from the request.
302
306
  tool.setup(user, request, context)
@@ -893,7 +897,11 @@ class ToolBase(ABC):
893
897
  if field_name not in raw_configs:
894
898
  config_fields[field_name] = ProtobufUtils.field_def_pbo_to_default_value(field_def)
895
899
  else:
896
- config_fields[field_name] = ProtobufUtils.field_pbo_to_value(field_def, raw_configs[field_name])
900
+ field_value: Any = ProtobufUtils.field_pbo_to_value(raw_configs[field_name])
901
+ if field_value is not None:
902
+ config_fields[field_name] = field_value
903
+ else:
904
+ config_fields[field_name] = ProtobufUtils.field_def_pbo_to_default_value(field_def)
897
905
  return config_fields
898
906
 
899
907
  @staticmethod
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.7.22a651
3
+ Version: 2025.7.30a660
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>
@@ -1,8 +1,8 @@
1
1
  sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- sapiopycommons/ai/protobuf_utils.py,sha256=8VYGhAdD731Ojy5PTy61PlTcvfEdydkIdX-4rOFPtxM,24911
4
- sapiopycommons/ai/test_client.py,sha256=ty-D_xemOiPbp-2hj57aam4-l74HvxKLpPf22i5pPqY,11917
5
- sapiopycommons/ai/tool_service_base.py,sha256=8SvmxWyu2nKeRjtq5qNAizL-lnfURr4Cbuw4K7hpWxs,41947
3
+ sapiopycommons/ai/protobuf_utils.py,sha256=yJkKolSfH2a-zk1k7juGh9-xQz6mmsoaJtM91meQIgk,24645
4
+ sapiopycommons/ai/test_client.py,sha256=TBlXeWVAx2OUtCZNry8dNjY9I3NOkySYj_QdQd7xx1A,12050
5
+ sapiopycommons/ai/tool_service_base.py,sha256=n_8UiLD6vuvkobJAHEGybvq5AY-itFCN1IjTiuyjmrU,42584
6
6
  sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.py,sha256=YcZjb_YM-XeLErM8hEC_S7vGMVGvcXAMGs2b-u5zvOE,2377
7
7
  sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2.pyi,sha256=FwtXmNAf7iYGEFm4kbqb04v77jNHbZg18ZmEDhle_bU,1444
8
8
  sapiopycommons/ai/api/fielddefinitions/proto/fields_pb2_grpc.py,sha256=wPImJPdCUZNVEVoUWzsba9kGIXjEKPdUkawP5SnVyiU,932
@@ -90,7 +90,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
90
90
  sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
91
91
  sapiopycommons/webhook/webhook_handlers.py,sha256=7o_wXOruhT9auNh8OfhJAh4WhhiPKij67FMBSpGPICc,39939
92
92
  sapiopycommons/webhook/webservice_handlers.py,sha256=cvW6Mk_110BzYqkbk63Kg7jWrltBCDALOlkJRu8h4VQ,14300
93
- sapiopycommons-2025.7.22a651.dist-info/METADATA,sha256=ij7R4yByMHiMKB3NljyGKKk34lsMoufPai-38qbEB3A,3143
94
- sapiopycommons-2025.7.22a651.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
95
- sapiopycommons-2025.7.22a651.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
96
- sapiopycommons-2025.7.22a651.dist-info/RECORD,,
93
+ sapiopycommons-2025.7.30a660.dist-info/METADATA,sha256=ARGB8aFkiawv1p5UphWDTJ-5xpFvVjZqoaGLe09mwgE,3143
94
+ sapiopycommons-2025.7.30a660.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
95
+ sapiopycommons-2025.7.30a660.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
96
+ sapiopycommons-2025.7.30a660.dist-info/RECORD,,