pygeai 0.4.0b3__py3-none-any.whl → 0.5.0__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.
Files changed (61) hide show
  1. pygeai/__init__.py +1 -1
  2. pygeai/assistant/rag/models.py +1 -1
  3. pygeai/chat/ui.py +0 -1
  4. pygeai/cli/__init__.py +1 -1
  5. pygeai/cli/commands/chat.py +54 -56
  6. pygeai/cli/commands/lab/ai_lab.py +129 -466
  7. pygeai/cli/commands/lab/options.py +8 -0
  8. pygeai/cli/commands/lab/utils.py +13 -0
  9. pygeai/cli/geai.py +5 -2
  10. pygeai/cli/texts/help.py +12 -0
  11. pygeai/core/base/session.py +1 -1
  12. pygeai/core/common/config.py +0 -2
  13. pygeai/core/common/exceptions.py +6 -0
  14. pygeai/lab/agents/clients.py +30 -61
  15. pygeai/lab/clients.py +20 -0
  16. pygeai/lab/managers.py +6 -58
  17. pygeai/lab/models.py +1 -1
  18. pygeai/lab/processes/clients.py +81 -129
  19. pygeai/lab/processes/mappers.py +2 -2
  20. pygeai/lab/strategies/clients.py +11 -17
  21. pygeai/lab/tools/clients.py +59 -59
  22. pygeai/lab/tools/mappers.py +5 -5
  23. pygeai/tests/cli/docker/__init__.py +0 -0
  24. pygeai/tests/integration/assistants/__init__.py +0 -0
  25. pygeai/tests/integration/assistants/rag/__init__.py +0 -0
  26. pygeai/tests/integration/assistants/rag/test_create_rag.py +91 -0
  27. pygeai/tests/integration/chat/__init__.py +0 -0
  28. pygeai/tests/integration/chat/test_generate_image.py +158 -0
  29. pygeai/tests/integration/lab/agents/test_create_agent.py +21 -19
  30. pygeai/tests/integration/lab/agents/test_create_sharing_link.py +4 -1
  31. pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +0 -1
  32. pygeai/tests/integration/lab/agents/test_update_agent.py +19 -31
  33. pygeai/tests/integration/lab/processes/__init__.py +0 -0
  34. pygeai/tests/integration/lab/processes/test_create_process.py +345 -0
  35. pygeai/tests/integration/lab/processes/test_get_process.py +201 -0
  36. pygeai/tests/integration/lab/processes/test_update_process.py +289 -0
  37. pygeai/tests/integration/lab/reasoning_strategies/__init__.py +0 -0
  38. pygeai/tests/integration/lab/reasoning_strategies/test_get_reasoning_strategy.py +70 -0
  39. pygeai/tests/integration/lab/reasoning_strategies/test_list_reasoning_strategies.py +93 -0
  40. pygeai/tests/integration/lab/reasoning_strategies/test_update_reasoning_strategy.py +149 -0
  41. pygeai/tests/integration/lab/tools/test_create_tool.py +14 -20
  42. pygeai/tests/integration/lab/tools/test_delete_tool.py +3 -3
  43. pygeai/tests/integration/lab/tools/test_get_parameter.py +98 -0
  44. pygeai/tests/integration/lab/tools/test_get_tool.py +3 -3
  45. pygeai/tests/integration/lab/tools/test_list_tools.py +106 -0
  46. pygeai/tests/integration/lab/tools/test_publish_tool_revision.py +119 -0
  47. pygeai/tests/integration/lab/tools/test_set_parameter.py +114 -0
  48. pygeai/tests/integration/lab/tools/test_update_tool.py +267 -0
  49. pygeai/tests/snippets/lab/agentic_flow_example_4.py +23 -23
  50. pygeai/tests/snippets/lab/agents/get_sharing_link.py +1 -2
  51. pygeai/tests/snippets/lab/samples/summarize_files.py +3 -3
  52. pygeai/tests/snippets/lab/tools/create_tool.py +1 -1
  53. pygeai/tests/snippets/lab/use_cases/file_summarizer_example.py +3 -3
  54. pygeai/tests/snippets/lab/use_cases/file_summarizer_example_2.py +11 -11
  55. pygeai/tests/snippets/lab/use_cases/update_web_reader.py +1 -2
  56. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/METADATA +47 -19
  57. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/RECORD +61 -39
  58. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/WHEEL +0 -0
  59. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/entry_points.txt +0 -0
  60. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/licenses/LICENSE +0 -0
  61. {pygeai-0.4.0b3.dist-info → pygeai-0.5.0.dist-info}/top_level.txt +0 -0
@@ -110,8 +110,8 @@ class AgenticProcessMapper:
110
110
  """
111
111
  return [
112
112
  Variable(
113
- key=var["key"],
114
- value=var["value"]
113
+ key=var.get("key"),
114
+ value=var.get("value")
115
115
  )
116
116
  for var in data
117
117
  ]
@@ -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(BaseClient):
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
 
@@ -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
- from pygeai.core.common.exceptions import InvalidAPIResponseException, MissingRequirementException
5
+ from pygeai.core.common.exceptions import InvalidAPIResponseException, MissingRequirementException, APIResponseError
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(BaseClient):
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(
@@ -116,18 +114,20 @@ class ToolClient(BaseClient):
116
114
  headers=headers,
117
115
  data=data
118
116
  )
119
-
117
+
118
+ if response.status_code >= 300:
119
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
120
+ raise APIResponseError(f"API returned an error: {response.text}")
120
121
  try:
121
122
  result = response.json()
122
123
  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}")
124
+ logger.error(f"Unable to create tool for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
125
+ raise InvalidAPIResponseException(f"Unable to create tool for project {self.project_id}: {response.text}")
125
126
 
126
127
  return result
127
128
 
128
129
  def list_tools(
129
130
  self,
130
- project_id: str,
131
131
  id: str = "",
132
132
  count: str = "100",
133
133
  access_scope: str = "public",
@@ -138,7 +138,6 @@ class ToolClient(BaseClient):
138
138
  """
139
139
  Retrieves a list of tools associated with the specified project.
140
140
 
141
- :param project_id: str - Unique identifier of the project.
142
141
  :param id: str - ID of the tool to filter by. Defaults to "" (no filtering).
143
142
  :param count: str - Number of tools to retrieve. Defaults to "100".
144
143
  :param access_scope: str - Access scope of the tools, either "public" or "private". Defaults to "public".
@@ -150,13 +149,13 @@ class ToolClient(BaseClient):
150
149
  endpoint = LIST_TOOLS_V2
151
150
  headers = {
152
151
  "Authorization": self.api_service.token,
153
- "ProjectId": project_id
152
+ "ProjectId": self.project_id
154
153
  }
155
154
 
156
155
  if scope and scope not in VALID_SCOPES:
157
156
  raise ValueError(f"Scope must be one of {', '.join(VALID_SCOPES)}.")
158
157
 
159
- logger.debug(f"Listing tools available for the project with ID: {project_id}")
158
+ logger.debug(f"Listing tools available for the project with ID: {self.project_id}")
160
159
 
161
160
  response = self.api_service.get(
162
161
  endpoint=endpoint,
@@ -170,17 +169,19 @@ class ToolClient(BaseClient):
170
169
  "allowExternal": allow_external
171
170
  }
172
171
  )
172
+ if response.status_code >= 300:
173
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
174
+ raise APIResponseError(f"API returned an error: {response.text}")
173
175
  try:
174
176
  result = response.json()
175
177
  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}")
178
+ logger.error(f"Unable to list tools for project {self.project_id}: JSON parsing error (status {response.status_code}): {e}. Response: {response.text}")
179
+ raise InvalidAPIResponseException(f"Unable to list tools for project {self.project_id}: {response.text}")
178
180
 
179
181
  return result
180
182
 
181
183
  def get_tool(
182
184
  self,
183
- project_id: str,
184
185
  tool_id: str,
185
186
  revision: str = 0,
186
187
  version: int = 0,
@@ -189,7 +190,6 @@ class ToolClient(BaseClient):
189
190
  """
190
191
  Retrieves details of a specific tool from the specified project.
191
192
 
192
- :param project_id: str - Unique identifier of the project.
193
193
  :param tool_id: str - Unique identifier of the tool to retrieve.
194
194
  :param revision: str - Revision of the tool to retrieve. Defaults to 0 (latest revision).
195
195
  :param version: int - Version of the tool to retrieve. Defaults to 0 (latest version).
@@ -199,7 +199,7 @@ class ToolClient(BaseClient):
199
199
  endpoint = GET_TOOL_V2.format(toolId=tool_id)
200
200
  headers = {
201
201
  "Authorization": self.api_service.token,
202
- "ProjectId": project_id
202
+ "ProjectId": self.project_id
203
203
  }
204
204
 
205
205
  logger.debug(f"Retrieving detail of tool with ID: {tool_id}")
@@ -213,24 +213,25 @@ class ToolClient(BaseClient):
213
213
  "allowDrafts": allow_drafts,
214
214
  }
215
215
  )
216
+ if response.status_code >= 300:
217
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
218
+ raise APIResponseError(f"API returned an error: {response.text}")
216
219
  try:
217
220
  result = response.json()
218
221
  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}")
222
+ 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}")
223
+ raise InvalidAPIResponseException(f"Unable to retrieve tool {tool_id} for project {self.project_id}: {response.text}")
221
224
 
222
225
  return result
223
226
 
224
227
  def delete_tool(
225
228
  self,
226
- project_id: str,
227
229
  tool_id: str = None,
228
230
  tool_name: str = None
229
231
  ) -> dict | str:
230
232
  """
231
233
  Deletes a specific tool from the specified project.
232
234
 
233
- :param project_id: str - Unique identifier of the project.
234
235
  :param tool_id: str, optional - Unique identifier of the tool to delete. Defaults to None.
235
236
  :param tool_name: str, optional - Name of the tool to delete. Defaults to None.
236
237
  :return: dict or str - JSON response containing the result of the delete operation if successful,
@@ -243,7 +244,7 @@ class ToolClient(BaseClient):
243
244
  endpoint = DELETE_TOOL_V2.format(toolId=tool_id if tool_id else tool_name)
244
245
  headers = {
245
246
  "Authorization": self.api_service.token,
246
- "ProjectId": project_id
247
+ "ProjectId": self.project_id
247
248
  }
248
249
 
249
250
  if tool_id:
@@ -255,17 +256,19 @@ class ToolClient(BaseClient):
255
256
  endpoint=endpoint,
256
257
  headers=headers
257
258
  )
259
+ if response.status_code >= 300:
260
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
261
+ raise APIResponseError(f"API returned an error: {response.text}")
258
262
 
259
263
  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}")
264
+ 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}")
265
+ raise InvalidAPIResponseException(f"Unable to delete tool {tool_id or tool_name} from project {self.project_id}: {response.text}")
262
266
  else:
263
267
  return {}
264
268
 
265
269
  def update_tool(
266
270
  self,
267
- project_id: str,
268
- tool_id: str,
271
+ tool_id: str = None,
269
272
  name: str = None,
270
273
  description: str = None,
271
274
  scope: str = None,
@@ -282,7 +285,6 @@ class ToolClient(BaseClient):
282
285
  """
283
286
  Updates an existing tool in the specified project or upserts it if specified.
284
287
 
285
- :param project_id: str - Unique identifier of the project containing the tool.
286
288
  :param tool_id: str - Unique identifier of the tool to update. Required for update operations.
287
289
  :param name: str - Updated name of the tool. Must be non-empty, unique within the project, and exclude ':' or '/' if provided. Optional.
288
290
  :param description: str - Updated description of the tool's purpose, helping agents decide when to use it. Optional.
@@ -323,6 +325,8 @@ class ToolClient(BaseClient):
323
325
  :raises JSONDecodeError: Caught internally if the response cannot be parsed as JSON; returns raw response text.
324
326
  :raises Exception: May be raised by `api_service.put` for network issues, authentication errors, or server-side problems (not caught here).
325
327
  """
328
+ if not (tool_id or name):
329
+ raise ValueError(f"Either tool ID or tool Name must be defined in order to update tool.")
326
330
  if scope and scope not in VALID_SCOPES:
327
331
  raise ValueError(f"Scope must be one of {', '.join(VALID_SCOPES)}.")
328
332
  if access_scope and access_scope not in VALID_ACCESS_SCOPES:
@@ -365,32 +369,32 @@ class ToolClient(BaseClient):
365
369
 
366
370
  headers = {
367
371
  "Authorization": self.api_service.token,
368
- "ProjectId": project_id
372
+ "ProjectId": self.project_id
369
373
  }
370
374
  response = self.api_service.put(
371
375
  endpoint=endpoint,
372
376
  headers=headers,
373
377
  data=data
374
378
  )
375
-
379
+ if response.status_code >= 300:
380
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
381
+ raise APIResponseError(f"API returned an error: {response.text}")
376
382
  try:
377
383
  result = response.json()
378
384
  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}")
385
+ 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}")
386
+ raise InvalidAPIResponseException(f"Unable to update tool {tool_id} in project {self.project_id}: {response.text}")
381
387
 
382
388
  return result
383
389
 
384
390
  def publish_tool_revision(
385
391
  self,
386
- project_id: str,
387
392
  tool_id: str,
388
393
  revision: str
389
394
  ):
390
395
  """
391
396
  Publishes a specific revision of a tool in the specified project.
392
397
 
393
- :param project_id: str - Unique identifier of the project.
394
398
  :param tool_id: str - Unique identifier of the tool to publish.
395
399
  :param revision: str - Revision of the tool to publish.
396
400
  :return: dict or str - JSON response containing the result of the publish operation if successful, otherwise the raw response text.
@@ -398,7 +402,7 @@ class ToolClient(BaseClient):
398
402
  endpoint = PUBLISH_TOOL_REVISION_V2.format(toolId=tool_id)
399
403
  headers = {
400
404
  "Authorization": self.api_service.token,
401
- "ProjectId": project_id
405
+ "ProjectId": self.project_id
402
406
  }
403
407
 
404
408
  logger.debug(f"Publishing revision {revision} for tool with ID {tool_id}")
@@ -413,14 +417,13 @@ class ToolClient(BaseClient):
413
417
  try:
414
418
  result = response.json()
415
419
  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}")
420
+ 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}")
421
+ raise InvalidAPIResponseException(f"Unable to publish revision {revision} for tool {tool_id} in project {self.project_id}: {response.text}")
418
422
 
419
423
  return result
420
424
 
421
425
  def get_parameter(
422
426
  self,
423
- project_id: str,
424
427
  tool_id: str = None,
425
428
  tool_public_name: str = None,
426
429
  revision: str = 0,
@@ -430,7 +433,6 @@ class ToolClient(BaseClient):
430
433
  """
431
434
  Retrieves details of parameters for a specific tool identified by either its ID or public name in the specified project.
432
435
 
433
- :param project_id: str - Unique identifier of the project.
434
436
  :param tool_id: str, optional - Unique identifier of the tool whose parameters are to be retrieved. Defaults to None.
435
437
  :param tool_public_name: str, optional - Public name of the tool whose parameters are to be retrieved. Defaults to None.
436
438
  :param revision: str - Revision of the parameters to retrieve. Defaults to "0" (latest revision).
@@ -450,7 +452,7 @@ class ToolClient(BaseClient):
450
452
  endpoint = GET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else GET_PARAMETER_V2.format(toolPublicName=tool_id)
451
453
  headers = {
452
454
  "Authorization": self.api_service.token,
453
- "ProjectId": project_id
455
+ "ProjectId": self.project_id
454
456
  }
455
457
 
456
458
  response = self.api_service.get(
@@ -462,17 +464,19 @@ class ToolClient(BaseClient):
462
464
  "allowDrafts": allow_drafts,
463
465
  }
464
466
  )
467
+ if response.status_code >= 300:
468
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
469
+ raise APIResponseError(f"API returned an error: {response.text}")
465
470
  try:
466
471
  result = response.json()
467
472
  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}")
473
+ 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}")
474
+ raise InvalidAPIResponseException(f"Unable to retrieve parameters for tool {tool_id or tool_public_name} in project {self.project_id}: {response.text}")
470
475
 
471
476
  return result
472
477
 
473
478
  def set_parameter(
474
479
  self,
475
- project_id: str,
476
480
  tool_id: str = None,
477
481
  tool_public_name: str = None,
478
482
  parameters: list = None
@@ -480,7 +484,6 @@ class ToolClient(BaseClient):
480
484
  """
481
485
  Sets or updates parameters for a specific tool identified by either its ID or public name in the specified project.
482
486
 
483
- :param project_id: str - Unique identifier of the project.
484
487
  :param tool_id: str, optional - Unique identifier of the tool whose parameters are to be set. Defaults to None.
485
488
  :param tool_public_name: str, optional - Public name of the tool whose parameters are to be set. Defaults to None.
486
489
  :param parameters: list - List of parameter dictionaries defining the tool's parameters.
@@ -497,7 +500,7 @@ class ToolClient(BaseClient):
497
500
  endpoint = SET_PARAMETER_V2.format(toolPublicName=tool_public_name) if tool_public_name else SET_PARAMETER_V2.format(toolPublicName=tool_id)
498
501
  headers = {
499
502
  "Authorization": self.api_service.token,
500
- "ProjectId": project_id,
503
+ "ProjectId": self.project_id,
501
504
  "Content-Type": "application/json",
502
505
  "Accept": "application/json"
503
506
  }
@@ -518,30 +521,24 @@ class ToolClient(BaseClient):
518
521
  headers=headers,
519
522
  data=data
520
523
  )
521
- try:
522
- result = response.json()
523
- 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}")
526
-
527
- return result
524
+ if response.status_code != 204:
525
+ logger.error(f"Unable to set parameter for tool {tool_id or tool_public_name} from project {self.project_id}: JSON parsing error (status {response.status_code}). Response: {response.text}")
526
+ raise InvalidAPIResponseException(f"Unable to set parameter for tool {tool_id or tool_public_name} from project {self.project_id}: {response.text}")
527
+ else:
528
+ return {}
528
529
 
529
530
  def export_tool(
530
531
  self,
531
- project_id: str,
532
532
  tool_id: str,
533
533
  ) -> dict:
534
534
  """
535
535
  Retrieves details of a specific tool from the specified project.
536
536
 
537
- :param project_id: str - Unique identifier of the project containing the tool.
538
537
  :param tool_id: str - Unique identifier of the tool to retrieve.
539
538
  :return: dict - JSON response containing the tool details.
540
539
  :raises InvalidAPIResponseException: If the response cannot be parsed as JSON or an error occurs.
541
540
  :raises MissingRequirementException: If project_id or tool_id is not provided.
542
541
  """
543
- if not project_id:
544
- raise MissingRequirementException("Cannot retrieve tool without specifying project_id")
545
542
 
546
543
  if not tool_id:
547
544
  raise MissingRequirementException("tool_id must be specified in order to retrieve the tool")
@@ -549,7 +546,7 @@ class ToolClient(BaseClient):
549
546
  endpoint = EXPORT_TOOL_V2.format(toolId=tool_id)
550
547
  headers = {
551
548
  "Authorization": self.api_service.token,
552
- "ProjectId": project_id
549
+ "ProjectId": self.project_id
553
550
  }
554
551
 
555
552
  logger.debug(f"Exporting tool with ID {tool_id}")
@@ -558,10 +555,13 @@ class ToolClient(BaseClient):
558
555
  endpoint=endpoint,
559
556
  headers=headers,
560
557
  )
558
+ if response.status_code >= 300:
559
+ logger.error(f"Invalid status code returned from the API endpoint: {response.text}")
560
+ raise APIResponseError(f"API returned an error: {response.text}")
561
561
  try:
562
562
  result = response.json()
563
563
  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}")
564
+ 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}")
565
+ raise InvalidAPIResponseException(f"Unable to export tool {tool_id} for project {self.project_id}: {response.text}")
566
566
 
567
567
  return result
@@ -37,8 +37,8 @@ class ToolMapper:
37
37
  """
38
38
  return [
39
39
  ToolMessage(
40
- description=msg["description"],
41
- type=msg["type"]
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["name"]
59
- description = tool_data["description"]
60
- scope = tool_data["scope"]
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
File without changes
File without changes
@@ -0,0 +1,91 @@
1
+ from unittest import TestCase
2
+ import uuid
3
+ from pygeai.assistant.managers import AssistantManager
4
+ from pygeai.core.models import WelcomeData, LlmSettings
5
+ from pygeai.assistant.rag.models import (
6
+ Search,
7
+ RetrieverOptions,
8
+ SearchOptions,
9
+ ChunkOptions,
10
+ IndexOptions,
11
+ RAGAssistant,
12
+ )
13
+
14
+
15
+ class TestAssistantCreateRagIntegration(TestCase):
16
+
17
+ def setUp(self):
18
+ """
19
+ Set up the test environment.
20
+ """
21
+ self.assistant_manager = AssistantManager(alias="beta")
22
+
23
+ self.new_rag = self.__load_rag()
24
+ self.created_rag: RAGAssistant = None
25
+
26
+
27
+ def tearDown(self):
28
+ """
29
+ Clean up after each test if necessary.
30
+ This can be used to delete the created tool
31
+ """
32
+ if isinstance(self.created_rag, RAGAssistant):
33
+ self.assistant_manager.delete_assistant(assistant_name=self.created_rag.name)
34
+
35
+
36
+ def __load_rag(self):
37
+ llm_options = LlmSettings(
38
+ cache=False,
39
+ temperature=0.1,
40
+ max_tokens=999,
41
+ model_name="gpt-3.5-turbo-16k",
42
+ n=1,
43
+ presence_penalty=0,
44
+ frequency_penalty=0,
45
+ provider="OpenAI",
46
+ stream=False,
47
+ top_p=1.0,
48
+ type=None,
49
+ verbose=True,
50
+ )
51
+
52
+ retriever_options = RetrieverOptions(type="vectorStore")
53
+
54
+ search_options = SearchOptions(
55
+ history_count=2,
56
+ llm=llm_options,
57
+ search=Search(
58
+ k=5,
59
+ return_source_documents=False,
60
+ score_threshold=0,
61
+ prompt="Use {context} and {question}",
62
+ template="",
63
+ ),
64
+ retriever=retriever_options,
65
+ )
66
+
67
+ chunk_options = ChunkOptions(chunk_size=999, chunk_overlap=0)
68
+
69
+ index_options = IndexOptions(chunks=chunk_options)
70
+
71
+ welcome_data = WelcomeData(
72
+ title="Test Profile Welcome Data",
73
+ description="Test Profile with WelcomeData",
74
+ features=[],
75
+ examples_prompt=[],
76
+ )
77
+
78
+ return RAGAssistant(
79
+ name=str(uuid.uuid4()),
80
+ description="Test Profile with WelcomeData",
81
+ search_options=search_options,
82
+ index_options=index_options,
83
+ welcome_data=welcome_data,
84
+ )
85
+
86
+
87
+ def test_create_rag_assistant(self):
88
+ rag_assistant = self.__load_rag()
89
+ self.created_rag = self.assistant_manager.create_assistant(rag_assistant)
90
+
91
+ self.assertIsInstance(self.created_rag, RAGAssistant, "Failed to create RAG assistant")
File without changes