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.
- sapiopycommons/ai/tool_service_base.py +142 -19
- {sapiopycommons-2025.4.24a493.dist-info → sapiopycommons-2025.4.24a495.dist-info}/METADATA +1 -1
- {sapiopycommons-2025.4.24a493.dist-info → sapiopycommons-2025.4.24a495.dist-info}/RECORD +5 -5
- {sapiopycommons-2025.4.24a493.dist-info → sapiopycommons-2025.4.24a495.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.4.24a493.dist-info → sapiopycommons-2025.4.24a495.dist-info}/licenses/LICENSE +0 -0
|
@@ -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
|
-
#
|
|
191
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
217
|
-
# TODO:
|
|
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
|
|
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:
|
|
298
|
+
:return: Whether or not the tool succeeded, the results of the tool, and any logs generated by the tool.
|
|
257
299
|
"""
|
|
258
|
-
|
|
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.
|
|
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.24a493.dist-info → sapiopycommons-2025.4.24a495.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|