pygeai 0.4.0b3__py3-none-any.whl → 0.4.0b5__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/assistant/rag/models.py +1 -1
- pygeai/cli/commands/chat.py +8 -2
- pygeai/cli/commands/lab/ai_lab.py +44 -550
- pygeai/cli/commands/lab/utils.py +13 -0
- pygeai/cli/geai.py +5 -2
- pygeai/cli/texts/help.py +12 -0
- pygeai/core/common/exceptions.py +5 -0
- pygeai/lab/agents/clients.py +30 -61
- pygeai/lab/clients.py +17 -0
- pygeai/lab/managers.py +1 -53
- pygeai/lab/models.py +1 -1
- pygeai/lab/processes/clients.py +81 -129
- pygeai/lab/processes/mappers.py +2 -2
- pygeai/lab/strategies/clients.py +11 -17
- pygeai/lab/tools/clients.py +30 -50
- pygeai/lab/tools/mappers.py +5 -5
- pygeai/tests/integration/chat/__init__.py +0 -0
- pygeai/tests/integration/chat/test_generate_image.py +162 -0
- pygeai/tests/integration/lab/agents/test_create_agent.py +9 -12
- pygeai/tests/integration/lab/agents/test_update_agent.py +6 -14
- pygeai/tests/integration/lab/tools/test_create_tool.py +3 -5
- pygeai/tests/integration/lab/tools/test_list_tools.py +106 -0
- pygeai/tests/integration/lab/tools/test_update_tool.py +268 -0
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/METADATA +4 -4
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/RECORD +29 -23
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/WHEEL +0 -0
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/entry_points.txt +0 -0
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/licenses/LICENSE +0 -0
- {pygeai-0.4.0b3.dist-info → pygeai-0.4.0b5.dist-info}/top_level.txt +0 -0
pygeai/lab/processes/mappers.py
CHANGED
pygeai/lab/strategies/clients.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from json import JSONDecodeError
|
|
2
2
|
|
|
3
3
|
from pygeai import logger
|
|
4
|
-
from pygeai.core.base.clients import BaseClient
|
|
5
4
|
from pygeai.core.common.exceptions import InvalidAPIResponseException
|
|
5
|
+
from pygeai.lab.clients import AILabClient
|
|
6
6
|
from pygeai.lab.strategies.endpoints import LIST_REASONING_STRATEGIES_V2, CREATE_REASONING_STRATEGY_V2, \
|
|
7
7
|
UPDATE_REASONING_STRATEGY_V2, UPSERT_REASONING_STRATEGY_V2, GET_REASONING_STRATEGY_V2
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class ReasoningStrategyClient(
|
|
10
|
+
class ReasoningStrategyClient(AILabClient):
|
|
11
11
|
|
|
12
12
|
def list_reasoning_strategies(
|
|
13
13
|
self,
|
|
@@ -56,7 +56,6 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
56
56
|
|
|
57
57
|
def create_reasoning_strategy(
|
|
58
58
|
self,
|
|
59
|
-
project_id: str,
|
|
60
59
|
name: str,
|
|
61
60
|
system_prompt: str,
|
|
62
61
|
access_scope: str = "public",
|
|
@@ -67,7 +66,6 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
67
66
|
"""
|
|
68
67
|
Creates a new reasoning strategy in the specified project.
|
|
69
68
|
|
|
70
|
-
:param project_id: str - Unique identifier of the project.
|
|
71
69
|
:param name: str - Name of the reasoning strategy.
|
|
72
70
|
:param system_prompt: str - System prompt for the strategy.
|
|
73
71
|
:param access_scope: str, optional - Access scope, "public" or "private" (default: "public").
|
|
@@ -83,7 +81,7 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
83
81
|
|
|
84
82
|
headers = {
|
|
85
83
|
"Authorization": self.api_service.token,
|
|
86
|
-
"ProjectId": project_id,
|
|
84
|
+
"ProjectId": self.project_id,
|
|
87
85
|
"Content-Type": "application/json",
|
|
88
86
|
"Accept": "application/json"
|
|
89
87
|
}
|
|
@@ -103,14 +101,13 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
103
101
|
try:
|
|
104
102
|
result = response.json()
|
|
105
103
|
except JSONDecodeError as e:
|
|
106
|
-
logger.error(f"Unable to create reasoning strategy for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
107
|
-
raise InvalidAPIResponseException(f"Unable to create reasoning strategy for project {project_id}: {response.text}")
|
|
104
|
+
logger.error(f"Unable to create reasoning strategy for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
105
|
+
raise InvalidAPIResponseException(f"Unable to create reasoning strategy for project {self.project_id}: {response.text}")
|
|
108
106
|
|
|
109
107
|
return result
|
|
110
108
|
|
|
111
109
|
def update_reasoning_strategy(
|
|
112
110
|
self,
|
|
113
|
-
project_id: str,
|
|
114
111
|
reasoning_strategy_id: str,
|
|
115
112
|
name: str = None,
|
|
116
113
|
system_prompt: str = None,
|
|
@@ -123,7 +120,6 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
123
120
|
"""
|
|
124
121
|
Updates or upserts a reasoning strategy in the specified project.
|
|
125
122
|
|
|
126
|
-
:param project_id: str - Unique identifier of the project.
|
|
127
123
|
:param reasoning_strategy_id: str - Unique identifier of the strategy.
|
|
128
124
|
:param name: str, optional - Updated strategy name.
|
|
129
125
|
:param system_prompt: str, optional - Updated system prompt.
|
|
@@ -169,7 +165,7 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
169
165
|
|
|
170
166
|
headers = {
|
|
171
167
|
"Authorization": self.api_service.token,
|
|
172
|
-
"ProjectId": project_id,
|
|
168
|
+
"ProjectId": self.project_id,
|
|
173
169
|
"Content-Type": "application/json",
|
|
174
170
|
"Accept": "application/json"
|
|
175
171
|
}
|
|
@@ -181,21 +177,19 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
181
177
|
try:
|
|
182
178
|
result = response.json()
|
|
183
179
|
except JSONDecodeError as e:
|
|
184
|
-
logger.error(f"Unable to update reasoning strategy {reasoning_strategy_id} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
185
|
-
raise InvalidAPIResponseException(f"Unable to update reasoning strategy {reasoning_strategy_id} in project {project_id}: {response.text}")
|
|
180
|
+
logger.error(f"Unable to update reasoning strategy {reasoning_strategy_id} in project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
181
|
+
raise InvalidAPIResponseException(f"Unable to update reasoning strategy {reasoning_strategy_id} in project {self.project_id}: {response.text}")
|
|
186
182
|
|
|
187
183
|
return result
|
|
188
184
|
|
|
189
185
|
def get_reasoning_strategy(
|
|
190
186
|
self,
|
|
191
|
-
project_id: str,
|
|
192
187
|
reasoning_strategy_id: str = None,
|
|
193
188
|
reasoning_strategy_name: str = None
|
|
194
189
|
):
|
|
195
190
|
"""
|
|
196
191
|
Retrieves a reasoning strategy by ID or name in the specified project.
|
|
197
192
|
|
|
198
|
-
:param project_id: str - Unique identifier of the project.
|
|
199
193
|
:param reasoning_strategy_id: str, optional - Unique identifier of the strategy.
|
|
200
194
|
:param reasoning_strategy_name: str, optional - Name of the strategy.
|
|
201
195
|
:return: dict - Strategy details.
|
|
@@ -210,7 +204,7 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
210
204
|
|
|
211
205
|
headers = {
|
|
212
206
|
"Authorization": self.api_service.token,
|
|
213
|
-
"ProjectId": project_id
|
|
207
|
+
"ProjectId": self.project_id
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
if reasoning_strategy_id:
|
|
@@ -225,8 +219,8 @@ class ReasoningStrategyClient(BaseClient):
|
|
|
225
219
|
try:
|
|
226
220
|
result = response.json()
|
|
227
221
|
except JSONDecodeError as e:
|
|
228
|
-
logger.error(f"Unable to retrieve reasoning strategy {reasoning_strategy_id or reasoning_strategy_name} for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
229
|
-
raise InvalidAPIResponseException(f"Unable to retrieve reasoning strategy {reasoning_strategy_id or reasoning_strategy_name} for project {project_id}: {response.text}")
|
|
222
|
+
logger.error(f"Unable to retrieve reasoning strategy {reasoning_strategy_id or reasoning_strategy_name} for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
223
|
+
raise InvalidAPIResponseException(f"Unable to retrieve reasoning strategy {reasoning_strategy_id or reasoning_strategy_name} for project {self.project_id}: {response.text}")
|
|
230
224
|
|
|
231
225
|
return result
|
|
232
226
|
|
pygeai/lab/tools/clients.py
CHANGED
|
@@ -2,18 +2,17 @@ import json
|
|
|
2
2
|
from json import JSONDecodeError
|
|
3
3
|
|
|
4
4
|
from pygeai import logger
|
|
5
|
-
from pygeai.core.base.clients import BaseClient
|
|
6
5
|
from pygeai.core.common.exceptions import InvalidAPIResponseException, MissingRequirementException
|
|
7
6
|
from pygeai.lab.constants import VALID_SCOPES, VALID_ACCESS_SCOPES, VALID_REPORT_EVENTS
|
|
8
7
|
from pygeai.lab.tools.endpoints import CREATE_TOOL_V2, LIST_TOOLS_V2, GET_TOOL_V2, UPDATE_TOOL_V2, UPSERT_TOOL_V2, \
|
|
9
8
|
PUBLISH_TOOL_REVISION_V2, GET_PARAMETER_V2, SET_PARAMETER_V2, DELETE_TOOL_V2, EXPORT_TOOL_V2
|
|
9
|
+
from pygeai.lab.clients import AILabClient
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class ToolClient(
|
|
12
|
+
class ToolClient(AILabClient):
|
|
13
13
|
|
|
14
14
|
def create_tool(
|
|
15
15
|
self,
|
|
16
|
-
project_id: str,
|
|
17
16
|
name: str,
|
|
18
17
|
description: str = None,
|
|
19
18
|
scope: str = None,
|
|
@@ -29,7 +28,6 @@ class ToolClient(BaseClient):
|
|
|
29
28
|
"""
|
|
30
29
|
Creates a new tool in the specified project.
|
|
31
30
|
|
|
32
|
-
:param project_id: str - Unique identifier of the project where the tool will be created.
|
|
33
31
|
:param name: str - Name of the tool. Must be non-empty, unique within the project, and exclude ':' or '/'.
|
|
34
32
|
:param description: str - Description of the tool's purpose, helping agents decide when to use it. Optional.
|
|
35
33
|
:param scope: str - Scope of the tool, either 'builtin', 'external', or 'api'. Optional.
|
|
@@ -108,7 +106,7 @@ class ToolClient(BaseClient):
|
|
|
108
106
|
"Accept": "application/json",
|
|
109
107
|
"Content-Type": "application/json",
|
|
110
108
|
"Authorization": self.api_service.token,
|
|
111
|
-
"ProjectId": project_id
|
|
109
|
+
"ProjectId": self.project_id
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
response = self.api_service.post(
|
|
@@ -120,14 +118,13 @@ class ToolClient(BaseClient):
|
|
|
120
118
|
try:
|
|
121
119
|
result = response.json()
|
|
122
120
|
except JSONDecodeError as e:
|
|
123
|
-
logger.error(f"Unable to create tool for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
124
|
-
raise InvalidAPIResponseException(f"Unable to create tool for project {project_id}: {response.text}")
|
|
121
|
+
logger.error(f"Unable to create tool for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
122
|
+
raise InvalidAPIResponseException(f"Unable to create tool for project {self.project_id}: {response.text}")
|
|
125
123
|
|
|
126
124
|
return result
|
|
127
125
|
|
|
128
126
|
def list_tools(
|
|
129
127
|
self,
|
|
130
|
-
project_id: str,
|
|
131
128
|
id: str = "",
|
|
132
129
|
count: str = "100",
|
|
133
130
|
access_scope: str = "public",
|
|
@@ -138,7 +135,6 @@ class ToolClient(BaseClient):
|
|
|
138
135
|
"""
|
|
139
136
|
Retrieves a list of tools associated with the specified project.
|
|
140
137
|
|
|
141
|
-
:param project_id: str - Unique identifier of the project.
|
|
142
138
|
:param id: str - ID of the tool to filter by. Defaults to "" (no filtering).
|
|
143
139
|
:param count: str - Number of tools to retrieve. Defaults to "100".
|
|
144
140
|
:param access_scope: str - Access scope of the tools, either "public" or "private". Defaults to "public".
|
|
@@ -150,13 +146,13 @@ class ToolClient(BaseClient):
|
|
|
150
146
|
endpoint = LIST_TOOLS_V2
|
|
151
147
|
headers = {
|
|
152
148
|
"Authorization": self.api_service.token,
|
|
153
|
-
"ProjectId": project_id
|
|
149
|
+
"ProjectId": self.project_id
|
|
154
150
|
}
|
|
155
151
|
|
|
156
152
|
if scope and scope not in VALID_SCOPES:
|
|
157
153
|
raise ValueError(f"Scope must be one of {', '.join(VALID_SCOPES)}.")
|
|
158
154
|
|
|
159
|
-
logger.debug(f"Listing tools available for the project with ID: {project_id}")
|
|
155
|
+
logger.debug(f"Listing tools available for the project with ID: {self.project_id}")
|
|
160
156
|
|
|
161
157
|
response = self.api_service.get(
|
|
162
158
|
endpoint=endpoint,
|
|
@@ -173,14 +169,13 @@ class ToolClient(BaseClient):
|
|
|
173
169
|
try:
|
|
174
170
|
result = response.json()
|
|
175
171
|
except JSONDecodeError as e:
|
|
176
|
-
logger.error(f"Unable to list tools for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
177
|
-
raise InvalidAPIResponseException(f"Unable to list tools for project {project_id}: {response.text}")
|
|
172
|
+
logger.error(f"Unable to list tools for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
173
|
+
raise InvalidAPIResponseException(f"Unable to list tools for project {self.project_id}: {response.text}")
|
|
178
174
|
|
|
179
175
|
return result
|
|
180
176
|
|
|
181
177
|
def get_tool(
|
|
182
178
|
self,
|
|
183
|
-
project_id: str,
|
|
184
179
|
tool_id: str,
|
|
185
180
|
revision: str = 0,
|
|
186
181
|
version: int = 0,
|
|
@@ -189,7 +184,6 @@ class ToolClient(BaseClient):
|
|
|
189
184
|
"""
|
|
190
185
|
Retrieves details of a specific tool from the specified project.
|
|
191
186
|
|
|
192
|
-
:param project_id: str - Unique identifier of the project.
|
|
193
187
|
:param tool_id: str - Unique identifier of the tool to retrieve.
|
|
194
188
|
:param revision: str - Revision of the tool to retrieve. Defaults to 0 (latest revision).
|
|
195
189
|
:param version: int - Version of the tool to retrieve. Defaults to 0 (latest version).
|
|
@@ -199,7 +193,7 @@ class ToolClient(BaseClient):
|
|
|
199
193
|
endpoint = GET_TOOL_V2.format(toolId=tool_id)
|
|
200
194
|
headers = {
|
|
201
195
|
"Authorization": self.api_service.token,
|
|
202
|
-
"ProjectId": project_id
|
|
196
|
+
"ProjectId": self.project_id
|
|
203
197
|
}
|
|
204
198
|
|
|
205
199
|
logger.debug(f"Retrieving detail of tool with ID: {tool_id}")
|
|
@@ -216,21 +210,19 @@ class ToolClient(BaseClient):
|
|
|
216
210
|
try:
|
|
217
211
|
result = response.json()
|
|
218
212
|
except JSONDecodeError as e:
|
|
219
|
-
logger.error(f"Unable to retrieve tool {tool_id} for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
220
|
-
raise InvalidAPIResponseException(f"Unable to retrieve tool {tool_id} for project {project_id}: {response.text}")
|
|
213
|
+
logger.error(f"Unable to retrieve tool {tool_id} for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
214
|
+
raise InvalidAPIResponseException(f"Unable to retrieve tool {tool_id} for project {self.project_id}: {response.text}")
|
|
221
215
|
|
|
222
216
|
return result
|
|
223
217
|
|
|
224
218
|
def delete_tool(
|
|
225
219
|
self,
|
|
226
|
-
project_id: str,
|
|
227
220
|
tool_id: str = None,
|
|
228
221
|
tool_name: str = None
|
|
229
222
|
) -> dict | str:
|
|
230
223
|
"""
|
|
231
224
|
Deletes a specific tool from the specified project.
|
|
232
225
|
|
|
233
|
-
:param project_id: str - Unique identifier of the project.
|
|
234
226
|
:param tool_id: str, optional - Unique identifier of the tool to delete. Defaults to None.
|
|
235
227
|
:param tool_name: str, optional - Name of the tool to delete. Defaults to None.
|
|
236
228
|
:return: dict or str - JSON response containing the result of the delete operation if successful,
|
|
@@ -243,7 +235,7 @@ class ToolClient(BaseClient):
|
|
|
243
235
|
endpoint = DELETE_TOOL_V2.format(toolId=tool_id if tool_id else tool_name)
|
|
244
236
|
headers = {
|
|
245
237
|
"Authorization": self.api_service.token,
|
|
246
|
-
"ProjectId": project_id
|
|
238
|
+
"ProjectId": self.project_id
|
|
247
239
|
}
|
|
248
240
|
|
|
249
241
|
if tool_id:
|
|
@@ -257,14 +249,13 @@ class ToolClient(BaseClient):
|
|
|
257
249
|
)
|
|
258
250
|
|
|
259
251
|
if response.status_code != 204:
|
|
260
|
-
logger.error(f"Unable to delete tool {tool_id or tool_name} from project {project_id}: JSON parsing error (status {response.status_code}). Response: {response.text}")
|
|
261
|
-
raise InvalidAPIResponseException(f"Unable to delete tool {tool_id or tool_name} from project {project_id}: {response.text}")
|
|
252
|
+
logger.error(f"Unable to delete tool {tool_id or tool_name} from project {self.project_id}: JSON parsing error (status {response.status_code}). Response: {response.text}")
|
|
253
|
+
raise InvalidAPIResponseException(f"Unable to delete tool {tool_id or tool_name} from project {self.project_id}: {response.text}")
|
|
262
254
|
else:
|
|
263
255
|
return {}
|
|
264
256
|
|
|
265
257
|
def update_tool(
|
|
266
258
|
self,
|
|
267
|
-
project_id: str,
|
|
268
259
|
tool_id: str,
|
|
269
260
|
name: str = None,
|
|
270
261
|
description: str = None,
|
|
@@ -282,7 +273,6 @@ class ToolClient(BaseClient):
|
|
|
282
273
|
"""
|
|
283
274
|
Updates an existing tool in the specified project or upserts it if specified.
|
|
284
275
|
|
|
285
|
-
:param project_id: str - Unique identifier of the project containing the tool.
|
|
286
276
|
:param tool_id: str - Unique identifier of the tool to update. Required for update operations.
|
|
287
277
|
:param name: str - Updated name of the tool. Must be non-empty, unique within the project, and exclude ':' or '/' if provided. Optional.
|
|
288
278
|
:param description: str - Updated description of the tool's purpose, helping agents decide when to use it. Optional.
|
|
@@ -365,7 +355,7 @@ class ToolClient(BaseClient):
|
|
|
365
355
|
|
|
366
356
|
headers = {
|
|
367
357
|
"Authorization": self.api_service.token,
|
|
368
|
-
"ProjectId": project_id
|
|
358
|
+
"ProjectId": self.project_id
|
|
369
359
|
}
|
|
370
360
|
response = self.api_service.put(
|
|
371
361
|
endpoint=endpoint,
|
|
@@ -376,21 +366,19 @@ class ToolClient(BaseClient):
|
|
|
376
366
|
try:
|
|
377
367
|
result = response.json()
|
|
378
368
|
except JSONDecodeError as e:
|
|
379
|
-
logger.error(f"Unable to update tool {tool_id} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
380
|
-
raise InvalidAPIResponseException(f"Unable to update tool {tool_id} in project {project_id}: {response.text}")
|
|
369
|
+
logger.error(f"Unable to update tool {tool_id} in project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
370
|
+
raise InvalidAPIResponseException(f"Unable to update tool {tool_id} in project {self.project_id}: {response.text}")
|
|
381
371
|
|
|
382
372
|
return result
|
|
383
373
|
|
|
384
374
|
def publish_tool_revision(
|
|
385
375
|
self,
|
|
386
|
-
project_id: str,
|
|
387
376
|
tool_id: str,
|
|
388
377
|
revision: str
|
|
389
378
|
):
|
|
390
379
|
"""
|
|
391
380
|
Publishes a specific revision of a tool in the specified project.
|
|
392
381
|
|
|
393
|
-
:param project_id: str - Unique identifier of the project.
|
|
394
382
|
:param tool_id: str - Unique identifier of the tool to publish.
|
|
395
383
|
:param revision: str - Revision of the tool to publish.
|
|
396
384
|
:return: dict or str - JSON response containing the result of the publish operation if successful, otherwise the raw response text.
|
|
@@ -398,7 +386,7 @@ class ToolClient(BaseClient):
|
|
|
398
386
|
endpoint = PUBLISH_TOOL_REVISION_V2.format(toolId=tool_id)
|
|
399
387
|
headers = {
|
|
400
388
|
"Authorization": self.api_service.token,
|
|
401
|
-
"ProjectId": project_id
|
|
389
|
+
"ProjectId": self.project_id
|
|
402
390
|
}
|
|
403
391
|
|
|
404
392
|
logger.debug(f"Publishing revision {revision} for tool with ID {tool_id}")
|
|
@@ -413,14 +401,13 @@ class ToolClient(BaseClient):
|
|
|
413
401
|
try:
|
|
414
402
|
result = response.json()
|
|
415
403
|
except JSONDecodeError as e:
|
|
416
|
-
logger.error(f"Unable to publish revision {revision} for tool {tool_id} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
417
|
-
raise InvalidAPIResponseException(f"Unable to publish revision {revision} for tool {tool_id} in project {project_id}: {response.text}")
|
|
404
|
+
logger.error(f"Unable to publish revision {revision} for tool {tool_id} in project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
405
|
+
raise InvalidAPIResponseException(f"Unable to publish revision {revision} for tool {tool_id} in project {self.project_id}: {response.text}")
|
|
418
406
|
|
|
419
407
|
return result
|
|
420
408
|
|
|
421
409
|
def get_parameter(
|
|
422
410
|
self,
|
|
423
|
-
project_id: str,
|
|
424
411
|
tool_id: str = None,
|
|
425
412
|
tool_public_name: str = None,
|
|
426
413
|
revision: str = 0,
|
|
@@ -430,7 +417,6 @@ class ToolClient(BaseClient):
|
|
|
430
417
|
"""
|
|
431
418
|
Retrieves details of parameters for a specific tool identified by either its ID or public name in the specified project.
|
|
432
419
|
|
|
433
|
-
:param project_id: str - Unique identifier of the project.
|
|
434
420
|
:param tool_id: str, optional - Unique identifier of the tool whose parameters are to be retrieved. Defaults to None.
|
|
435
421
|
:param tool_public_name: str, optional - Public name of the tool whose parameters are to be retrieved. Defaults to None.
|
|
436
422
|
:param revision: str - Revision of the parameters to retrieve. Defaults to "0" (latest revision).
|
|
@@ -450,7 +436,7 @@ class ToolClient(BaseClient):
|
|
|
450
436
|
endpoint = GET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else GET_PARAMETER_V2.format(toolPublicName=tool_id)
|
|
451
437
|
headers = {
|
|
452
438
|
"Authorization": self.api_service.token,
|
|
453
|
-
"ProjectId": project_id
|
|
439
|
+
"ProjectId": self.project_id
|
|
454
440
|
}
|
|
455
441
|
|
|
456
442
|
response = self.api_service.get(
|
|
@@ -465,14 +451,13 @@ class ToolClient(BaseClient):
|
|
|
465
451
|
try:
|
|
466
452
|
result = response.json()
|
|
467
453
|
except JSONDecodeError as e:
|
|
468
|
-
logger.error(f"Unable to retrieve parameters for tool {tool_id or tool_public_name} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
469
|
-
raise InvalidAPIResponseException(f"Unable to retrieve parameters for tool {tool_id or tool_public_name} in project {project_id}: {response.text}")
|
|
454
|
+
logger.error(f"Unable to retrieve parameters for tool {tool_id or tool_public_name} in project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
455
|
+
raise InvalidAPIResponseException(f"Unable to retrieve parameters for tool {tool_id or tool_public_name} in project {self.project_id}: {response.text}")
|
|
470
456
|
|
|
471
457
|
return result
|
|
472
458
|
|
|
473
459
|
def set_parameter(
|
|
474
460
|
self,
|
|
475
|
-
project_id: str,
|
|
476
461
|
tool_id: str = None,
|
|
477
462
|
tool_public_name: str = None,
|
|
478
463
|
parameters: list = None
|
|
@@ -480,7 +465,6 @@ class ToolClient(BaseClient):
|
|
|
480
465
|
"""
|
|
481
466
|
Sets or updates parameters for a specific tool identified by either its ID or public name in the specified project.
|
|
482
467
|
|
|
483
|
-
:param project_id: str - Unique identifier of the project.
|
|
484
468
|
:param tool_id: str, optional - Unique identifier of the tool whose parameters are to be set. Defaults to None.
|
|
485
469
|
:param tool_public_name: str, optional - Public name of the tool whose parameters are to be set. Defaults to None.
|
|
486
470
|
:param parameters: list - List of parameter dictionaries defining the tool's parameters.
|
|
@@ -497,7 +481,7 @@ class ToolClient(BaseClient):
|
|
|
497
481
|
endpoint = SET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else SET_PARAMETER_V2.format(toolPublicName=tool_id)
|
|
498
482
|
headers = {
|
|
499
483
|
"Authorization": self.api_service.token,
|
|
500
|
-
"ProjectId": project_id,
|
|
484
|
+
"ProjectId": self.project_id,
|
|
501
485
|
"Content-Type": "application/json",
|
|
502
486
|
"Accept": "application/json"
|
|
503
487
|
}
|
|
@@ -521,27 +505,23 @@ class ToolClient(BaseClient):
|
|
|
521
505
|
try:
|
|
522
506
|
result = response.json()
|
|
523
507
|
except JSONDecodeError as e:
|
|
524
|
-
logger.error(f"Unable to set parameters for tool {tool_id or tool_public_name} in project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
525
|
-
raise InvalidAPIResponseException(f"Unable to set parameters for tool {tool_id or tool_public_name} in project {project_id}: {response.text}")
|
|
508
|
+
logger.error(f"Unable to set parameters for tool {tool_id or tool_public_name} in project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
509
|
+
raise InvalidAPIResponseException(f"Unable to set parameters for tool {tool_id or tool_public_name} in project {self.project_id}: {response.text}")
|
|
526
510
|
|
|
527
511
|
return result
|
|
528
512
|
|
|
529
513
|
def export_tool(
|
|
530
514
|
self,
|
|
531
|
-
project_id: str,
|
|
532
515
|
tool_id: str,
|
|
533
516
|
) -> dict:
|
|
534
517
|
"""
|
|
535
518
|
Retrieves details of a specific tool from the specified project.
|
|
536
519
|
|
|
537
|
-
:param project_id: str - Unique identifier of the project containing the tool.
|
|
538
520
|
:param tool_id: str - Unique identifier of the tool to retrieve.
|
|
539
521
|
:return: dict - JSON response containing the tool details.
|
|
540
522
|
:raises InvalidAPIResponseException: If the response cannot be parsed as JSON or an error occurs.
|
|
541
523
|
:raises MissingRequirementException: If project_id or tool_id is not provided.
|
|
542
524
|
"""
|
|
543
|
-
if not project_id:
|
|
544
|
-
raise MissingRequirementException("Cannot retrieve tool without specifying project_id")
|
|
545
525
|
|
|
546
526
|
if not tool_id:
|
|
547
527
|
raise MissingRequirementException("tool_id must be specified in order to retrieve the tool")
|
|
@@ -549,7 +529,7 @@ class ToolClient(BaseClient):
|
|
|
549
529
|
endpoint = EXPORT_TOOL_V2.format(toolId=tool_id)
|
|
550
530
|
headers = {
|
|
551
531
|
"Authorization": self.api_service.token,
|
|
552
|
-
"ProjectId": project_id
|
|
532
|
+
"ProjectId": self.project_id
|
|
553
533
|
}
|
|
554
534
|
|
|
555
535
|
logger.debug(f"Exporting tool with ID {tool_id}")
|
|
@@ -561,7 +541,7 @@ class ToolClient(BaseClient):
|
|
|
561
541
|
try:
|
|
562
542
|
result = response.json()
|
|
563
543
|
except JSONDecodeError as e:
|
|
564
|
-
logger.error(f"Unable to export tool {tool_id} for project {project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
565
|
-
raise InvalidAPIResponseException(f"Unable to export tool {tool_id} for project {project_id}: {response.text}")
|
|
544
|
+
logger.error(f"Unable to export tool {tool_id} for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
|
|
545
|
+
raise InvalidAPIResponseException(f"Unable to export tool {tool_id} for project {self.project_id}: {response.text}")
|
|
566
546
|
|
|
567
547
|
return result
|
pygeai/lab/tools/mappers.py
CHANGED
|
@@ -37,8 +37,8 @@ class ToolMapper:
|
|
|
37
37
|
"""
|
|
38
38
|
return [
|
|
39
39
|
ToolMessage(
|
|
40
|
-
description=msg
|
|
41
|
-
type=msg
|
|
40
|
+
description=msg.get("description"),
|
|
41
|
+
type=msg.get("type")
|
|
42
42
|
)
|
|
43
43
|
for msg in messages_data
|
|
44
44
|
]
|
|
@@ -55,9 +55,9 @@ class ToolMapper:
|
|
|
55
55
|
"""
|
|
56
56
|
tool_data = data.get("tool", data)
|
|
57
57
|
|
|
58
|
-
name = tool_data
|
|
59
|
-
description = tool_data
|
|
60
|
-
scope = tool_data
|
|
58
|
+
name = tool_data.get("name")
|
|
59
|
+
description = tool_data.get("description")
|
|
60
|
+
scope = tool_data.get("scope")
|
|
61
61
|
parameter_data = tool_data.get("parameters")
|
|
62
62
|
parameters = cls._map_parameters(parameter_data) if parameter_data else None
|
|
63
63
|
|
|
File without changes
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
from unittest import TestCase
|
|
2
|
+
from pygeai.chat.clients import ChatClient
|
|
3
|
+
|
|
4
|
+
chat_client: ChatClient
|
|
5
|
+
|
|
6
|
+
class TestChatGenerateImageIntegration(TestCase):
|
|
7
|
+
|
|
8
|
+
def setUp(self):
|
|
9
|
+
self.chat_client = ChatClient(alias="beta")
|
|
10
|
+
self.new_image = self.__load_image()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def __load_image(self):
|
|
14
|
+
return {
|
|
15
|
+
"model": "openai/gpt-image-1",
|
|
16
|
+
"prompt": "generate an image of a futuristic city skyline at sunset",
|
|
17
|
+
"n": 1,
|
|
18
|
+
"quality": "high",
|
|
19
|
+
"size": "1024x1536"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __generate_image(self, image = None):
|
|
24
|
+
image = image if image is not None else self.new_image
|
|
25
|
+
return self.chat_client.generate_image(
|
|
26
|
+
model=image["model"],
|
|
27
|
+
prompt=image["prompt"],
|
|
28
|
+
n=image["n"],
|
|
29
|
+
quality=image["quality"],
|
|
30
|
+
size=image["size"],
|
|
31
|
+
aspect_ratio= image["aspect_ratio"] if "aspect_ratio" in image else None
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_generate_image(self):
|
|
36
|
+
created_image = self.__generate_image()
|
|
37
|
+
self.assertEqual(len(created_image["data"]), 1, "Expected an image to be generated")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_generate_image_invalid_model(self):
|
|
41
|
+
self.new_image["model"] = "openai/gpt-image-10",
|
|
42
|
+
created_image = self.__generate_image()
|
|
43
|
+
|
|
44
|
+
self.assertEqual(
|
|
45
|
+
created_image["error"]["code"], 400,
|
|
46
|
+
"Expected a 400 code for invalid model"
|
|
47
|
+
)
|
|
48
|
+
self.assertEqual(
|
|
49
|
+
created_image["error"]["message"],
|
|
50
|
+
'Provider \'["openai\' does not exists.',
|
|
51
|
+
"Expected an error message when model does not exists"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_generate_image_no_model(self):
|
|
56
|
+
self.new_image["model"] = ""
|
|
57
|
+
created_image = self.__generate_image()
|
|
58
|
+
|
|
59
|
+
self.assertEqual(
|
|
60
|
+
created_image["error"]["code"], 400,
|
|
61
|
+
"Expected a 400 code for no model"
|
|
62
|
+
)
|
|
63
|
+
self.assertEqual(
|
|
64
|
+
created_image["error"]["message"],
|
|
65
|
+
"Invalid 'model' name. Must follow pattern {provider}/{modelName}",
|
|
66
|
+
"Expected an error message when no model is provided"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_generate_image_no_prompt(self):
|
|
71
|
+
self.new_image["prompt"] = ""
|
|
72
|
+
created_image = self.__generate_image()
|
|
73
|
+
|
|
74
|
+
self.assertEqual(
|
|
75
|
+
created_image["error"]["type"],
|
|
76
|
+
"invalid_request_error",
|
|
77
|
+
"Expected a 400 code for no model"
|
|
78
|
+
)
|
|
79
|
+
self.assertEqual(
|
|
80
|
+
created_image["error"]["param"], "prompt",
|
|
81
|
+
"Expected an error message when no model is provided"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_generate_image_specific_n(self):
|
|
86
|
+
self.new_image["n"] = 2
|
|
87
|
+
|
|
88
|
+
created_image = self.__generate_image()
|
|
89
|
+
self.assertEqual(len(created_image["data"]), 2, "Expected two images to be generated")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def test_generate_image_no_n(self):
|
|
93
|
+
self.new_image["n"] = None # default is 1
|
|
94
|
+
|
|
95
|
+
created_image = self.__generate_image()
|
|
96
|
+
self.assertEqual(len(created_image["data"]), 1, "Expected an image to be generated")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_generate_image_no_supported_n(self):
|
|
100
|
+
self.new_image["model"] = "openai/dall-e-3"
|
|
101
|
+
self.new_image["n"] = 5
|
|
102
|
+
|
|
103
|
+
created_image = self.__generate_image()
|
|
104
|
+
self.assertIn(
|
|
105
|
+
"Invalid 'n': integer above maximum value",
|
|
106
|
+
created_image["error"]["message"],
|
|
107
|
+
"Expected an error message when n is not supported by the model"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def test_generate_image_no_quality(self):
|
|
112
|
+
self.new_image["quality"] = ""
|
|
113
|
+
|
|
114
|
+
created_image = self.__generate_image()
|
|
115
|
+
self.assertIn(
|
|
116
|
+
"Invalid value: ''. Supported values are: 'low', 'medium', 'high', and 'auto'",
|
|
117
|
+
created_image["error"]["message"],
|
|
118
|
+
"Expected an error message when quality is not provided"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def test_generate_image_no_supported_quality(self):
|
|
123
|
+
self.new_image["model"] = "openai/dall-e-3"
|
|
124
|
+
|
|
125
|
+
created_image = self.__generate_image()
|
|
126
|
+
self.assertIn(
|
|
127
|
+
"Invalid value: 'high'. Supported values are: 'standard' and 'hd'",
|
|
128
|
+
created_image["error"]["message"],
|
|
129
|
+
"Expected an error message when quality is not supported by the model"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_generate_image_no_size(self):
|
|
134
|
+
self.new_image["size"] = ""
|
|
135
|
+
|
|
136
|
+
created_image = self.__generate_image()
|
|
137
|
+
self.assertIn(
|
|
138
|
+
"Invalid value: ''. Supported values are: '1024x1024', '1024x1536', '1536x1024', and 'auto'",
|
|
139
|
+
created_image["error"]["message"],
|
|
140
|
+
"Expected an error message when no size is provided"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_generate_image_no_supported_size(self):
|
|
145
|
+
self.new_image["size"] = 1024
|
|
146
|
+
self.new_image["quality"] = None
|
|
147
|
+
|
|
148
|
+
created_image = self.__generate_image()
|
|
149
|
+
self.assertIn(
|
|
150
|
+
"Invalid type for 'size': expected one of '1024x1024', '1024x1536', '1536x1024', or 'auto', but got an integer instead",
|
|
151
|
+
created_image["error"]["message"],
|
|
152
|
+
"Expected an error message when no size is provided"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_generate_image_with_aspect_ratio(self):
|
|
157
|
+
self.new_image["model"] = "vertex_ai/imagen-3.0-generate-001"
|
|
158
|
+
self.new_image["aspect_ratio"] = "4:3"
|
|
159
|
+
self.new_image["quality"] = None
|
|
160
|
+
|
|
161
|
+
created_image = self.__generate_image()
|
|
162
|
+
self.assertEqual(len(created_image["data"]), 1, "Expected an image to be generated")
|