sapiopycommons 2025.4.24a493__py3-none-any.whl → 2025.4.24a495__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.

@@ -6,13 +6,15 @@ from abc import abstractmethod, ABC
6
6
  from typing import Any
7
7
 
8
8
  from grpc import ServicerContext
9
+
10
+ from sapiopycommons.ai.api.fielddefinitions.proto.velox_field_def_pb2 import VeloxFieldDefProto
9
11
  from sapiopycommons.general.aliases import FieldMap
10
12
  from sapiopylib.rest.User import SapioUser
11
13
 
12
14
  from sapiopycommons.ai.api.plan.tool.proto.entry_pb2 import StepEntryOutputData, StepEntryData, StepJsonData, DataType, \
13
15
  StepImageData, StepTextData, StepCsvData, StepBinaryData, StepCsvHeaderRow, StepCsvRow
14
16
  from sapiopycommons.ai.api.plan.tool.proto.tool_pb2 import ProcessStepRequest, ToolDetailsRequest, ToolDetailsResponse, \
15
- ProcessStepResponse, ToolDetails, StepRecord, StepRecordFieldValue
17
+ ProcessStepResponse, ToolDetails, StepRecord, StepRecordFieldValue, ToolInputDetails, ToolOutputDetails
16
18
  from sapiopycommons.ai.api.plan.tool.proto.tool_pb2_grpc import ToolServiceServicer
17
19
  from sapiopycommons.ai.api.session.proto.sapio_conn_info_pb2 import SapioConnectionInfo, SapioUserSecretType
18
20
 
@@ -181,20 +183,15 @@ class TextResult(SapioToolResult):
181
183
 
182
184
  class ToolServiceBase(ToolServiceServicer, ABC):
183
185
  """
184
- A base class for implementing a tool service.
185
-
186
- Subclasses must implement the get_details and run methods to provide specific functionality for the tool.
186
+ A base class for implementing a tool service. Subclasses should implement the register_tools method to register
187
+ their tools with the service.
187
188
  """
188
189
  def GetToolDetails(self, request: ToolDetailsRequest, context: ServicerContext) -> ToolDetailsResponse:
189
190
  try:
190
- # Convert the SapioConnectionInfo proto object to a SapioUser object.
191
- user = self.create_user(request.sapio_conn_info)
192
- # Get the tool details from the subclass.
193
- # TODO: Return something other than the ToolDetails proto objects? Something that's cleaner for the
194
- # implementing class to work with?
195
- details: list[ToolDetails] = self.get_details(user, request, context)
191
+ # Get the tool details from the registered tools.
192
+ details: list[ToolDetails] = self.get_details()
196
193
  return ToolDetailsResponse(tool_framework_version=self.tool_version(), tool_details=details)
197
- except Exception as e:
194
+ except Exception:
198
195
  # TODO: This response doesn't even allow logs. What should we do if an exception occurs in this case?
199
196
  return ToolDetailsResponse()
200
197
 
@@ -202,19 +199,21 @@ class ToolServiceBase(ToolServiceServicer, ABC):
202
199
  try:
203
200
  # Convert the SapioConnectionInfo proto object to a SapioUser object.
204
201
  user = self.create_user(request.sapio_user)
205
- # Get the tool results from the subclass and convert them to proto objects.
202
+ # Get the tool results from the registered tool matching the request and convert them to proto objects.
206
203
  entry_data: list[StepEntryOutputData] = []
207
204
  new_records: list[StepRecord] = []
208
- for result in self.run(user, request, context):
205
+ # TODO: Make use of the success value after the response object has a field for it.
206
+ success, results, logs = self.run(user, request, context)
207
+ for result in results:
209
208
  data: StepEntryOutputData | list[StepRecord] = result.to_proto()
210
209
  if isinstance(data, StepEntryOutputData):
211
210
  entry_data.append(data)
212
211
  else:
213
212
  new_records.extend(data)
214
213
  # Return a ProcessStepResponse proto object containing the output data and new records to the caller.
215
- return ProcessStepResponse(entry_data=entry_data, new_records=new_records)
216
- except Exception as e:
217
- # TODO: Do something other than dump the full stack trace into the logs?
214
+ return ProcessStepResponse(entry_data=entry_data, log=logs, new_records=new_records)
215
+ except Exception:
216
+ # TODO: Return a False success result after the response object has a field for it.
218
217
  return ProcessStepResponse(log=[traceback.format_exc()])
219
218
 
220
219
  @staticmethod
@@ -244,18 +243,142 @@ class ToolServiceBase(ToolServiceServicer, ABC):
244
243
  """
245
244
  return 1
246
245
 
246
+ def _get_tools(self) -> list[ToolBase]:
247
+ """
248
+ return: Get the tools registered with this service.
249
+ """
250
+ tools: list[ToolBase] = self.register_tools()
251
+ if not tools:
252
+ raise Exception("No tools registered with this service.")
253
+ return tools
254
+
255
+ def _get_tool(self, name: str) -> ToolBase:
256
+ """
257
+ Get a specific tool by its name.
258
+
259
+ :param name: The name of the tool to retrieve.
260
+ :return: The tool object corresponding to the given name.
261
+ """
262
+ tools: dict[str, ToolBase] = {x.name: x for x in self.register_tools()}
263
+ if not tools:
264
+ raise Exception("No tools registered with this service.")
265
+ if name not in tools:
266
+ raise Exception(f"Tool \"{name}\" not found in registered tools.")
267
+ return tools[name]
268
+
247
269
  @abstractmethod
248
- def get_details(self, user: SapioUser, request: ToolDetailsRequest, context: ServicerContext) -> list[ToolDetails]:
270
+ def register_tools(self) -> list[ToolBase]:
271
+ """
272
+ Register the tools with this service. Create and instantiate ToolBase subclasses to register them.
273
+
274
+ :return: A list of tools to register to this service.
275
+ """
276
+ pass
277
+
278
+ def get_details(self) -> list[ToolDetails]:
249
279
  """
250
280
  Get the details of the tool.
251
281
 
282
+ :return: A ToolDetailsResponse object containing the tool details.
283
+ """
284
+ tool_details: list[ToolDetails] = []
285
+ for tool in self._get_tools():
286
+ tool_details.append(tool.to_proto())
287
+ return tool_details
288
+
289
+ def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) \
290
+ -> tuple[bool, list[SapioToolResult], list[str]]:
291
+ """
292
+ Execute a tool from this service.
293
+
252
294
  :param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
253
295
  system.
254
296
  :param request: The request object containing the input data.
255
297
  :param context: The gRPC context.
256
- :return: A ToolDetailsResponse object containing the tool details.
298
+ :return: Whether or not the tool succeeded, the results of the tool, and any logs generated by the tool.
257
299
  """
258
- pass
300
+ tool = self._get_tool(request.tool_name)
301
+ try:
302
+ results = tool.run(user, request, context)
303
+ return True, results, tool.logs
304
+ except Exception:
305
+ tool.log_message(traceback.format_exc())
306
+ return False, [], tool.logs
307
+
308
+
309
+ class ToolBase(ABC):
310
+ """
311
+ A base class for implementing a tool.
312
+ """
313
+ name: str
314
+ description: str
315
+ data_type_name: str | None
316
+ inputs: list[ToolInputDetails]
317
+ outputs: list[ToolOutputDetails]
318
+ configs: list[VeloxFieldDefProto]
319
+ logs: list[str]
320
+
321
+ def __init__(self, name: str, description: str, data_type_name: str | None = None):
322
+ """
323
+ :param name: The name of the tool.
324
+ :param description: A description of the tool.
325
+ :param data_type_name: The name of the output data type of this tool, if applicable. When this tool returns
326
+ FieldMapResult objects in its run method, this name will be used to set the data type of the output data.
327
+ """
328
+ self.name = name
329
+ self.description = description
330
+ self.data_type_name = data_type_name
331
+ self.inputs = []
332
+ self.outputs = []
333
+ self.configs = []
334
+ self.logs = []
335
+
336
+ def add_input(self, details: ToolInputDetails) -> None:
337
+ """
338
+ Add an input configuration to the tool. This determines how many inputs this tool will accept in the plan
339
+ manager, as well as what those inputs are.
340
+
341
+ :param details: The input configuration details.
342
+ """
343
+ self.inputs.append(details)
344
+
345
+ def add_output(self, details: ToolOutputDetails) -> None:
346
+ """
347
+ Add an output configuration to the tool. This determines how many outputs this tool will return in the plan
348
+ manager, as well as what those outputs are.
349
+
350
+ :param details: The output configuration details.
351
+ """
352
+ self.outputs.append(details)
353
+
354
+ def add_config_field(self, field: VeloxFieldDefProto) -> None:
355
+ """
356
+ Add a configuration field to the tool. This field will be used to configure the tool in the plan manager.
357
+
358
+ :param field: The configuration field details.
359
+ """
360
+ self.configs.append(field)
361
+
362
+ def to_proto(self) -> ToolDetails:
363
+ """
364
+ :return: The ToolDetails proto object representing this tool.
365
+ """
366
+ return ToolDetails(
367
+ name=self.name,
368
+ description=self.description,
369
+ input_configs=self.inputs,
370
+ output_configs=self.outputs,
371
+ output_data_type_name=self.data_type_name,
372
+ config_fields=self.configs
373
+ )
374
+
375
+ def log_message(self, message: str) -> None:
376
+ """
377
+ Log a message for this tool. This message will be included in the logs returned to the caller.
378
+
379
+ :param message: The message to log.
380
+ """
381
+ self.logs.append(message)
259
382
 
260
383
  @abstractmethod
261
384
  def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) -> list[SapioToolResult]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sapiopycommons
3
- Version: 2025.4.24a493
3
+ Version: 2025.4.24a495
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,7 +1,7 @@
1
1
  sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  sapiopycommons/ai/tool_of_tools.py,sha256=zYmQ4rNX-qYQnc-vNDnYZjtv9JgmQAmVVuHfVOdBF3w,46984
4
- sapiopycommons/ai/tool_service_base.py,sha256=YJoHWTPD10TXXmZUKZIS6ryrV3Xqzt6TWNMNFaD8aQ4,10911
4
+ sapiopycommons/ai/tool_service_base.py,sha256=NFW5ulS__vDyASZ4VwsUDYRZNpN7QlKULGflvqcq6i4,15279
5
5
  sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.py,sha256=qPkyQsREtTLMliV9JB6tC5-NhmdWVWHJr70XNfcAfDI,20605
6
6
  sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2.pyi,sha256=gVXRsuscx9XavKsTcepzXWf0LDAAyQ_J5ZjFK6kPYuo,34028
7
7
  sapiopycommons/ai/api/fielddefinitions/proto/velox_field_def_pb2_grpc.py,sha256=4vD4jWanaJ4uclSkFmS7JIz_lwYXDWBE3DomuPjUyII,941
@@ -82,7 +82,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
82
82
  sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
83
83
  sapiopycommons/webhook/webhook_handlers.py,sha256=L0HetSm43NvA5KyW3xbLpGFh2DbAaeZJVtXIEl2fvV8,39689
84
84
  sapiopycommons/webhook/webservice_handlers.py,sha256=Y5dHx_UFWFuSqaoPL6Re-fsKYRuxvCWZ8bj6KSZ3jfM,14285
85
- sapiopycommons-2025.4.24a493.dist-info/METADATA,sha256=FMPyRCRl6p7rmhrM1EEKrCE_Iod4lx7Z2xsy5piQ_kE,3143
86
- sapiopycommons-2025.4.24a493.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
87
- sapiopycommons-2025.4.24a493.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
88
- sapiopycommons-2025.4.24a493.dist-info/RECORD,,
85
+ sapiopycommons-2025.4.24a495.dist-info/METADATA,sha256=Q0s3dSO7fgqX3UkSA5n0GxaaNjIADxUHhvToU8XBkmM,3143
86
+ sapiopycommons-2025.4.24a495.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
87
+ sapiopycommons-2025.4.24a495.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
88
+ sapiopycommons-2025.4.24a495.dist-info/RECORD,,