sapiopycommons 2025.10.2a773__py3-none-any.whl → 2025.10.9a776__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 → agent_service_base.py} +127 -127
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.py +41 -0
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.pyi +35 -0
- sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2_grpc.py +24 -0
- sapiopycommons/ai/protoapi/plan/script/script_pb2.py +17 -15
- sapiopycommons/ai/protoapi/plan/script/script_pb2.pyi +10 -4
- sapiopycommons/ai/protoapi/plan/tool/tool_pb2.py +29 -27
- sapiopycommons/ai/protoapi/plan/tool/tool_pb2.pyi +14 -6
- sapiopycommons/ai/request_validation.py +40 -21
- sapiopycommons/ai/server.py +11 -11
- sapiopycommons/ai/test_client.py +26 -23
- sapiopycommons/files/temp_files.py +1 -1
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/METADATA +1 -1
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/RECORD +16 -13
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.10.2a773.dist-info → sapiopycommons-2025.10.9a776.dist-info}/licenses/LICENSE +0 -0
|
@@ -38,22 +38,22 @@ from sapiopycommons.general.aliases import FieldMap, FieldValue
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
# FR-47422: Created classes.
|
|
41
|
-
class
|
|
41
|
+
class SapioAgentResult(ABC):
|
|
42
42
|
"""
|
|
43
|
-
A class representing a result from a Sapio
|
|
43
|
+
A class representing a result from a Sapio agent. Instantiate one of the subclasses to create a result object.
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
46
|
@abstractmethod
|
|
47
47
|
def to_proto(self) -> StepOutputBatchPbo | list[FieldValueMapPbo]:
|
|
48
48
|
"""
|
|
49
|
-
Convert this
|
|
49
|
+
Convert this SapioAgentResult object to a StepOutputBatchPbo or list of FieldValueMapPbo proto objects.
|
|
50
50
|
"""
|
|
51
51
|
pass
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
class BinaryResult(
|
|
54
|
+
class BinaryResult(SapioAgentResult):
|
|
55
55
|
"""
|
|
56
|
-
A class representing binary results from a Sapio
|
|
56
|
+
A class representing binary results from a Sapio agent.
|
|
57
57
|
"""
|
|
58
58
|
binary_data: list[bytes]
|
|
59
59
|
content_type: str
|
|
@@ -66,7 +66,7 @@ class BinaryResult(SapioToolResult):
|
|
|
66
66
|
:param binary_data: The binary data as a list of bytes.
|
|
67
67
|
:param content_type: The content type of the data.
|
|
68
68
|
:param file_extensions: A list of file extensions that this binary data can be saved as.
|
|
69
|
-
:param name: An optional identifying name for this result that will be accessible to the next
|
|
69
|
+
:param name: An optional identifying name for this result that will be accessible to the next agent.
|
|
70
70
|
"""
|
|
71
71
|
self.binary_data = binary_data
|
|
72
72
|
self.content_type = content_type
|
|
@@ -83,9 +83,9 @@ class BinaryResult(SapioToolResult):
|
|
|
83
83
|
)
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
class CsvResult(
|
|
86
|
+
class CsvResult(SapioAgentResult):
|
|
87
87
|
"""
|
|
88
|
-
A class representing CSV results from a Sapio
|
|
88
|
+
A class representing CSV results from a Sapio agent.
|
|
89
89
|
"""
|
|
90
90
|
csv_data: list[dict[str, Any]]
|
|
91
91
|
content_type: str
|
|
@@ -98,7 +98,7 @@ class CsvResult(SapioToolResult):
|
|
|
98
98
|
:param csv_data: The list of CSV data results, provided as a list of dictionaries of column name to value.
|
|
99
99
|
:param content_type: The content type of the data.
|
|
100
100
|
:param file_extensions: A list of file extensions that this binary data can be saved as.
|
|
101
|
-
:param name: An optional identifying name for this result that will be accessible to the next
|
|
101
|
+
:param name: An optional identifying name for this result that will be accessible to the next agent.
|
|
102
102
|
"""
|
|
103
103
|
self.csv_data = csv_data
|
|
104
104
|
self.content_type = content_type
|
|
@@ -118,16 +118,16 @@ class CsvResult(SapioToolResult):
|
|
|
118
118
|
)
|
|
119
119
|
|
|
120
120
|
|
|
121
|
-
class FieldMapResult(
|
|
121
|
+
class FieldMapResult(SapioAgentResult):
|
|
122
122
|
"""
|
|
123
|
-
A class representing field map results from a Sapio
|
|
123
|
+
A class representing field map results from a Sapio agent.
|
|
124
124
|
"""
|
|
125
125
|
field_maps: list[FieldMap]
|
|
126
126
|
|
|
127
127
|
def __init__(self, field_maps: list[FieldMap]):
|
|
128
128
|
"""
|
|
129
129
|
:param field_maps: A list of field maps, where each map is a dictionary of field names to values. Each entry
|
|
130
|
-
will create a new data record in the system, so long as the
|
|
130
|
+
will create a new data record in the system, so long as the agent definition specifies an output data type
|
|
131
131
|
name.
|
|
132
132
|
"""
|
|
133
133
|
self.field_maps = field_maps
|
|
@@ -151,9 +151,9 @@ class FieldMapResult(SapioToolResult):
|
|
|
151
151
|
return new_records
|
|
152
152
|
|
|
153
153
|
|
|
154
|
-
class JsonResult(
|
|
154
|
+
class JsonResult(SapioAgentResult):
|
|
155
155
|
"""
|
|
156
|
-
A class representing JSON results from a Sapio
|
|
156
|
+
A class representing JSON results from a Sapio agent.
|
|
157
157
|
"""
|
|
158
158
|
json_data: list[dict[str, Any]]
|
|
159
159
|
content_type: str
|
|
@@ -167,7 +167,7 @@ class JsonResult(SapioToolResult):
|
|
|
167
167
|
These entries must be able to be serialized to JSON using json.dumps().
|
|
168
168
|
:param content_type: The content type of the data.
|
|
169
169
|
:param file_extensions: A list of file extensions that this binary data can be saved as.
|
|
170
|
-
:param name: An optional identifying name for this result that will be accessible to the next
|
|
170
|
+
:param name: An optional identifying name for this result that will be accessible to the next agent.
|
|
171
171
|
"""
|
|
172
172
|
# Verify that the given json_data is actually a list of dictionaries.
|
|
173
173
|
if not isinstance(json_data, list) or not all(isinstance(x, dict) for x in json_data):
|
|
@@ -187,9 +187,9 @@ class JsonResult(SapioToolResult):
|
|
|
187
187
|
)
|
|
188
188
|
|
|
189
189
|
|
|
190
|
-
class TextResult(
|
|
190
|
+
class TextResult(SapioAgentResult):
|
|
191
191
|
"""
|
|
192
|
-
A class representing text results from a Sapio
|
|
192
|
+
A class representing text results from a Sapio agent.
|
|
193
193
|
"""
|
|
194
194
|
text_data: list[str]
|
|
195
195
|
content_type: str
|
|
@@ -202,7 +202,7 @@ class TextResult(SapioToolResult):
|
|
|
202
202
|
:param text_data: The text data as a list of strings.
|
|
203
203
|
:param content_type: The content type of the data.
|
|
204
204
|
:param file_extensions: A list of file extensions that this binary data can be saved as.
|
|
205
|
-
:param name: An optional identifying name for this result that will be accessible to the next
|
|
205
|
+
:param name: An optional identifying name for this result that will be accessible to the next agent.
|
|
206
206
|
"""
|
|
207
207
|
self.text_data = text_data
|
|
208
208
|
self.content_type = content_type
|
|
@@ -219,24 +219,24 @@ class TextResult(SapioToolResult):
|
|
|
219
219
|
)
|
|
220
220
|
|
|
221
221
|
|
|
222
|
-
class
|
|
222
|
+
class AgentServiceBase(ToolServiceServicer, ABC):
|
|
223
223
|
"""
|
|
224
|
-
A base class for implementing
|
|
225
|
-
their
|
|
224
|
+
A base class for implementing an agent service. Subclasses should implement the register_agents method to register
|
|
225
|
+
their agents with the service.
|
|
226
226
|
"""
|
|
227
227
|
debug_mode: bool = False
|
|
228
228
|
|
|
229
229
|
def GetToolDetails(self, request: ToolDetailsRequestPbo, context: ServicerContext) -> ToolDetailsResponsePbo:
|
|
230
230
|
try:
|
|
231
|
-
# Get the
|
|
231
|
+
# Get the agent details from the registered agents.
|
|
232
232
|
details: list[ToolDetailsPbo] = []
|
|
233
|
-
for
|
|
234
|
-
details.append(
|
|
233
|
+
for agent in self.register_agents():
|
|
234
|
+
details.append(agent().to_pbo())
|
|
235
235
|
if not details:
|
|
236
|
-
raise Exception("No
|
|
237
|
-
return ToolDetailsResponsePbo(tool_framework_version=self.
|
|
236
|
+
raise Exception("No agents registered with this service.")
|
|
237
|
+
return ToolDetailsResponsePbo(tool_framework_version=self.server_version(), tool_details=details)
|
|
238
238
|
except Exception as e:
|
|
239
|
-
# Woe to you if you somehow cause an exception to be raised when just initializing your
|
|
239
|
+
# Woe to you if you somehow cause an exception to be raised when just initializing your agents.
|
|
240
240
|
# There's no way to log this.
|
|
241
241
|
print(f"CRITICAL ERROR: {e}")
|
|
242
242
|
print(traceback.format_exc())
|
|
@@ -246,7 +246,7 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
246
246
|
try:
|
|
247
247
|
# Convert the SapioConnectionInfo proto object to a SapioUser object.
|
|
248
248
|
user = self._create_user(request.sapio_user)
|
|
249
|
-
# Get the
|
|
249
|
+
# Get the agent results from the registered agent matching the request.
|
|
250
250
|
success, msg, results, logs = self.run(user, request, context)
|
|
251
251
|
# Convert the results to protobuf objects.
|
|
252
252
|
output_data: list[StepOutputBatchPbo] = []
|
|
@@ -262,7 +262,7 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
262
262
|
return ProcessStepResponsePbo(status=status, status_message=msg, output=output_data, log=logs,
|
|
263
263
|
new_records=new_records)
|
|
264
264
|
except Exception as e:
|
|
265
|
-
# This try/except should never be needed, as the
|
|
265
|
+
# This try/except should never be needed, as the agent should handle its own exceptions, but better safe
|
|
266
266
|
# than sorry.
|
|
267
267
|
print(f"CRITICAL ERROR: {e}")
|
|
268
268
|
print(traceback.format_exc())
|
|
@@ -294,88 +294,88 @@ class ToolServiceBase(ToolServiceServicer, ABC):
|
|
|
294
294
|
return user
|
|
295
295
|
|
|
296
296
|
@staticmethod
|
|
297
|
-
def
|
|
297
|
+
def server_version() -> int:
|
|
298
298
|
"""
|
|
299
|
-
:return: The version of this set of
|
|
299
|
+
:return: The version of this set of .
|
|
300
300
|
"""
|
|
301
301
|
return 1
|
|
302
302
|
|
|
303
303
|
@abstractmethod
|
|
304
|
-
def
|
|
304
|
+
def register_agents(self) -> list[type[AgentBase]]:
|
|
305
305
|
"""
|
|
306
|
-
Register
|
|
306
|
+
Register agent types with this service. Provided agents should implement the AgentBase class.
|
|
307
307
|
|
|
308
|
-
:return: A list of
|
|
308
|
+
:return: A list of agents to register to this service.
|
|
309
309
|
"""
|
|
310
310
|
pass
|
|
311
311
|
|
|
312
312
|
def run(self, user: SapioUser, request: ProcessStepRequestPbo, context: ServicerContext) \
|
|
313
|
-
-> tuple[bool, str, list[
|
|
313
|
+
-> tuple[bool, str, list[SapioAgentResult], list[str]]:
|
|
314
314
|
"""
|
|
315
|
-
Execute
|
|
315
|
+
Execute an agent from this service.
|
|
316
316
|
|
|
317
317
|
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
318
318
|
system.
|
|
319
319
|
:param request: The request object containing the input data.
|
|
320
320
|
:param context: The gRPC context.
|
|
321
|
-
:return: Whether or not the
|
|
322
|
-
generated by the
|
|
323
|
-
"""
|
|
324
|
-
# Locate the
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if
|
|
328
|
-
# If the
|
|
329
|
-
# the
|
|
330
|
-
|
|
331
|
-
msg: str = (f"
|
|
332
|
-
f"
|
|
321
|
+
:return: Whether or not the agent succeeded, the status message, the results of the agent, and any logs
|
|
322
|
+
generated by the agent.
|
|
323
|
+
"""
|
|
324
|
+
# Locate the agent named in the request.
|
|
325
|
+
find_agent: str = request.tool_name
|
|
326
|
+
registered_agents: dict[str, type[AgentBase]] = {t.name(): t for t in self.register_agents()}
|
|
327
|
+
if find_agent not in registered_agents:
|
|
328
|
+
# If the agent is not found, list all of the registered agents for this service so that the LLM can correct
|
|
329
|
+
# the agent it is requesting.
|
|
330
|
+
all_agent_names: str = "\n".join(registered_agents.keys())
|
|
331
|
+
msg: str = (f"Agent \"{find_agent}\" not found in the registered agents for this service. The registered "
|
|
332
|
+
f"agents for this service are: \n{all_agent_names}")
|
|
333
333
|
return False, msg, [], []
|
|
334
334
|
|
|
335
|
-
# Instantiate the
|
|
336
|
-
|
|
335
|
+
# Instantiate the agent class.
|
|
336
|
+
agent: AgentBase = registered_agents[find_agent]()
|
|
337
337
|
try:
|
|
338
|
-
# Setup the
|
|
339
|
-
|
|
340
|
-
# Validate that the provided inputs match the
|
|
338
|
+
# Setup the agent with details from the request.
|
|
339
|
+
agent.setup(user, request, context, self.debug_mode)
|
|
340
|
+
# Validate that the provided inputs match the agent's expected inputs.
|
|
341
341
|
msg: str = ""
|
|
342
|
-
if len(request.input) != len(
|
|
343
|
-
msg = f"Expected {len(
|
|
342
|
+
if len(request.input) != len(agent.input_configs):
|
|
343
|
+
msg = f"Expected {len(agent.input_configs)} inputs for this agent, but got {len(request.input)} instead."
|
|
344
344
|
else:
|
|
345
|
-
errors: list[str] =
|
|
345
|
+
errors: list[str] = agent.validate_input()
|
|
346
346
|
if errors:
|
|
347
347
|
msg = "\n".join(errors)
|
|
348
348
|
# If there is no error message, then the inputs are valid.
|
|
349
349
|
success: bool = not bool(msg)
|
|
350
350
|
# If this is a dry run, then provide the fixed dry run output.
|
|
351
|
-
# Otherwise, if the inputs were successfully validated, then the
|
|
352
|
-
results: list[
|
|
351
|
+
# Otherwise, if the inputs were successfully validated, then the agent is executed normally.
|
|
352
|
+
results: list[SapioAgentResult] = []
|
|
353
353
|
if request.dry_run:
|
|
354
|
-
results =
|
|
354
|
+
results = agent.dry_run_output()
|
|
355
355
|
elif success:
|
|
356
|
-
results =
|
|
357
|
-
# Update the status message to reflect the successful execution of the
|
|
358
|
-
msg = f"{
|
|
359
|
-
return success, msg, results,
|
|
356
|
+
results = agent.run(user)
|
|
357
|
+
# Update the status message to reflect the successful execution of the agent.
|
|
358
|
+
msg = f"{agent.name()} successfully completed."
|
|
359
|
+
return success, msg, results, agent.logs
|
|
360
360
|
except Exception as e:
|
|
361
|
-
|
|
362
|
-
return False, str(e), [],
|
|
361
|
+
agent.log_exception("Exception occurred during agent execution.", e)
|
|
362
|
+
return False, str(e), [], agent.logs
|
|
363
363
|
finally:
|
|
364
|
-
# Clean up any temporary files created by the
|
|
364
|
+
# Clean up any temporary files created by the agent. If in debug mode, then log the files instead
|
|
365
365
|
# so that they can be manually inspected.
|
|
366
366
|
if self.debug_mode:
|
|
367
|
-
print("Temporary files/directories created during
|
|
368
|
-
for directory in
|
|
367
|
+
print("Temporary files/directories created during agent execution:")
|
|
368
|
+
for directory in agent.temp_data.directories:
|
|
369
369
|
print(f"\tDirectory: {directory}")
|
|
370
|
-
for file in
|
|
370
|
+
for file in agent.temp_data.files:
|
|
371
371
|
print(f"\tFile: {file}")
|
|
372
372
|
else:
|
|
373
|
-
|
|
373
|
+
agent.temp_data.cleanup()
|
|
374
374
|
|
|
375
375
|
|
|
376
|
-
class
|
|
376
|
+
class AgentBase(ABC):
|
|
377
377
|
"""
|
|
378
|
-
A base class for implementing
|
|
378
|
+
A base class for implementing an agent.
|
|
379
379
|
"""
|
|
380
380
|
input_configs: list[ToolInputDetailsPbo]
|
|
381
381
|
input_container_types: list[ContainerType]
|
|
@@ -398,9 +398,9 @@ class ToolBase(ABC):
|
|
|
398
398
|
@abstractmethod
|
|
399
399
|
def identifier(cls):
|
|
400
400
|
"""
|
|
401
|
-
:return: The unique identifier of the
|
|
402
|
-
updated if
|
|
403
|
-
otherwise a duplicate
|
|
401
|
+
:return: The unique identifier of the agent. This is used by the system to determine which agent should be
|
|
402
|
+
updated if an agent is re-imported. This should not be changed after the first time that an agent is
|
|
403
|
+
imported, otherwise a duplicate agent will be created.
|
|
404
404
|
"""
|
|
405
405
|
pass
|
|
406
406
|
|
|
@@ -408,7 +408,7 @@ class ToolBase(ABC):
|
|
|
408
408
|
@abstractmethod
|
|
409
409
|
def name() -> str:
|
|
410
410
|
"""
|
|
411
|
-
:return: The display name of the
|
|
411
|
+
:return: The display name of the agent. This should be unique across all agents in the service.
|
|
412
412
|
"""
|
|
413
413
|
pass
|
|
414
414
|
|
|
@@ -416,7 +416,7 @@ class ToolBase(ABC):
|
|
|
416
416
|
@abstractmethod
|
|
417
417
|
def category() -> str:
|
|
418
418
|
"""
|
|
419
|
-
:return: The category of the
|
|
419
|
+
:return: The category of the agent. This is used to group similar agents together in the plan manager.
|
|
420
420
|
"""
|
|
421
421
|
pass
|
|
422
422
|
|
|
@@ -424,7 +424,7 @@ class ToolBase(ABC):
|
|
|
424
424
|
@abstractmethod
|
|
425
425
|
def description() -> str:
|
|
426
426
|
"""
|
|
427
|
-
:return: A description of the
|
|
427
|
+
:return: A description of the agent.
|
|
428
428
|
"""
|
|
429
429
|
pass
|
|
430
430
|
|
|
@@ -432,14 +432,14 @@ class ToolBase(ABC):
|
|
|
432
432
|
@abstractmethod
|
|
433
433
|
def citations() -> dict[str, str]:
|
|
434
434
|
"""
|
|
435
|
-
:return: Any citations or references for this
|
|
435
|
+
:return: Any citations or references for this agent, as a dictionary of citation name to URL.
|
|
436
436
|
"""
|
|
437
437
|
pass
|
|
438
438
|
|
|
439
439
|
@staticmethod
|
|
440
440
|
def data_type_name() -> str | None:
|
|
441
441
|
"""
|
|
442
|
-
:return: The name of the output data type of this
|
|
442
|
+
:return: The name of the output data type of this agent, if applicable. When this agent returns
|
|
443
443
|
FieldMapResult objects in its run method, this name will be used to set the data type of the output data.
|
|
444
444
|
"""
|
|
445
445
|
return None
|
|
@@ -447,8 +447,8 @@ class ToolBase(ABC):
|
|
|
447
447
|
@staticmethod
|
|
448
448
|
def license_flag() -> str | None:
|
|
449
449
|
"""
|
|
450
|
-
:return: The license flag for this
|
|
451
|
-
If None, the
|
|
450
|
+
:return: The license flag for this agent. The system must have this license in order to use this agent.
|
|
451
|
+
If None, the agent is not license locked.
|
|
452
452
|
"""
|
|
453
453
|
return None
|
|
454
454
|
|
|
@@ -460,19 +460,19 @@ class ToolBase(ABC):
|
|
|
460
460
|
self.config_fields = []
|
|
461
461
|
self.temp_data = TempFileHandler()
|
|
462
462
|
self.logs = []
|
|
463
|
-
self.logger = logging.getLogger(f"
|
|
463
|
+
self.logger = logging.getLogger(f"AgentBase.{self.name()}")
|
|
464
464
|
ensure_logger_initialized(self.logger)
|
|
465
465
|
|
|
466
466
|
def setup(self, user: SapioUser, request: ProcessStepRequestPbo, context: ServicerContext, debug_mode: bool) -> None:
|
|
467
467
|
"""
|
|
468
|
-
Setup the
|
|
468
|
+
Setup the agent with the user, request, and context. This method can be overridden by subclasses to perform
|
|
469
469
|
additional setup.
|
|
470
470
|
|
|
471
471
|
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
472
472
|
system.
|
|
473
473
|
:param request: The request object containing the input data.
|
|
474
474
|
:param context: The gRPC context.
|
|
475
|
-
:param debug_mode: If true, the
|
|
475
|
+
:param debug_mode: If true, the agent should run in debug mode, providing additional logging and not cleaning
|
|
476
476
|
up temporary files.
|
|
477
477
|
"""
|
|
478
478
|
self.user = user
|
|
@@ -486,7 +486,7 @@ class ToolBase(ABC):
|
|
|
486
486
|
input_count: tuple[int, int] | None = None, is_paged: bool = False,
|
|
487
487
|
page_size: tuple[int, int] | None = None, max_request_bytes: int | None = None) -> None:
|
|
488
488
|
"""
|
|
489
|
-
Add an input configuration to the
|
|
489
|
+
Add an input configuration to the agent. This determines how many inputs this agent will accept in the plan
|
|
490
490
|
manager, as well as what those inputs are. The IO number of the input will be set to the current number of
|
|
491
491
|
inputs. That is, the first time this is called, the IO number will be 0, the second time it is called, the IO
|
|
492
492
|
number will be 1, and so on.
|
|
@@ -499,11 +499,11 @@ class ToolBase(ABC):
|
|
|
499
499
|
JSON output may look. This does not need to be an entirely valid example, and should often be truncated for
|
|
500
500
|
brevity. This must be provided for any container type other than BINARY.
|
|
501
501
|
:param validation: An optional validation string for the input.
|
|
502
|
-
:param input_count: A tuple of the minimum and maximum number of inputs allowed for this
|
|
502
|
+
:param input_count: A tuple of the minimum and maximum number of inputs allowed for this agent.
|
|
503
503
|
:param is_paged: If true, this input will be paged. If false, this input will not be paged.
|
|
504
|
-
:param page_size: A tuple of the minimum and maximum page size for this
|
|
504
|
+
:param page_size: A tuple of the minimum and maximum page size for this agent. The input must be paged in order
|
|
505
505
|
for this to have an effect.
|
|
506
|
-
:param max_request_bytes: The maximum request size in bytes for this
|
|
506
|
+
:param max_request_bytes: The maximum request size in bytes for this agent.
|
|
507
507
|
"""
|
|
508
508
|
if container_type != ContainerType.BINARY and structure_example is None:
|
|
509
509
|
raise ValueError("structure_example must be provided for inputs with a container_type other than BINARY.")
|
|
@@ -537,7 +537,7 @@ class ToolBase(ABC):
|
|
|
537
537
|
def add_output(self, container_type: ContainerType, content_type: str, display_name: str, description: str,
|
|
538
538
|
testing_example: str | bytes, structure_example: str | bytes | None = None) -> None:
|
|
539
539
|
"""
|
|
540
|
-
Add an output configuration to the
|
|
540
|
+
Add an output configuration to the agent. This determines how many inputs this agent will accept in the plan
|
|
541
541
|
manager, as well as what those inputs are. The IO number of the output will be set to the current number of
|
|
542
542
|
outputs. That is, the first time this is called, the IO number will be 0, the second time it is called, the IO
|
|
543
543
|
number will be 1, and so on.
|
|
@@ -546,8 +546,8 @@ class ToolBase(ABC):
|
|
|
546
546
|
:param content_type: The content type of the output.
|
|
547
547
|
:param display_name: The display name of the output.
|
|
548
548
|
:param description: The description of the output.
|
|
549
|
-
:param testing_example: An example of the input to be used when testing this
|
|
550
|
-
an entirely valid example of what an output of this
|
|
549
|
+
:param testing_example: An example of the input to be used when testing this agent in the system. This must be
|
|
550
|
+
an entirely valid example of what an output of this agent could look like so that it can be properly used
|
|
551
551
|
to run tests with. The provided example may be a string, such as for representing JSON or CSV outputs,
|
|
552
552
|
or bytes, such as for representing binary outputs like images or files.
|
|
553
553
|
:param structure_example: An optional example of the structure of the input, such as how the structure of a
|
|
@@ -583,7 +583,7 @@ class ToolBase(ABC):
|
|
|
583
583
|
|
|
584
584
|
def add_config_field(self, field: VeloxFieldDefPbo) -> None:
|
|
585
585
|
"""
|
|
586
|
-
Add a configuration field to the
|
|
586
|
+
Add a configuration field to the agent. This field will be used to configure the agent in the plan manager.
|
|
587
587
|
|
|
588
588
|
:param field: The configuration field details.
|
|
589
589
|
"""
|
|
@@ -591,7 +591,7 @@ class ToolBase(ABC):
|
|
|
591
591
|
|
|
592
592
|
def add_config_field_def(self, field: AbstractVeloxFieldDefinition) -> None:
|
|
593
593
|
"""
|
|
594
|
-
Add a configuration field to the
|
|
594
|
+
Add a configuration field to the agent. This field will be used to configure the agent in the plan manager.
|
|
595
595
|
|
|
596
596
|
:param field: The configuration field details.
|
|
597
597
|
"""
|
|
@@ -600,7 +600,7 @@ class ToolBase(ABC):
|
|
|
600
600
|
def add_boolean_config_field(self, field_name: str, display_name: str, description: str,
|
|
601
601
|
default_value: bool | None = None, optional: bool = False) -> None:
|
|
602
602
|
"""
|
|
603
|
-
Add a boolean configuration field to the
|
|
603
|
+
Add a boolean configuration field to the agent. This field will be used to configure the agent in the plan
|
|
604
604
|
manager.
|
|
605
605
|
|
|
606
606
|
:param field_name: The name of the field.
|
|
@@ -625,7 +625,7 @@ class ToolBase(ABC):
|
|
|
625
625
|
default_value: float | None = None, min_value: float = -10.**120,
|
|
626
626
|
max_value: float = 10.**120, precision: int = 2, optional: bool = False) -> None:
|
|
627
627
|
"""
|
|
628
|
-
Add a double configuration field to the
|
|
628
|
+
Add a double configuration field to the agent. This field will be used to configure the agent in the plan
|
|
629
629
|
manager.
|
|
630
630
|
|
|
631
631
|
:param field_name: The name of the field.
|
|
@@ -656,7 +656,7 @@ class ToolBase(ABC):
|
|
|
656
656
|
default_value: int | None = None, min_value: int = -2**31, max_value: int = 2**31-1,
|
|
657
657
|
optional: bool = False) -> None:
|
|
658
658
|
"""
|
|
659
|
-
Add an integer configuration field to the
|
|
659
|
+
Add an integer configuration field to the agent. This field will be used to configure the agent in the plan
|
|
660
660
|
manager.
|
|
661
661
|
|
|
662
662
|
:param field_name: The name of the field.
|
|
@@ -685,7 +685,7 @@ class ToolBase(ABC):
|
|
|
685
685
|
default_value: str | None = None, max_length: int = 1000, optional: bool = False,
|
|
686
686
|
validation_regex: str | None = None, error_msg: str | None = None) -> None:
|
|
687
687
|
"""
|
|
688
|
-
Add a string configuration field to the
|
|
688
|
+
Add a string configuration field to the agent. This field will be used to configure the agent in the plan
|
|
689
689
|
manager.
|
|
690
690
|
|
|
691
691
|
:param field_name: The name of the field.
|
|
@@ -716,7 +716,7 @@ class ToolBase(ABC):
|
|
|
716
716
|
direct_edit: bool = False, optional: bool = False,
|
|
717
717
|
validation_regex: str | None = None, error_msg: str | None = None) -> None:
|
|
718
718
|
"""
|
|
719
|
-
Add a list configuration field to the
|
|
719
|
+
Add a list configuration field to the agent. This field will be used to configure the agent in the plan
|
|
720
720
|
manager.
|
|
721
721
|
|
|
722
722
|
:param field_name: The name of the field.
|
|
@@ -750,7 +750,7 @@ class ToolBase(ABC):
|
|
|
750
750
|
direct_edit: bool = False, optional: bool = False,
|
|
751
751
|
validation_regex: str | None = None, error_msg: str | None = None) -> None:
|
|
752
752
|
"""
|
|
753
|
-
Add a multi-select list configuration field to the
|
|
753
|
+
Add a multi-select list configuration field to the agent. This field will be used to configure the agent in the
|
|
754
754
|
plan manager.
|
|
755
755
|
|
|
756
756
|
:param field_name: The name of the field.
|
|
@@ -782,7 +782,7 @@ class ToolBase(ABC):
|
|
|
782
782
|
|
|
783
783
|
def to_pbo(self) -> ToolDetailsPbo:
|
|
784
784
|
"""
|
|
785
|
-
:return: The ToolDetailsPbo proto object representing this
|
|
785
|
+
:return: The ToolDetailsPbo proto object representing this agent.
|
|
786
786
|
"""
|
|
787
787
|
return ToolDetailsPbo(
|
|
788
788
|
import_id=self.identifier(),
|
|
@@ -800,7 +800,7 @@ class ToolBase(ABC):
|
|
|
800
800
|
@abstractmethod
|
|
801
801
|
def validate_input(self) -> list[str] | None:
|
|
802
802
|
"""
|
|
803
|
-
Validate the request given to this
|
|
803
|
+
Validate the request given to this agent. If the request is validly formatted, this method should return None.
|
|
804
804
|
If the request is not valid, this method should return an error message indicating what is wrong with the
|
|
805
805
|
request.
|
|
806
806
|
|
|
@@ -816,18 +816,18 @@ class ToolBase(ABC):
|
|
|
816
816
|
"""
|
|
817
817
|
pass
|
|
818
818
|
|
|
819
|
-
def dry_run_output(self) -> list[
|
|
819
|
+
def dry_run_output(self) -> list[SapioAgentResult]:
|
|
820
820
|
"""
|
|
821
|
-
Provide fixed results for a dry run of this
|
|
822
|
-
request. It should only return example outputs that can be used to test the next
|
|
821
|
+
Provide fixed results for a dry run of this agent. This method should not perform any actual processing of the
|
|
822
|
+
request. It should only return example outputs that can be used to test the next agent in the plan.
|
|
823
823
|
|
|
824
824
|
The default implementation of this method looks at the testing_example field of each output configuration
|
|
825
|
-
and returns a
|
|
825
|
+
and returns a SapioAgentResult object based on the content type of the output.
|
|
826
826
|
|
|
827
|
-
:return: A list of
|
|
828
|
-
corresponds to a separate output from the
|
|
827
|
+
:return: A list of SapioAgentResult objects containing example outputs for this agent. Each result in the list
|
|
828
|
+
corresponds to a separate output from the agent.
|
|
829
829
|
"""
|
|
830
|
-
results: list[
|
|
830
|
+
results: list[SapioAgentResult] = []
|
|
831
831
|
for output, container_type in zip(self.output_configs, self.output_container_types):
|
|
832
832
|
config: ToolIoConfigBasePbo = output.base_config
|
|
833
833
|
example: ExampleContainerPbo = config.testing_example
|
|
@@ -860,9 +860,9 @@ class ToolBase(ABC):
|
|
|
860
860
|
return results
|
|
861
861
|
|
|
862
862
|
@abstractmethod
|
|
863
|
-
def run(self, user: SapioUser) -> list[
|
|
863
|
+
def run(self, user: SapioUser) -> list[SapioAgentResult]:
|
|
864
864
|
"""
|
|
865
|
-
Execute this
|
|
865
|
+
Execute this agent.
|
|
866
866
|
|
|
867
867
|
The request inputs can be accessed using the self.get_input_*() methods.
|
|
868
868
|
The request settings can be accessed using the self.get_config_fields() method.
|
|
@@ -870,9 +870,9 @@ class ToolBase(ABC):
|
|
|
870
870
|
|
|
871
871
|
:param user: A user object that can be used to initialize manager classes using DataMgmtServer to query the
|
|
872
872
|
system.
|
|
873
|
-
:return: A list of
|
|
874
|
-
a separate output from the
|
|
875
|
-
appearing as records related to the plan step during the run.
|
|
873
|
+
:return: A list of SapioAgentResult objects containing the response data. Each result in the list corresponds to
|
|
874
|
+
a separate output from the agent. Field map results do not appear as agent output in the plan manager,
|
|
875
|
+
instead appearing as records related to the plan step during the run.
|
|
876
876
|
"""
|
|
877
877
|
pass
|
|
878
878
|
|
|
@@ -901,7 +901,7 @@ class ToolBase(ABC):
|
|
|
901
901
|
|
|
902
902
|
def log_info(self, message: str) -> None:
|
|
903
903
|
"""
|
|
904
|
-
Log an info message for this
|
|
904
|
+
Log an info message for this agent. If verbose logging is enabled, this message will be included in the logs
|
|
905
905
|
returned to the caller. Empty/None inputs will not be logged.
|
|
906
906
|
|
|
907
907
|
:param message: The message to log.
|
|
@@ -914,7 +914,7 @@ class ToolBase(ABC):
|
|
|
914
914
|
|
|
915
915
|
def log_warning(self, message: str) -> None:
|
|
916
916
|
"""
|
|
917
|
-
Log a warning message for this
|
|
917
|
+
Log a warning message for this agent. This message will be included in the logs returned to the caller.
|
|
918
918
|
Empty/None inputs will not be logged.
|
|
919
919
|
|
|
920
920
|
:param message: The message to log.
|
|
@@ -926,7 +926,7 @@ class ToolBase(ABC):
|
|
|
926
926
|
|
|
927
927
|
def log_error(self, message: str) -> None:
|
|
928
928
|
"""
|
|
929
|
-
Log an error message for this
|
|
929
|
+
Log an error message for this agent. This message will be included in the logs returned to the caller.
|
|
930
930
|
Empty/None inputs will not be logged.
|
|
931
931
|
|
|
932
932
|
:param message: The message to log.
|
|
@@ -938,7 +938,7 @@ class ToolBase(ABC):
|
|
|
938
938
|
|
|
939
939
|
def log_exception(self, message: str, e: Exception) -> None:
|
|
940
940
|
"""
|
|
941
|
-
Log an exception for this
|
|
941
|
+
Log an exception for this agent. This message will be included in the logs returned to the caller.
|
|
942
942
|
Empty/None inputs will not be logged.
|
|
943
943
|
|
|
944
944
|
:param message: The message to log.
|
|
@@ -953,7 +953,7 @@ class ToolBase(ABC):
|
|
|
953
953
|
"""
|
|
954
954
|
Check if the input at the given index is marked as partial.
|
|
955
955
|
|
|
956
|
-
:param index: The index of the input to check. Defaults to 0. Used for
|
|
956
|
+
:param index: The index of the input to check. Defaults to 0. Used for agents that accept multiple inputs.
|
|
957
957
|
:return: True if the input is marked as partial, False otherwise.
|
|
958
958
|
"""
|
|
959
959
|
return self.request.input[index].is_partial
|
|
@@ -962,7 +962,7 @@ class ToolBase(ABC):
|
|
|
962
962
|
"""
|
|
963
963
|
Get the name of the input from the request object.
|
|
964
964
|
|
|
965
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
965
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
966
966
|
:return: The name of the input from the request object, or None if no name is set.
|
|
967
967
|
"""
|
|
968
968
|
return self.request.input[index].item_container.container_name
|
|
@@ -971,7 +971,7 @@ class ToolBase(ABC):
|
|
|
971
971
|
"""
|
|
972
972
|
Get the content type of the input from the request object.
|
|
973
973
|
|
|
974
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
974
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
975
975
|
:return: The content type of the input from the request object.
|
|
976
976
|
"""
|
|
977
977
|
return self.request.input[index].item_container.content_type
|
|
@@ -980,7 +980,7 @@ class ToolBase(ABC):
|
|
|
980
980
|
"""
|
|
981
981
|
Get the binary data from the request object.
|
|
982
982
|
|
|
983
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
983
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
984
984
|
:return: The binary data from the request object.
|
|
985
985
|
"""
|
|
986
986
|
container: StepItemContainerPbo = self.request.input[index].item_container
|
|
@@ -992,7 +992,7 @@ class ToolBase(ABC):
|
|
|
992
992
|
"""
|
|
993
993
|
Parse the CSV data from the request object.
|
|
994
994
|
|
|
995
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
995
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
996
996
|
:return: A tuple containing the header row and the data rows. The header row is a list of strings representing
|
|
997
997
|
the column names, and the data rows are a list of dictionaries where each dictionary represents a row in the
|
|
998
998
|
CSV with the column names as keys and the corresponding values as strings.
|
|
@@ -1013,7 +1013,7 @@ class ToolBase(ABC):
|
|
|
1013
1013
|
"""
|
|
1014
1014
|
Parse the JSON data from the request object.
|
|
1015
1015
|
|
|
1016
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
1016
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
1017
1017
|
:return: A list of parsed JSON objects, which are represented as dictionaries.
|
|
1018
1018
|
"""
|
|
1019
1019
|
container: StepItemContainerPbo = self.request.input[index].item_container
|
|
@@ -1021,7 +1021,7 @@ class ToolBase(ABC):
|
|
|
1021
1021
|
raise Exception(f"Input {index} does not contain a JSON container.")
|
|
1022
1022
|
input_json: list[Any] = [json.loads(x) for x in container.json_container.items]
|
|
1023
1023
|
# Verify that the given JSON actually is a list of dictionaries. If they aren't then the previous step provided
|
|
1024
|
-
# bad input.
|
|
1024
|
+
# bad input. Agents are enforced to result in a list of dictionaries when returning JSON data, so this is likely
|
|
1025
1025
|
# an error caused by a script or static input step.
|
|
1026
1026
|
for i, entry in enumerate(input_json):
|
|
1027
1027
|
if not isinstance(entry, dict):
|
|
@@ -1033,7 +1033,7 @@ class ToolBase(ABC):
|
|
|
1033
1033
|
"""
|
|
1034
1034
|
Parse the text data from the request object.
|
|
1035
1035
|
|
|
1036
|
-
:param index: The index of the input to parse. Defaults to 0. Used for
|
|
1036
|
+
:param index: The index of the input to parse. Defaults to 0. Used for agents that accept multiple inputs.
|
|
1037
1037
|
:return: A list of text data as strings.
|
|
1038
1038
|
"""
|
|
1039
1039
|
container: StepItemContainerPbo = self.request.input[index].item_container
|
|
@@ -1043,7 +1043,7 @@ class ToolBase(ABC):
|
|
|
1043
1043
|
|
|
1044
1044
|
def get_config_defs(self) -> dict[str, VeloxFieldDefPbo]:
|
|
1045
1045
|
"""
|
|
1046
|
-
Get the config field definitions for this
|
|
1046
|
+
Get the config field definitions for this agent.
|
|
1047
1047
|
|
|
1048
1048
|
:return: A dictionary of field definitions, where the keys are the field names and the values are the
|
|
1049
1049
|
VeloxFieldDefPbo objects representing the field definitions.
|