sapiopycommons 2025.4.24a494__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.
- sapiopycommons/ai/tool_service_base.py +70 -47
- {sapiopycommons-2025.4.24a494.dist-info → sapiopycommons-2025.4.24a495.dist-info}/METADATA +1 -1
- {sapiopycommons-2025.4.24a494.dist-info → sapiopycommons-2025.4.24a495.dist-info}/RECORD +5 -5
- {sapiopycommons-2025.4.24a494.dist-info → sapiopycommons-2025.4.24a495.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.4.24a494.dist-info → sapiopycommons-2025.4.24a495.dist-info}/licenses/LICENSE +0 -0
|
@@ -183,22 +183,15 @@ class TextResult(SapioToolResult):
|
|
|
183
183
|
|
|
184
184
|
class ToolServiceBase(ToolServiceServicer, ABC):
|
|
185
185
|
"""
|
|
186
|
-
A base class for implementing a tool service.
|
|
187
|
-
|
|
188
|
-
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.
|
|
189
188
|
"""
|
|
190
|
-
tools: list[ToolBase]
|
|
191
|
-
|
|
192
189
|
def GetToolDetails(self, request: ToolDetailsRequest, context: ServicerContext) -> ToolDetailsResponse:
|
|
193
190
|
try:
|
|
194
|
-
#
|
|
195
|
-
|
|
196
|
-
# Get the tool details from the subclass.
|
|
197
|
-
# TODO: Return something other than the ToolDetails proto objects? Something that's cleaner for the
|
|
198
|
-
# implementing class to work with?
|
|
199
|
-
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()
|
|
200
193
|
return ToolDetailsResponse(tool_framework_version=self.tool_version(), tool_details=details)
|
|
201
|
-
except Exception
|
|
194
|
+
except Exception:
|
|
202
195
|
# TODO: This response doesn't even allow logs. What should we do if an exception occurs in this case?
|
|
203
196
|
return ToolDetailsResponse()
|
|
204
197
|
|
|
@@ -206,22 +199,21 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
206
199
|
try:
|
|
207
200
|
# Convert the SapioConnectionInfo proto object to a SapioUser object.
|
|
208
201
|
user = self.create_user(request.sapio_user)
|
|
209
|
-
# Get the tool results from the
|
|
202
|
+
# Get the tool results from the registered tool matching the request and convert them to proto objects.
|
|
210
203
|
entry_data: list[StepEntryOutputData] = []
|
|
211
204
|
new_records: list[StepRecord] = []
|
|
212
|
-
|
|
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:
|
|
213
208
|
data: StepEntryOutputData | list[StepRecord] = result.to_proto()
|
|
214
209
|
if isinstance(data, StepEntryOutputData):
|
|
215
210
|
entry_data.append(data)
|
|
216
211
|
else:
|
|
217
212
|
new_records.extend(data)
|
|
218
213
|
# Return a ProcessStepResponse proto object containing the output data and new records to the caller.
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
except Exception as e:
|
|
223
|
-
# TODO: Do something other than dump the full stack trace into the logs?
|
|
224
|
-
# TODO: Eventually we'll return an is_success = false value.
|
|
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.
|
|
225
217
|
return ProcessStepResponse(log=[traceback.format_exc()])
|
|
226
218
|
|
|
227
219
|
@staticmethod
|
|
@@ -253,32 +245,40 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
253
245
|
|
|
254
246
|
def _get_tools(self) -> list[ToolBase]:
|
|
255
247
|
"""
|
|
256
|
-
Get the tools registered with this service.
|
|
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.
|
|
257
261
|
"""
|
|
258
|
-
|
|
259
|
-
if not
|
|
260
|
-
self.tools = self.register_tools()
|
|
261
|
-
# If the tools are still not registered, raise an exception.
|
|
262
|
-
if not self.tools:
|
|
262
|
+
tools: dict[str, ToolBase] = {x.name: x for x in self.register_tools()}
|
|
263
|
+
if not tools:
|
|
263
264
|
raise Exception("No tools registered with this service.")
|
|
264
|
-
|
|
265
|
+
if name not in tools:
|
|
266
|
+
raise Exception(f"Tool \"{name}\" not found in registered tools.")
|
|
267
|
+
return tools[name]
|
|
265
268
|
|
|
266
269
|
@abstractmethod
|
|
267
270
|
def register_tools(self) -> list[ToolBase]:
|
|
268
271
|
"""
|
|
269
|
-
Register the tools with this service.
|
|
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.
|
|
270
275
|
"""
|
|
271
276
|
pass
|
|
272
277
|
|
|
273
|
-
|
|
274
|
-
def get_details(self, user: SapioUser, request: ToolDetailsRequest, context: ServicerContext) -> list[ToolDetails]:
|
|
278
|
+
def get_details(self) -> list[ToolDetails]:
|
|
275
279
|
"""
|
|
276
280
|
Get the details of the tool.
|
|
277
281
|
|
|
278
|
-
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
279
|
-
system.
|
|
280
|
-
:param request: The request object containing the input data.
|
|
281
|
-
:param context: The gRPC context.
|
|
282
282
|
:return: A ToolDetailsResponse object containing the tool details.
|
|
283
283
|
"""
|
|
284
284
|
tool_details: list[ToolDetails] = []
|
|
@@ -286,8 +286,8 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
286
286
|
tool_details.append(tool.to_proto())
|
|
287
287
|
return tool_details
|
|
288
288
|
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) \
|
|
290
|
+
-> tuple[bool, list[SapioToolResult], list[str]]:
|
|
291
291
|
"""
|
|
292
292
|
Execute a tool from this service.
|
|
293
293
|
|
|
@@ -295,32 +295,48 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
295
295
|
system.
|
|
296
296
|
:param request: The request object containing the input data.
|
|
297
297
|
:param context: The gRPC context.
|
|
298
|
-
:return:
|
|
298
|
+
:return: Whether or not the tool succeeded, the results of the tool, and any logs generated by the tool.
|
|
299
299
|
"""
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
|
304
307
|
|
|
305
308
|
|
|
306
309
|
class ToolBase(ABC):
|
|
310
|
+
"""
|
|
311
|
+
A base class for implementing a tool.
|
|
312
|
+
"""
|
|
307
313
|
name: str
|
|
308
314
|
description: str
|
|
309
315
|
data_type_name: str | None
|
|
310
316
|
inputs: list[ToolInputDetails]
|
|
311
317
|
outputs: list[ToolOutputDetails]
|
|
312
318
|
configs: list[VeloxFieldDefProto]
|
|
319
|
+
logs: list[str]
|
|
313
320
|
|
|
314
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
|
+
"""
|
|
315
328
|
self.name = name
|
|
316
329
|
self.description = description
|
|
317
330
|
self.data_type_name = data_type_name
|
|
318
331
|
self.inputs = []
|
|
319
332
|
self.outputs = []
|
|
333
|
+
self.configs = []
|
|
334
|
+
self.logs = []
|
|
320
335
|
|
|
321
336
|
def add_input(self, details: ToolInputDetails) -> None:
|
|
322
337
|
"""
|
|
323
|
-
Add an input configuration to the tool.
|
|
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.
|
|
324
340
|
|
|
325
341
|
:param details: The input configuration details.
|
|
326
342
|
"""
|
|
@@ -328,7 +344,8 @@ class ToolBase(ABC):
|
|
|
328
344
|
|
|
329
345
|
def add_output(self, details: ToolOutputDetails) -> None:
|
|
330
346
|
"""
|
|
331
|
-
Add an output configuration to the tool.
|
|
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.
|
|
332
349
|
|
|
333
350
|
:param details: The output configuration details.
|
|
334
351
|
"""
|
|
@@ -336,7 +353,7 @@ class ToolBase(ABC):
|
|
|
336
353
|
|
|
337
354
|
def add_config_field(self, field: VeloxFieldDefProto) -> None:
|
|
338
355
|
"""
|
|
339
|
-
Add a configuration field to the tool.
|
|
356
|
+
Add a configuration field to the tool. This field will be used to configure the tool in the plan manager.
|
|
340
357
|
|
|
341
358
|
:param field: The configuration field details.
|
|
342
359
|
"""
|
|
@@ -344,9 +361,7 @@ class ToolBase(ABC):
|
|
|
344
361
|
|
|
345
362
|
def to_proto(self) -> ToolDetails:
|
|
346
363
|
"""
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
:return: The ToolDetails proto object.
|
|
364
|
+
:return: The ToolDetails proto object representing this tool.
|
|
350
365
|
"""
|
|
351
366
|
return ToolDetails(
|
|
352
367
|
name=self.name,
|
|
@@ -357,6 +372,14 @@ class ToolBase(ABC):
|
|
|
357
372
|
config_fields=self.configs
|
|
358
373
|
)
|
|
359
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)
|
|
382
|
+
|
|
360
383
|
@abstractmethod
|
|
361
384
|
def run(self, user: SapioUser, request: ProcessStepRequest, context: ServicerContext) -> list[SapioToolResult]:
|
|
362
385
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sapiopycommons
|
|
3
|
-
Version: 2025.4.
|
|
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=
|
|
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.
|
|
86
|
-
sapiopycommons-2025.4.
|
|
87
|
-
sapiopycommons-2025.4.
|
|
88
|
-
sapiopycommons-2025.4.
|
|
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,,
|
|
File without changes
|
{sapiopycommons-2025.4.24a494.dist-info → sapiopycommons-2025.4.24a495.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|