pygeai 0.2.7b36__py3-none-any.whl → 0.2.7b38__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.
- pygeai/core/base/mappers.py +11 -2
- pygeai/core/models.py +20 -11
- pygeai/lab/managers.py +54 -129
- pygeai/organization/responses.py +23 -0
- pygeai/tests/health/__init__.py +0 -0
- pygeai/tests/health/test_clients.py +40 -0
- pygeai/tests/integration/lab/agents/test_create_agent.py +39 -34
- pygeai/tests/integration/lab/agents/test_create_sharing_link.py +101 -0
- pygeai/tests/integration/lab/agents/test_delete_agent.py +100 -0
- pygeai/tests/integration/lab/agents/test_get_agent.py +12 -7
- pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +139 -0
- pygeai/tests/integration/lab/agents/test_update_agent.py +69 -42
- pygeai/tests/lab/test_managers.py +45 -45
- pygeai/tests/organization/test_mappers.py +146 -0
- pygeai/tests/snippets/lab/agents/create_agent.py +1 -5
- pygeai/tests/snippets/lab/agents/create_agent_2.py +1 -5
- pygeai/tests/snippets/lab/agents/delete_agent.py +1 -5
- pygeai/tests/snippets/lab/agents/get_agent.py +2 -11
- pygeai/tests/snippets/lab/agents/get_sharing_link.py +3 -7
- pygeai/tests/snippets/lab/agents/list_agents.py +2 -6
- pygeai/tests/snippets/lab/agents/publish_agent_revision.py +2 -6
- pygeai/tests/snippets/lab/agents/update_agent.py +1 -5
- pygeai/tests/snippets/lab/processes/create_process.py +3 -5
- pygeai/tests/snippets/lab/processes/create_task.py +3 -5
- pygeai/tests/snippets/lab/processes/jobs/list_jobs.py +10 -19
- pygeai/tests/snippets/lab/processes/kbs/create_kb.py +2 -5
- pygeai/tests/snippets/lab/processes/kbs/get_kb.py +10 -16
- pygeai/tests/snippets/lab/processes/kbs/list_kbs.py +13 -20
- pygeai/tests/snippets/lab/processes/kbs/try_all.py +5 -7
- pygeai/tests/snippets/lab/processes/list_processes.py +5 -7
- pygeai/tests/snippets/lab/strategies/create_reasoning_strategy.py +2 -5
- pygeai/tests/snippets/lab/strategies/get_reasoning_strategy.py +2 -5
- pygeai/tests/snippets/lab/strategies/list_reasoning_strategies.py +3 -6
- pygeai/tests/snippets/lab/strategies/update_reasoning_strategy.py +2 -5
- pygeai/tests/snippets/lab/tools/create_tool.py +3 -7
- pygeai/tests/snippets/lab/tools/delete_tool.py +2 -6
- pygeai/tests/snippets/lab/tools/get_parameter.py +5 -7
- pygeai/tests/snippets/lab/tools/get_tool.py +5 -7
- pygeai/tests/snippets/lab/tools/list_tools.py +3 -7
- pygeai/tests/snippets/lab/tools/publish_tool_revision.py +3 -5
- pygeai/tests/snippets/lab/tools/set_parameters.py +4 -9
- pygeai/tests/snippets/lab/tools/update_tool.py +4 -8
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/METADATA +1 -1
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/RECORD +48 -42
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/WHEEL +0 -0
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/entry_points.txt +0 -0
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.2.7b36.dist-info → pygeai-0.2.7b38.dist-info}/top_level.txt +0 -0
pygeai/organization/responses.py
CHANGED
|
@@ -22,3 +22,26 @@ class ProjectTokensResponse(BaseModel):
|
|
|
22
22
|
|
|
23
23
|
class ProjectItemListResponse(BaseModel):
|
|
24
24
|
items: list[RequestItem]
|
|
25
|
+
|
|
26
|
+
def to_list(self):
|
|
27
|
+
return [item.to_dict() for item in self.items] if self.items else []
|
|
28
|
+
|
|
29
|
+
def __getitem__(self, index: int) -> RequestItem:
|
|
30
|
+
if self.items is None:
|
|
31
|
+
raise IndexError("ProjectItemListResponse is empty")
|
|
32
|
+
return self.items[index]
|
|
33
|
+
|
|
34
|
+
def __len__(self) -> int:
|
|
35
|
+
return len(self.items) if self.items else 0
|
|
36
|
+
|
|
37
|
+
def __iter__(self):
|
|
38
|
+
"""Make ProjectItemListResponse iterable over its items."""
|
|
39
|
+
if self.items is None:
|
|
40
|
+
return iter([])
|
|
41
|
+
return iter(self.items)
|
|
42
|
+
|
|
43
|
+
def append(self, item: RequestItem) -> None:
|
|
44
|
+
"""Append an Agent instance to the items list."""
|
|
45
|
+
if self.items is None:
|
|
46
|
+
self.items = []
|
|
47
|
+
self.items.append(item)
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from json import JSONDecodeError
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
6
|
+
from pygeai.health.clients import HealthClient
|
|
7
|
+
from pygeai.health.endpoints import STATUS_CHECK_V1
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestHealthClient(unittest.TestCase):
|
|
11
|
+
"""
|
|
12
|
+
python -m unittest pygeai.tests.health.test_clients.TestHealthClient
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def setUp(self):
|
|
16
|
+
self.client = HealthClient()
|
|
17
|
+
|
|
18
|
+
@patch("pygeai.core.services.rest.ApiService.get")
|
|
19
|
+
def test_check_api_status_success(self, mock_get):
|
|
20
|
+
expected_response = {"status": "healthy", "version": "1.0.0"}
|
|
21
|
+
mock_response = mock_get.return_value
|
|
22
|
+
mock_response.json.return_value = expected_response
|
|
23
|
+
|
|
24
|
+
result = self.client.check_api_status()
|
|
25
|
+
|
|
26
|
+
self.assertEqual(result, expected_response)
|
|
27
|
+
mock_get.assert_called_once_with(endpoint=STATUS_CHECK_V1)
|
|
28
|
+
|
|
29
|
+
@patch("pygeai.core.services.rest.ApiService.get")
|
|
30
|
+
def test_check_api_status_json_decode_error(self, mock_get):
|
|
31
|
+
mock_response = mock_get.return_value
|
|
32
|
+
mock_response.status_code = 200
|
|
33
|
+
mock_response.json.side_effect = JSONDecodeError("Invalid JSON", "", 0)
|
|
34
|
+
mock_response.text = "Invalid JSON response"
|
|
35
|
+
|
|
36
|
+
with self.assertRaises(InvalidAPIResponseException) as context:
|
|
37
|
+
self.client.check_api_status()
|
|
38
|
+
|
|
39
|
+
self.assertEqual(str(context.exception), "Unable to check API status: Invalid JSON response")
|
|
40
|
+
mock_get.assert_called_once_with(endpoint=STATUS_CHECK_V1)
|
|
@@ -4,6 +4,7 @@ import uuid
|
|
|
4
4
|
from pygeai.lab.managers import AILabManager
|
|
5
5
|
from pygeai.lab.models import Agent, AgentData, Prompt, LlmConfig, Model, Sampling, PromptExample, PromptOutput
|
|
6
6
|
from pydantic import ValidationError
|
|
7
|
+
from pygeai.core.common.exceptions import APIError, InvalidAPIResponseException
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class TestAILabCreateAgentIntegration(TestCase):
|
|
@@ -23,7 +24,9 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
23
24
|
This can be used to delete the created agent or reset the state.
|
|
24
25
|
"""
|
|
25
26
|
if isinstance(self.created_agent, Agent):
|
|
26
|
-
|
|
27
|
+
#TODO: Remove exception catch when delete_agent stop returning an unexpected error
|
|
28
|
+
with self.assertRaises(InvalidAPIResponseException) as e:
|
|
29
|
+
self.ai_lab_manager.delete_agent(self.project_id, self.created_agent.id)
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
def __load_agent(self):
|
|
@@ -151,11 +154,12 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
151
154
|
self.new_agent = Agent(
|
|
152
155
|
name=str(uuid.uuid4())
|
|
153
156
|
)
|
|
154
|
-
|
|
155
|
-
|
|
157
|
+
with self.assertRaises(APIError) as exception:
|
|
158
|
+
self.__create_agent(automatic_publish=auto_publish)
|
|
159
|
+
|
|
156
160
|
#TODO: Change validation error to a more specific one
|
|
157
|
-
self.
|
|
158
|
-
self.
|
|
161
|
+
self.assertIn("400",str(exception.exception))
|
|
162
|
+
self.assertIn("Bad Request",str(exception.exception))
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
def test_create_agent_no_name(self):
|
|
@@ -164,11 +168,12 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
164
168
|
for auto_publish in test_params:
|
|
165
169
|
with self.subTest(input=auto_publish):
|
|
166
170
|
self.new_agent.name = ""
|
|
167
|
-
|
|
171
|
+
with self.assertRaises(APIError) as exception:
|
|
172
|
+
self.__create_agent(automatic_publish=auto_publish)
|
|
168
173
|
|
|
169
|
-
self.
|
|
170
|
-
self.created_agent.errors[0].description,
|
|
174
|
+
self.assertIn(
|
|
171
175
|
"Agent name cannot be empty.",
|
|
176
|
+
str(exception.exception),
|
|
172
177
|
f"Expected an error about the missing agent name with autopublish {'enabled' if auto_publish else 'disabled'}"
|
|
173
178
|
)
|
|
174
179
|
|
|
@@ -180,12 +185,11 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
180
185
|
|
|
181
186
|
with self.subTest(input=auto_publish):
|
|
182
187
|
self.new_agent.name = "AritmeticaExpert"
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
self.assertEqual(
|
|
187
|
-
self.created_agent.errors[0].description,
|
|
188
|
+
with self.assertRaises(APIError) as exception:
|
|
189
|
+
self.__create_agent(automatic_publish=auto_publish)
|
|
190
|
+
self.assertIn(
|
|
188
191
|
"Agent cannot be created as it already exists [name=AritmeticaExpert].",
|
|
192
|
+
str(exception.exception),
|
|
189
193
|
f"Expected an error about duplicated agent name with autopublish {'enabled' if auto_publish else 'disabled'}"
|
|
190
194
|
)
|
|
191
195
|
|
|
@@ -194,26 +198,25 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
194
198
|
test_params = [ True, False ]
|
|
195
199
|
|
|
196
200
|
for auto_publish in test_params:
|
|
197
|
-
|
|
198
201
|
with self.subTest(input=auto_publish):
|
|
199
202
|
new_agent = self.__load_agent()
|
|
200
203
|
new_agent2 = self.__load_agent()
|
|
201
|
-
|
|
202
|
-
new_agent.name = f"{new_agent.name}:invalid"
|
|
203
|
-
result = self.__create_agent(agent=new_agent, automatic_publish=auto_publish)
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
self.
|
|
209
|
-
result.errors[0].description,
|
|
205
|
+
with self.assertRaises(APIError) as exception:
|
|
206
|
+
new_agent.name = f"{new_agent.name}:invalid"
|
|
207
|
+
self.__create_agent(agent=new_agent, automatic_publish=auto_publish)
|
|
208
|
+
self.assertIn(
|
|
210
209
|
"Invalid character in name (: is not allowed).",
|
|
210
|
+
str(exception.exception),
|
|
211
211
|
f"Expected an error about invalid character (:) in agent name with autopublish {'enabled' if auto_publish else 'disabled'}"
|
|
212
212
|
)
|
|
213
213
|
|
|
214
|
-
self.
|
|
215
|
-
|
|
214
|
+
with self.assertRaises(APIError) as exception:
|
|
215
|
+
new_agent2.name = f"{new_agent2.name}/invalid"
|
|
216
|
+
self.__create_agent(agent=new_agent2, automatic_publish=auto_publish)
|
|
217
|
+
self.assertIn(
|
|
216
218
|
"Invalid character in name (/ is not allowed).",
|
|
219
|
+
str(exception.exception),
|
|
217
220
|
f"Expected an error about invalid character (/) in agent name with autopublish {'enabled' if auto_publish else 'disabled'}"
|
|
218
221
|
)
|
|
219
222
|
|
|
@@ -243,11 +246,11 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
243
246
|
|
|
244
247
|
with self.subTest(input=auto_publish):
|
|
245
248
|
self.new_agent.public_name = None
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
self.
|
|
249
|
-
self.created_agent.errors[0].description,
|
|
249
|
+
with self.assertRaises(APIError) as exception:
|
|
250
|
+
self.__create_agent(automatic_publish=auto_publish)
|
|
251
|
+
self.assertIn(
|
|
250
252
|
"Agent publicName is required for agents with accessScope=public.",
|
|
253
|
+
str(exception.exception),
|
|
251
254
|
f"Expected an error about missing publicName for public access scope with autopublish {'enabled' if auto_publish else 'disabled'}"
|
|
252
255
|
)
|
|
253
256
|
|
|
@@ -258,11 +261,12 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
258
261
|
for auto_publish in test_params:
|
|
259
262
|
with self.subTest(input=auto_publish):
|
|
260
263
|
self.new_agent.public_name = self.new_agent.public_name.replace("_", "#") # Add invalid character to public name
|
|
261
|
-
|
|
264
|
+
with self.assertRaises(APIError) as exception:
|
|
265
|
+
self.__create_agent(automatic_publish=auto_publish)
|
|
262
266
|
|
|
263
|
-
self.
|
|
264
|
-
self.created_agent.errors[0].description,
|
|
267
|
+
self.assertIn(
|
|
265
268
|
"Invalid public name, it can only contain lowercase letters, numbers, periods (.), dashes (-), and underscores (_). Please remove any other characters.",
|
|
269
|
+
str(exception.exception),
|
|
266
270
|
f"The expected error about invalid publicName was not returned when autopublish is {'enabled' if auto_publish else 'disabled'}"
|
|
267
271
|
)
|
|
268
272
|
|
|
@@ -275,11 +279,12 @@ class TestAILabCreateAgentIntegration(TestCase):
|
|
|
275
279
|
with self.subTest(input=auto_publish):
|
|
276
280
|
duplicated_pn_agent = self.__load_agent()
|
|
277
281
|
duplicated_pn_agent.public_name = self.created_agent.public_name
|
|
278
|
-
result = self.__create_agent(agent=duplicated_pn_agent, automatic_publish=auto_publish)
|
|
279
282
|
|
|
280
|
-
self.
|
|
281
|
-
|
|
283
|
+
with self.assertRaises(APIError) as exception:
|
|
284
|
+
self.__create_agent(agent=duplicated_pn_agent, automatic_publish=auto_publish)
|
|
285
|
+
self.assertIn(
|
|
282
286
|
f"Agent already exists [publicName={self.created_agent.public_name}].",
|
|
287
|
+
str(exception.exception),
|
|
283
288
|
f"Expected an error about the duplicated public name when autopublish is {'enabled' if auto_publish else 'disabled'}"
|
|
284
289
|
)
|
|
285
290
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
import unittest
|
|
3
|
+
from pygeai.lab.managers import AILabManager
|
|
4
|
+
from pygeai.lab.models import SharingLink
|
|
5
|
+
from pygeai.core.common.exceptions import MissingRequirementException
|
|
6
|
+
|
|
7
|
+
ai_lab_manager: AILabManager
|
|
8
|
+
|
|
9
|
+
class TestAILabCreateSharingLinkIntegration(TestCase):
|
|
10
|
+
|
|
11
|
+
def setUp(self):
|
|
12
|
+
self.ai_lab_manager = AILabManager(alias="beta")
|
|
13
|
+
self.project_id = "be4889df-cacc-4e6f-b3bb-153c4ac0d168"
|
|
14
|
+
self.agent_id = "0026e53d-ea78-4cac-af9f-12650e5bb6d9"
|
|
15
|
+
|
|
16
|
+
def __create_sharing_link(self, agent_id=None, project_id=None):
|
|
17
|
+
return self.ai_lab_manager.create_sharing_link(
|
|
18
|
+
project_id=self.project_id if project_id is None else project_id,
|
|
19
|
+
agent_id=self.agent_id if agent_id is None else agent_id
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_create_sharing_link(self):
|
|
24
|
+
shared_link = self.__create_sharing_link()
|
|
25
|
+
self.assertIsInstance(shared_link, SharingLink, "Expected response to be an instance of SharingLink")
|
|
26
|
+
|
|
27
|
+
self.assertEqual(
|
|
28
|
+
shared_link.agent_id,
|
|
29
|
+
self.agent_id,
|
|
30
|
+
"Returned agentId should match the requested agent_id"
|
|
31
|
+
)
|
|
32
|
+
self.assertTrue(
|
|
33
|
+
shared_link.api_token.startswith("shared-"),
|
|
34
|
+
"apiToken should start with 'shared-'"
|
|
35
|
+
)
|
|
36
|
+
self.assertTrue(
|
|
37
|
+
shared_link.shared_link.startswith("https://"),
|
|
38
|
+
"sharedLink should be a valid URL"
|
|
39
|
+
)
|
|
40
|
+
self.assertIn(
|
|
41
|
+
f"agentId={self.agent_id}",
|
|
42
|
+
shared_link.shared_link,
|
|
43
|
+
"sharedLink should contain the agentId as a query parameter"
|
|
44
|
+
)
|
|
45
|
+
self.assertIn(
|
|
46
|
+
f"sharedToken={shared_link.api_token}",
|
|
47
|
+
shared_link.shared_link,
|
|
48
|
+
"sharedLink should contain the apiToken as sharedToken"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_create_sharing_link_no_project(self):
|
|
53
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
54
|
+
self.__create_sharing_link(project_id="")
|
|
55
|
+
self.assertEqual(
|
|
56
|
+
str(context.exception),
|
|
57
|
+
"Cannot create sharing link without specifying project_id",
|
|
58
|
+
"Expected exception for missing project_id"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def test_create_sharing_link_no_agent_id(self):
|
|
63
|
+
with self.assertRaises(MissingRequirementException) as context:
|
|
64
|
+
self.__create_sharing_link(agent_id="")
|
|
65
|
+
self.assertEqual(
|
|
66
|
+
str(context.exception),
|
|
67
|
+
"agent_id must be specified in order to create sharing link",
|
|
68
|
+
"Expected exception for missing agent_id"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
@unittest.skip("A descriptive error exception is expected")
|
|
72
|
+
def test_create_sharing_link_invalid_agent_id(self):
|
|
73
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
74
|
+
shared_link = self.__create_sharing_link(agent_id=invalid_id)
|
|
75
|
+
|
|
76
|
+
""" self.assertEqual(
|
|
77
|
+
deleted_agent.content["messages"][0]["description"],
|
|
78
|
+
f"Agent not found [IdOrName= {invalid_id}].",
|
|
79
|
+
"Expected error message for invalid agent id"
|
|
80
|
+
) """
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_create_sharing_link_invalid_project_id(self):
|
|
84
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
85
|
+
shared_link = self.__create_sharing_link(project_id=invalid_id)
|
|
86
|
+
|
|
87
|
+
self.assertIsInstance(shared_link, SharingLink, "Expected response to be an instance of SharingLink")
|
|
88
|
+
|
|
89
|
+
self.assertEqual(
|
|
90
|
+
shared_link.agent_id,
|
|
91
|
+
self.agent_id,
|
|
92
|
+
"Returned agentId should match the requested agent_id"
|
|
93
|
+
)
|
|
94
|
+
self.assertTrue(
|
|
95
|
+
shared_link.api_token.startswith("shared-"),
|
|
96
|
+
"apiToken should start with 'shared-'"
|
|
97
|
+
)
|
|
98
|
+
self.assertTrue(
|
|
99
|
+
shared_link.shared_link.startswith("https://"),
|
|
100
|
+
"sharedLink should be a valid URL"
|
|
101
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
import uuid
|
|
3
|
+
from pygeai.lab.managers import AILabManager
|
|
4
|
+
from pygeai.lab.models import Agent, AgentData, Prompt, LlmConfig, Model
|
|
5
|
+
from pygeai.core.common.exceptions import APIError
|
|
6
|
+
|
|
7
|
+
ai_lab_manager: AILabManager
|
|
8
|
+
|
|
9
|
+
class TestAILabDeleteAgentIntegration(TestCase):
|
|
10
|
+
|
|
11
|
+
def setUp(self):
|
|
12
|
+
self.ai_lab_manager = AILabManager(alias="beta")
|
|
13
|
+
self.project_id = "be4889df-cacc-4e6f-b3bb-153c4ac0d168"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def __create_agent(self):
|
|
17
|
+
"""
|
|
18
|
+
Helper to create an agent with the current project_id and ai_lab_manager.
|
|
19
|
+
If automatic_publish is None, do not pass it (useful for tests that omit it).
|
|
20
|
+
"""
|
|
21
|
+
agent = Agent(
|
|
22
|
+
name=str(uuid.uuid4()),
|
|
23
|
+
description="Agent that translates from any language to english.",
|
|
24
|
+
agent_data=AgentData(
|
|
25
|
+
prompt=Prompt(
|
|
26
|
+
instructions="the user will provide a text, you must return the same text translated to english",
|
|
27
|
+
inputs=["text", "avoid slang indicator"]
|
|
28
|
+
),
|
|
29
|
+
llm_config=LlmConfig(
|
|
30
|
+
max_tokens=1800,
|
|
31
|
+
timeout=0
|
|
32
|
+
),
|
|
33
|
+
models=[Model(name="gpt-4-turbo-preview")]
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
return self.ai_lab_manager.create_agent(
|
|
39
|
+
project_id=self.project_id,
|
|
40
|
+
agent=agent
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def __delete_agent(self, agent_id: str, project_id=None):
|
|
44
|
+
return self.ai_lab_manager.delete_agent(
|
|
45
|
+
project_id=self.project_id if project_id is None else project_id,
|
|
46
|
+
agent_id=agent_id
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_delete_agent(self):
|
|
51
|
+
create_agent = self.__create_agent()
|
|
52
|
+
deleted_agent = self.__delete_agent(agent_id=create_agent.id)
|
|
53
|
+
|
|
54
|
+
self.assertEqual(
|
|
55
|
+
deleted_agent.content,
|
|
56
|
+
"Agent deleted successfully",
|
|
57
|
+
"Expected confirmation message after deletion"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_delete_agent_no_project(self):
|
|
62
|
+
create_agent = self.__create_agent()
|
|
63
|
+
deleted_agent = self.__delete_agent(agent_id=create_agent.id, project_id="")
|
|
64
|
+
|
|
65
|
+
self.assertEqual(
|
|
66
|
+
deleted_agent.content,
|
|
67
|
+
"Agent deleted successfully",
|
|
68
|
+
"Expected confirmation message after deletion even with missing project_id"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_delete_agent_no_agent_id(self):
|
|
73
|
+
with self.assertRaises(APIError) as exception:
|
|
74
|
+
self.__delete_agent(agent_id="")
|
|
75
|
+
|
|
76
|
+
self.assertIn("405",str(exception.exception))
|
|
77
|
+
self.assertIn("Method Not Allowed",str(exception.exception))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_delete_agent_invalid_agent_id(self):
|
|
81
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
82
|
+
deleted_agent = self.__delete_agent(agent_id=invalid_id)
|
|
83
|
+
|
|
84
|
+
self.assertEqual(
|
|
85
|
+
deleted_agent.content["messages"][0]["description"],
|
|
86
|
+
f"Agent not found [IdOrName= {invalid_id}].",
|
|
87
|
+
"Expected error message for invalid agent id"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_delete_agent_invalid_project_id(self):
|
|
92
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
93
|
+
create_agent = self.__create_agent()
|
|
94
|
+
deleted_agent = self.__delete_agent(agent_id=create_agent.id, project_id=invalid_id)
|
|
95
|
+
|
|
96
|
+
self.assertEqual(
|
|
97
|
+
deleted_agent.content,
|
|
98
|
+
"Agent deleted successfully",
|
|
99
|
+
"Expected confirmation message after deletion even with invalid project id"
|
|
100
|
+
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from unittest import TestCase
|
|
2
|
-
import unittest
|
|
3
2
|
from pygeai.lab.managers import AILabManager
|
|
4
3
|
from pygeai.lab.models import Agent, FilterSettings
|
|
4
|
+
from pygeai.core.common.exceptions import MissingRequirementException, APIError
|
|
5
5
|
import copy
|
|
6
6
|
|
|
7
7
|
ai_lab_manager: AILabManager
|
|
@@ -41,8 +41,13 @@ class TestAILabGetAgentIntegration(TestCase):
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def test_get_agent_no_project(self):
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
with self.assertRaises(MissingRequirementException) as excepcion:
|
|
45
|
+
self.__get_agent(project_id="")
|
|
46
|
+
self.assertIn(
|
|
47
|
+
"Cannot retrieve agent without specifying project_id",
|
|
48
|
+
str(excepcion.exception),
|
|
49
|
+
"Expected exception for missing project_id"
|
|
50
|
+
)
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
def test_get_agent_no_agent_id(self):
|
|
@@ -57,11 +62,11 @@ class TestAILabGetAgentIntegration(TestCase):
|
|
|
57
62
|
|
|
58
63
|
def test_get_agent_invalid_agent_id(self):
|
|
59
64
|
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
self.
|
|
63
|
-
agent.errors[0].description,
|
|
65
|
+
with self.assertRaises(APIError) as context:
|
|
66
|
+
self.__get_agent(agent_id=invalid_id)
|
|
67
|
+
self.assertIn(
|
|
64
68
|
f"Agent not found [IdOrName= {invalid_id}].",
|
|
69
|
+
str(context.exception),
|
|
65
70
|
"Expected an error for invalid agent id"
|
|
66
71
|
)
|
|
67
72
|
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
import uuid
|
|
3
|
+
from pygeai.lab.managers import AILabManager
|
|
4
|
+
from pygeai.lab.models import Agent, AgentData, Prompt, PromptOutput, PromptExample, LlmConfig, Sampling, Model
|
|
5
|
+
from pygeai.core.common.exceptions import APIError
|
|
6
|
+
|
|
7
|
+
ai_lab_manager: AILabManager
|
|
8
|
+
|
|
9
|
+
class TestAILabPublishAgentRevisionIntegration(TestCase):
|
|
10
|
+
|
|
11
|
+
def setUp(self):
|
|
12
|
+
self.ai_lab_manager = AILabManager(alias="beta")
|
|
13
|
+
self.project_id = "be4889df-cacc-4e6f-b3bb-153c4ac0d168"
|
|
14
|
+
self.agent_id = "b4b09935-2ad2-42c0-bd55-1ee6fa4b6034"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def __publish_agent_revision(self, revision: str, project_id=None, agent_id=None):
|
|
18
|
+
return self.ai_lab_manager.publish_agent_revision(
|
|
19
|
+
project_id=self.project_id if project_id is None else project_id,
|
|
20
|
+
agent_id=self.agent_id if agent_id is None else agent_id,
|
|
21
|
+
revision=revision
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def __load_agent(self):
|
|
26
|
+
random_str = str(uuid.uuid4())
|
|
27
|
+
agent = Agent(
|
|
28
|
+
id="b4b09935-2ad2-42c0-bd55-1ee6fa4b6034",
|
|
29
|
+
name=f"UpdatedAgent{random_str}",
|
|
30
|
+
access_scope="public",
|
|
31
|
+
public_name=f"public_{random_str}",
|
|
32
|
+
job_description=f"SummarizerAgent{random_str}",
|
|
33
|
+
avatar_image="https://www.shareicon.net/data/128x128/2016/11/09/851442_logo_512x512.png",
|
|
34
|
+
description=f"Agent that summarized documents. {random_str}",
|
|
35
|
+
agent_data=AgentData(
|
|
36
|
+
prompt=Prompt(
|
|
37
|
+
instructions="the user will provide a document, you must return a summary of the document.",
|
|
38
|
+
inputs=["text", "avoid slang indicator"],
|
|
39
|
+
outputs=[
|
|
40
|
+
PromptOutput(key="translated_text", description="translated text, with slang or not depending on the indication. in plain text.")
|
|
41
|
+
],
|
|
42
|
+
examples=[
|
|
43
|
+
PromptExample(input_data="hola mundo [no-slang]", output='{"translated_text":"hello world"}'),
|
|
44
|
+
PromptExample(input_data="esto es una prueba pincheguey [keep-slang]", output='{"translated_text":"this is a test pal"}')
|
|
45
|
+
]
|
|
46
|
+
),
|
|
47
|
+
llm_config=LlmConfig(
|
|
48
|
+
max_tokens=1800,
|
|
49
|
+
timeout=0,
|
|
50
|
+
sampling=Sampling(temperature=0.3, top_k=0, top_p=0)
|
|
51
|
+
),
|
|
52
|
+
models=[Model(name="openai/gpt-4-turbo-preview")]
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return agent
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def __update_agent(self):
|
|
60
|
+
"""
|
|
61
|
+
Helper method to update agent and generate a new revision of it
|
|
62
|
+
"""
|
|
63
|
+
agent = self.__load_agent()
|
|
64
|
+
return self.ai_lab_manager.update_agent(
|
|
65
|
+
project_id=self.project_id,
|
|
66
|
+
agent=agent,
|
|
67
|
+
automatic_publish=False,
|
|
68
|
+
upsert=False
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_publish_agent_revision(self):
|
|
73
|
+
new_revision = (self.__update_agent()).revision
|
|
74
|
+
published_agent = self.__publish_agent_revision(revision=new_revision)
|
|
75
|
+
|
|
76
|
+
self.assertFalse(published_agent.is_draft, "Expected draft to be false after publishing the revision")
|
|
77
|
+
self.assertEqual(published_agent.revision, new_revision, "Expected last revision to be published")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_publish_agent_earlier_revision(self):
|
|
81
|
+
with self.assertRaises(APIError) as exception:
|
|
82
|
+
self.__publish_agent_revision(revision="1")
|
|
83
|
+
self.assertIn(
|
|
84
|
+
"There are newer published revisions.",
|
|
85
|
+
str(exception.exception),
|
|
86
|
+
"Expected error when trying to send a earlier revision"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_publish_agent_invalid_revision(self):
|
|
91
|
+
with self.assertRaises(APIError) as exception:
|
|
92
|
+
self.__publish_agent_revision(revision="10000000")
|
|
93
|
+
self.assertIn(
|
|
94
|
+
"Invalid revision [rev=10000000]",
|
|
95
|
+
str(exception.exception),
|
|
96
|
+
"Expected error when trying to send a revision that does not exist"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_publish_agent_string_revision(self):
|
|
101
|
+
with self.assertRaises(APIError) as exception:
|
|
102
|
+
self.__publish_agent_revision(revision="revision")
|
|
103
|
+
self.assertIn("Bad Request", str(exception.exception))
|
|
104
|
+
self.assertIn("400", str(exception.exception))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_publish_agent_invalid_agent_id(self):
|
|
108
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
109
|
+
with self.assertRaises(APIError) as exception:
|
|
110
|
+
self.__publish_agent_revision(revision="103", agent_id=invalid_id)
|
|
111
|
+
self.assertIn(
|
|
112
|
+
f"Agent not found [IdOrName= {invalid_id}].",
|
|
113
|
+
str(exception.exception),
|
|
114
|
+
"Expected error when sending and invalid agent id"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_publish_agent_no_agent_id(self):
|
|
119
|
+
with self.assertRaises(APIError) as exception:
|
|
120
|
+
self.__publish_agent_revision(revision="103", agent_id="")
|
|
121
|
+
self.assertIn("Not Found", str(exception.exception))
|
|
122
|
+
self.assertIn("404", str(exception.exception))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_publish_agent_invalid_project_id(self):
|
|
126
|
+
new_revision = (self.__update_agent()).revision
|
|
127
|
+
invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
|
|
128
|
+
published_agent = self.__publish_agent_revision(revision=new_revision, project_id=invalid_id)
|
|
129
|
+
|
|
130
|
+
self.assertFalse(published_agent.is_draft, "Expected draft to be false after publishing the revision")
|
|
131
|
+
self.assertEqual(published_agent.revision, new_revision, "Expected last revision to be published")
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_publish_agent_no_project_id(self):
|
|
135
|
+
new_revision = (self.__update_agent()).revision
|
|
136
|
+
published_agent = self.__publish_agent_revision(revision=new_revision, project_id="")
|
|
137
|
+
|
|
138
|
+
self.assertFalse(published_agent.is_draft, "Expected draft to be false after publishing the revision")
|
|
139
|
+
self.assertEqual(published_agent.revision, new_revision, "Expected last revision to be published")
|