sapiopycommons 2025.10.13a781__py3-none-any.whl → 2025.10.16a785__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/agent_service_base.py +80 -2
- sapiopycommons/ai/external_credentials.py +112 -21
- sapiopycommons/ai/test_client.py +25 -1
- {sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/METADATA +1 -1
- {sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/RECORD +7 -7
- {sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/WHEEL +0 -0
- {sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/licenses/LICENSE +0 -0
|
@@ -22,7 +22,7 @@ from sapiopycommons.ai.protoapi.externalcredentials.external_credentials_pb2 imp
|
|
|
22
22
|
from sapiopycommons.ai.protoapi.fielddefinitions.fields_pb2 import FieldValueMapPbo, FieldValuePbo
|
|
23
23
|
from sapiopycommons.ai.protoapi.fielddefinitions.velox_field_def_pb2 import VeloxFieldDefPbo, FieldTypePbo, \
|
|
24
24
|
SelectionPropertiesPbo, IntegerPropertiesPbo, DoublePropertiesPbo, BooleanPropertiesPbo, StringPropertiesPbo, \
|
|
25
|
-
FieldValidatorPbo
|
|
25
|
+
FieldValidatorPbo, DatePropertiesPbo
|
|
26
26
|
from sapiopycommons.ai.protoapi.plan.item.item_container_pb2 import ContentTypePbo
|
|
27
27
|
from sapiopycommons.ai.protoapi.plan.tool.entry_pb2 import StepOutputBatchPbo, StepItemContainerPbo, \
|
|
28
28
|
StepBinaryContainerPbo, StepCsvContainerPbo, StepCsvHeaderRowPbo, StepCsvRowPbo, StepJsonContainerPbo, \
|
|
@@ -782,6 +782,67 @@ class AgentBase(ABC):
|
|
|
782
782
|
)
|
|
783
783
|
))
|
|
784
784
|
|
|
785
|
+
def add_date_config_field(self, field_name: str, display_name: str, description: str, optional: bool = False,
|
|
786
|
+
date_time_format: str = "MMM dd, yyyy", default_to_today: bool = False,
|
|
787
|
+
is_static_date: bool = False) -> None:
|
|
788
|
+
"""
|
|
789
|
+
Add a date configuration field to the agent. This field will be used to configure the agent in the plan
|
|
790
|
+
manager.
|
|
791
|
+
|
|
792
|
+
:param field_name: The name of the field.
|
|
793
|
+
:param display_name: The display name of the field.
|
|
794
|
+
:param description: The description of the field.
|
|
795
|
+
:param date_time_format: The format that this date field should appear in. The date format is Java-style.
|
|
796
|
+
See https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/text/SimpleDateFormat.html for more
|
|
797
|
+
details.
|
|
798
|
+
:param default_to_today: If true, the default value of the field will be set to today's date. If false, the
|
|
799
|
+
default value will be None.
|
|
800
|
+
:param is_static_date: If true, the user will input the date as UTC. If false, the user will input the date
|
|
801
|
+
as local time.
|
|
802
|
+
:param optional: If true, this field is optional. If false, this field is required.
|
|
803
|
+
"""
|
|
804
|
+
self.config_fields.append(VeloxFieldDefPbo(
|
|
805
|
+
data_field_type=FieldTypePbo.DATE,
|
|
806
|
+
data_field_name=field_name,
|
|
807
|
+
display_name=display_name,
|
|
808
|
+
description=description,
|
|
809
|
+
required=not optional,
|
|
810
|
+
editable=True,
|
|
811
|
+
date_properties=DatePropertiesPbo(
|
|
812
|
+
default_value="@Today" if default_to_today else None,
|
|
813
|
+
static_date=is_static_date,
|
|
814
|
+
date_time_format=date_time_format
|
|
815
|
+
)
|
|
816
|
+
))
|
|
817
|
+
|
|
818
|
+
def add_credentials_config_field(self, field_name: str, display_name: str, description: str, optional: bool = False,
|
|
819
|
+
category: str | None = None) -> None:
|
|
820
|
+
"""
|
|
821
|
+
Add a list field that asks the user to choose which credentials to use. This field will be used to
|
|
822
|
+
configure the agent in the plan manager.
|
|
823
|
+
|
|
824
|
+
:param field_name: The name of the field.
|
|
825
|
+
:param display_name: The display name of the field.
|
|
826
|
+
:param description: The description of the field.
|
|
827
|
+
:param optional: If true, this field is optional. If false, this field is required.
|
|
828
|
+
:param category: If provided, only credentials in this category will be shown to the user.
|
|
829
|
+
"""
|
|
830
|
+
self.config_fields.append(VeloxFieldDefPbo(
|
|
831
|
+
data_field_type=FieldTypePbo.SELECTION,
|
|
832
|
+
data_field_name=field_name,
|
|
833
|
+
display_name=display_name,
|
|
834
|
+
description=description,
|
|
835
|
+
required=not optional,
|
|
836
|
+
editable=True,
|
|
837
|
+
selection_properties=SelectionPropertiesPbo(
|
|
838
|
+
# A credentials field is just a selection field with its list mode set to [ExternalCredentials].
|
|
839
|
+
list_mode=f"[ExternalCredentials]{category.strip() if category else ''}",
|
|
840
|
+
multi_select=False,
|
|
841
|
+
default_value=None,
|
|
842
|
+
direct_edit=False
|
|
843
|
+
)
|
|
844
|
+
))
|
|
845
|
+
|
|
785
846
|
def to_pbo(self) -> ToolDetailsPbo:
|
|
786
847
|
"""
|
|
787
848
|
:return: The ToolDetailsPbo proto object representing this agent.
|
|
@@ -908,7 +969,24 @@ class AgentBase(ABC):
|
|
|
908
969
|
if len(matching_creds) > 1:
|
|
909
970
|
raise ValueError(f"Multiple credentials found for category '{category}' and host '{host}'.")
|
|
910
971
|
|
|
911
|
-
return ExternalCredentials(matching_creds[0])
|
|
972
|
+
return ExternalCredentials.from_pbo(matching_creds[0])
|
|
973
|
+
|
|
974
|
+
def get_credentials_from_config(self, value: str) -> ExternalCredentials:
|
|
975
|
+
"""
|
|
976
|
+
Get credentials given the value of a credentials config field.
|
|
977
|
+
|
|
978
|
+
:param value: The value of the credentials config field.
|
|
979
|
+
:return: An ExternalCredentials object containing the credentials.
|
|
980
|
+
"""
|
|
981
|
+
# Values should be of the format "Name (Identifier)"
|
|
982
|
+
match = re.match(r"^(.*) \((.*)\)$", value)
|
|
983
|
+
if not match:
|
|
984
|
+
raise ValueError(f"Invalid credentials value '{value}'. Expected format 'Name (Identifier)'.")
|
|
985
|
+
identifier: str = match.group(2)
|
|
986
|
+
for cred in self.request.external_credential:
|
|
987
|
+
if cred.id == identifier:
|
|
988
|
+
return ExternalCredentials.from_pbo(cred)
|
|
989
|
+
raise ValueError(f"No credentials found with identifier '{identifier}'.")
|
|
912
990
|
|
|
913
991
|
def call_subprocess(self,
|
|
914
992
|
args: str | bytes | PathLike[str] | PathLike[bytes] | Sequence[str | bytes | PathLike[str] | PathLike[bytes]],
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from sapiopycommons.ai.protoapi.externalcredentials.external_credentials_pb2 import ExternalCredentialsPbo
|
|
2
4
|
|
|
3
5
|
|
|
@@ -5,26 +7,97 @@ class ExternalCredentials:
|
|
|
5
7
|
"""
|
|
6
8
|
A class representing external credentials.
|
|
7
9
|
"""
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def __init__(self,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
10
|
+
_identifier: str
|
|
11
|
+
_display_name: str
|
|
12
|
+
_description: str
|
|
13
|
+
_category: str
|
|
14
|
+
_url: str
|
|
15
|
+
_username: str
|
|
16
|
+
_password: str
|
|
17
|
+
_token: str
|
|
18
|
+
_custom_fields: dict[str, str]
|
|
19
|
+
|
|
20
|
+
def __init__(self, url: str, category: str, identifier: str = "", display_name: str = "", description: str = "",
|
|
21
|
+
username: str = "", password: str = "", token: str = "", custom_fields: dict[str, str] | None = None):
|
|
22
|
+
"""
|
|
23
|
+
:param url: The URL that the credentials are for.
|
|
24
|
+
:param category: The category of the credentials. This can be used to search for the credentials using the
|
|
25
|
+
AgentBase.get_credentials function.
|
|
26
|
+
:param identifier: The unique identifier for the credentials.
|
|
27
|
+
:param display_name: The display name for the credentials.
|
|
28
|
+
:param description: A description of the credentials.
|
|
29
|
+
:param username: The username for the credentials.
|
|
30
|
+
:param password: The password for the credentials.
|
|
31
|
+
:param token: The token for the credentials.
|
|
32
|
+
:param custom_fields: A dictionary of custom fields associated with the credentials.
|
|
33
|
+
"""
|
|
34
|
+
self._identifier = identifier
|
|
35
|
+
self._display_name = display_name
|
|
36
|
+
self._description = description
|
|
37
|
+
self._category = category
|
|
38
|
+
self._url = url
|
|
39
|
+
self._username = username
|
|
40
|
+
self._password = password
|
|
41
|
+
self._token = token
|
|
42
|
+
self._custom_fields = custom_fields or {}
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def from_pbo(pbo: ExternalCredentialsPbo) -> ExternalCredentials:
|
|
46
|
+
"""
|
|
47
|
+
Create an ExternalCredentials instance from a protobuf object.
|
|
48
|
+
|
|
49
|
+
:param pbo: An ExternalCredentialsPbo object.
|
|
50
|
+
:return: An ExternalCredentials instance.
|
|
51
|
+
"""
|
|
52
|
+
creds = ExternalCredentials(pbo.url, pbo.category)
|
|
53
|
+
creds._identifier = pbo.id
|
|
54
|
+
creds._display_name = pbo.display_name
|
|
55
|
+
creds._description = pbo.description
|
|
56
|
+
creds._username = pbo.username
|
|
57
|
+
creds._password = pbo.password
|
|
58
|
+
creds._token = pbo.token
|
|
59
|
+
creds._custom_fields = dict(pbo.custom_field)
|
|
60
|
+
return creds
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def identifier(self) -> str:
|
|
64
|
+
"""The unique identifier for the credentials."""
|
|
65
|
+
return self._identifier
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def display_name(self) -> str:
|
|
69
|
+
"""The display name for the credentials."""
|
|
70
|
+
return self._display_name
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def description(self) -> str:
|
|
74
|
+
"""A description of the credentials."""
|
|
75
|
+
return self._description
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def category(self) -> str:
|
|
79
|
+
"""The category of the credentials."""
|
|
80
|
+
return self._category
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def url(self) -> str:
|
|
84
|
+
"""The URL that the credentials are for."""
|
|
85
|
+
return self._url
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def username(self) -> str:
|
|
89
|
+
"""The username for the credentials."""
|
|
90
|
+
return self._username
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def password(self) -> str:
|
|
94
|
+
"""The password for the credentials."""
|
|
95
|
+
return self._password
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def token(self) -> str:
|
|
99
|
+
"""The token for the credentials."""
|
|
100
|
+
return self._token
|
|
28
101
|
|
|
29
102
|
def get_custom_field(self, key: str, default: str = None) -> str | None:
|
|
30
103
|
"""
|
|
@@ -34,4 +107,22 @@ class ExternalCredentials:
|
|
|
34
107
|
:param default: The value to return if the key does not exist.
|
|
35
108
|
:return: The value of the custom field, or None if the key does not exist.
|
|
36
109
|
"""
|
|
37
|
-
return self.
|
|
110
|
+
return self._custom_fields.get(key, default)
|
|
111
|
+
|
|
112
|
+
def to_pbo(self) -> ExternalCredentialsPbo:
|
|
113
|
+
"""
|
|
114
|
+
Convert the ExternalCredentials instance to a protobuf object.
|
|
115
|
+
|
|
116
|
+
:return: An ExternalCredentialsPbo object.
|
|
117
|
+
"""
|
|
118
|
+
return ExternalCredentialsPbo(
|
|
119
|
+
id=self._identifier,
|
|
120
|
+
display_name=self._display_name,
|
|
121
|
+
description=self._description,
|
|
122
|
+
category=self._category,
|
|
123
|
+
url=self._url,
|
|
124
|
+
username=self._username,
|
|
125
|
+
password=self._password,
|
|
126
|
+
token=self._token,
|
|
127
|
+
custom_field=self._custom_fields
|
|
128
|
+
)
|
sapiopycommons/ai/test_client.py
CHANGED
|
@@ -7,6 +7,8 @@ from typing import Any
|
|
|
7
7
|
import grpc
|
|
8
8
|
from sapiopylib.rest.User import SapioUser
|
|
9
9
|
|
|
10
|
+
from sapiopycommons.ai.external_credentials import ExternalCredentials
|
|
11
|
+
from sapiopycommons.ai.protoapi.externalcredentials.external_credentials_pb2 import ExternalCredentialsPbo
|
|
10
12
|
from sapiopycommons.ai.protoapi.fielddefinitions.fields_pb2 import FieldValuePbo
|
|
11
13
|
from sapiopycommons.ai.protoapi.plan.converter.converter_pb2 import ConverterDetailsRequestPbo, \
|
|
12
14
|
ConverterDetailsResponsePbo, ConvertResponsePbo, ConvertRequestPbo
|
|
@@ -65,7 +67,8 @@ class AgentOutput:
|
|
|
65
67
|
self.new_records = []
|
|
66
68
|
self.logs = []
|
|
67
69
|
|
|
68
|
-
def save_outputs(self, path: str = "test_outputs", subfolder: str | None = None,
|
|
70
|
+
def save_outputs(self, path: str = "test_outputs", subfolder: str | None = None,
|
|
71
|
+
file_extensions: list[str] | None = None) -> None:
|
|
69
72
|
"""
|
|
70
73
|
Save all outputs to files in the specified output directory.
|
|
71
74
|
|
|
@@ -168,6 +171,7 @@ class TestClient:
|
|
|
168
171
|
connection: SapioConnectionInfoPbo
|
|
169
172
|
_request_inputs: list[StepItemContainerPbo]
|
|
170
173
|
_config_fields: dict[str, FieldValuePbo]
|
|
174
|
+
_credentials: list[ExternalCredentialsPbo]
|
|
171
175
|
|
|
172
176
|
def __init__(self, grpc_server_url: str, message_mb_size: int = 1024, user: SapioUser | None = None,
|
|
173
177
|
options: list[tuple[str, Any]] | None = None):
|
|
@@ -188,6 +192,7 @@ class TestClient:
|
|
|
188
192
|
self._create_connection(user)
|
|
189
193
|
self._request_inputs = []
|
|
190
194
|
self._config_fields = {}
|
|
195
|
+
self._credentials = []
|
|
191
196
|
|
|
192
197
|
def _create_connection(self, user: SapioUser | None = None):
|
|
193
198
|
"""
|
|
@@ -272,10 +277,28 @@ class TestClient:
|
|
|
272
277
|
"""
|
|
273
278
|
self._config_fields.clear()
|
|
274
279
|
|
|
280
|
+
def add_credentials(self, credentials: list[ExternalCredentials]) -> None:
|
|
281
|
+
"""
|
|
282
|
+
Add external credentials to the connection info for the next request.
|
|
283
|
+
|
|
284
|
+
:param credentials: A list of ExternalCredentialsPbo objects to add to the connection info.
|
|
285
|
+
"""
|
|
286
|
+
for cred in credentials:
|
|
287
|
+
self._credentials.append(cred.to_pbo())
|
|
288
|
+
|
|
289
|
+
def clear_credentials(self) -> None:
|
|
290
|
+
"""
|
|
291
|
+
Clear all external credentials that have been added to the next request.
|
|
292
|
+
This is useful if you want to start a new request without the previous credentials.
|
|
293
|
+
"""
|
|
294
|
+
self._credentials.clear()
|
|
295
|
+
|
|
275
296
|
def clear_request(self) -> None:
|
|
276
297
|
"""
|
|
277
298
|
Clear all inputs and configuration fields that have been added to the next request.
|
|
278
299
|
This is useful if you want to start a new request without the previous inputs and configurations.
|
|
300
|
+
|
|
301
|
+
Credentials are not cleared, as they may be reused across multiple requests.
|
|
279
302
|
"""
|
|
280
303
|
self.clear_inputs()
|
|
281
304
|
self.clear_configs()
|
|
@@ -331,6 +354,7 @@ class TestClient:
|
|
|
331
354
|
config_field_values=self._config_fields,
|
|
332
355
|
dry_run=is_dry_run,
|
|
333
356
|
verbose_logging=is_verbose,
|
|
357
|
+
external_credential=self._credentials,
|
|
334
358
|
input=[
|
|
335
359
|
StepInputBatchPbo(is_partial=False, item_container=item)
|
|
336
360
|
for item in self._request_inputs
|
{sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sapiopycommons
|
|
3
|
-
Version: 2025.10.
|
|
3
|
+
Version: 2025.10.16a785
|
|
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,12 +1,12 @@
|
|
|
1
1
|
sapiopycommons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
sapiopycommons/ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
sapiopycommons/ai/agent_service_base.py,sha256=
|
|
3
|
+
sapiopycommons/ai/agent_service_base.py,sha256=eTJunFQoxLc0risWiQIkQK946XpHzSFO38NzzRvOn9Q,60325
|
|
4
4
|
sapiopycommons/ai/converter_service_base.py,sha256=HiUXmwqv1STgyQeF9_eTFXzjIFXp5-NJ7sEhMpV3aAU,6351
|
|
5
|
-
sapiopycommons/ai/external_credentials.py,sha256=
|
|
5
|
+
sapiopycommons/ai/external_credentials.py,sha256=ki_xIH4J843b_sSwEa8YHr8vW9erVv-jowZJXSgPQs8,4347
|
|
6
6
|
sapiopycommons/ai/protobuf_utils.py,sha256=cBjbxoFAwU02kNUxEce95WnMU2CMuDD-qFaeWgvQJMQ,24599
|
|
7
7
|
sapiopycommons/ai/request_validation.py,sha256=TD2EUi_G5cy1OOVK1AmY2SQc3PEoAKGWs2pT8Qnp2Oo,25092
|
|
8
8
|
sapiopycommons/ai/server.py,sha256=gutSskn_Fenq1uz0DDMvjx4QVFiKt2WVEP3-01a69eU,6384
|
|
9
|
-
sapiopycommons/ai/test_client.py,sha256=
|
|
9
|
+
sapiopycommons/ai/test_client.py,sha256=IRZ-8prhg7XMDmN9aC1MQr5mSkMgfT37aLsOy-VB-MU,20495
|
|
10
10
|
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.py,sha256=mEonoj6Iq-AyvO4m3YsPYu85aZfD1E0a0cL8B9yPfEo,2481
|
|
11
11
|
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2.pyi,sha256=sfExq8fFwIwFxCpV50ytdxW5ePNBjJBr_80_trq_JQw,1658
|
|
12
12
|
sapiopycommons/ai/protoapi/externalcredentials/external_credentials_pb2_grpc.py,sha256=TNS1CB_QGBSa1YU9sYR_hF-pmBwv2GpxjaNQoM_r9iU,948
|
|
@@ -106,7 +106,7 @@ sapiopycommons/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
106
106
|
sapiopycommons/webhook/webhook_context.py,sha256=D793uLsb1691SalaPnBUk3rOSxn_hYLhdvkaIxjNXss,1909
|
|
107
107
|
sapiopycommons/webhook/webhook_handlers.py,sha256=7o_wXOruhT9auNh8OfhJAh4WhhiPKij67FMBSpGPICc,39939
|
|
108
108
|
sapiopycommons/webhook/webservice_handlers.py,sha256=cvW6Mk_110BzYqkbk63Kg7jWrltBCDALOlkJRu8h4VQ,14300
|
|
109
|
-
sapiopycommons-2025.10.
|
|
110
|
-
sapiopycommons-2025.10.
|
|
111
|
-
sapiopycommons-2025.10.
|
|
112
|
-
sapiopycommons-2025.10.
|
|
109
|
+
sapiopycommons-2025.10.16a785.dist-info/METADATA,sha256=2yQ4MjvJOysrdpojvELXBXHk9Pk_hDU7D1cl3k6zHKQ,3143
|
|
110
|
+
sapiopycommons-2025.10.16a785.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
111
|
+
sapiopycommons-2025.10.16a785.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
112
|
+
sapiopycommons-2025.10.16a785.dist-info/RECORD,,
|
|
File without changes
|
{sapiopycommons-2025.10.13a781.dist-info → sapiopycommons-2025.10.16a785.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|