pygeai 0.3.2__py3-none-any.whl → 0.4.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 (45) hide show
  1. pygeai/__init__.py +1 -1
  2. pygeai/chat/ui.py +0 -1
  3. pygeai/cli/__init__.py +1 -1
  4. pygeai/cli/commands/chat.py +54 -56
  5. pygeai/cli/commands/lab/ai_lab.py +129 -466
  6. pygeai/cli/commands/lab/options.py +8 -0
  7. pygeai/cli/commands/lab/utils.py +13 -0
  8. pygeai/cli/geai.py +5 -2
  9. pygeai/cli/texts/help.py +12 -0
  10. pygeai/core/common/config.py +0 -2
  11. pygeai/core/common/exceptions.py +6 -0
  12. pygeai/lab/agents/clients.py +30 -61
  13. pygeai/lab/clients.py +20 -0
  14. pygeai/lab/managers.py +6 -58
  15. pygeai/lab/processes/clients.py +81 -129
  16. pygeai/lab/strategies/clients.py +11 -17
  17. pygeai/lab/tools/clients.py +59 -59
  18. pygeai/tests/integration/assistants/__init__.py +0 -0
  19. pygeai/tests/integration/assistants/rag/__init__.py +0 -0
  20. pygeai/tests/integration/assistants/rag/test_create_rag.py +72 -0
  21. pygeai/tests/integration/chat/__init__.py +0 -0
  22. pygeai/tests/integration/chat/test_generate_image.py +162 -0
  23. pygeai/tests/integration/lab/agents/test_create_agent.py +9 -13
  24. pygeai/tests/integration/lab/agents/test_publish_agent_revision.py +0 -1
  25. pygeai/tests/integration/lab/agents/test_update_agent.py +6 -15
  26. pygeai/tests/integration/lab/tools/__init__.py +0 -0
  27. pygeai/tests/integration/lab/tools/test_create_tool.py +292 -0
  28. pygeai/tests/integration/lab/tools/test_delete_tool.py +87 -0
  29. pygeai/tests/integration/lab/tools/test_get_parameter.py +98 -0
  30. pygeai/tests/integration/lab/tools/test_get_tool.py +91 -0
  31. pygeai/tests/integration/lab/tools/test_list_tools.py +106 -0
  32. pygeai/tests/integration/lab/tools/test_publish_tool_revision.py +119 -0
  33. pygeai/tests/integration/lab/tools/test_set_parameter.py +114 -0
  34. pygeai/tests/integration/lab/tools/test_update_tool.py +268 -0
  35. pygeai/tests/snippets/lab/agents/create_agent_edge_case.py +48 -0
  36. pygeai/tests/snippets/lab/agents/create_agent_without_instructions.py +48 -0
  37. pygeai/tests/snippets/lab/agents/get_sharing_link.py +1 -2
  38. pygeai/tests/snippets/lab/tools/create_tool.py +1 -1
  39. pygeai/tests/snippets/lab/tools/create_tool_edge_case.py +50 -0
  40. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/METADATA +1 -1
  41. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/RECORD +45 -25
  42. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/WHEEL +0 -0
  43. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/entry_points.txt +0 -0
  44. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/licenses/LICENSE +0 -0
  45. {pygeai-0.3.2.dist-info → pygeai-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,98 @@
1
+ from unittest import TestCase
2
+ from pygeai.lab.managers import AILabManager
3
+ from pygeai.lab.models import FilterSettings, ToolParameter
4
+ from pygeai.core.common.exceptions import APIResponseError, MissingRequirementException
5
+ import copy
6
+
7
+ ai_lab_manager: AILabManager
8
+
9
+ class TestAILabGetParameterIntegration(TestCase):
10
+
11
+ def setUp(self):
12
+ self.ai_lab_manager = AILabManager(alias="beta")
13
+ self.tool_id = "42610b61-cb47-49bf-9475-36ee652f31f3"
14
+ self.filter_settings = FilterSettings(
15
+ revision="0",
16
+ version="0",
17
+ allow_drafts=True
18
+ )
19
+
20
+
21
+ def __get_parameter(self, tool_id: str = None, tool_public_name: str = None, filter_settings: FilterSettings = None):
22
+ return self.ai_lab_manager.get_parameter(
23
+ tool_id=self.tool_id if tool_id is None else tool_id,
24
+ tool_public_name=tool_public_name,
25
+ filter_settings=self.filter_settings if filter_settings is None else filter_settings
26
+ )
27
+
28
+
29
+ def test_get_parameter(self):
30
+ tool_parameters = self.__get_parameter()
31
+
32
+ for param in tool_parameters:
33
+ self.assertIsInstance(param, ToolParameter, "Expected a tool parameter")
34
+
35
+
36
+ def test_get_parameter_invalid_tool_id(self):
37
+ invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
38
+
39
+ with self.assertRaises(APIResponseError) as exception:
40
+ self.__get_parameter(tool_id=invalid_id)
41
+ self.assertIn(
42
+ f"Tool not found [IdOrName= {invalid_id}]",
43
+ str(exception.exception),
44
+ "Expected error when trying to send an invalid tool id"
45
+ )
46
+
47
+
48
+ def test_get_parameter_no_tool_id(self):
49
+ with self.assertRaises(MissingRequirementException) as exception:
50
+ self.__get_parameter(tool_id="")
51
+ self.assertIn(
52
+ "Either tool_id or tool_public_name must be provided.",
53
+ str(exception.exception),
54
+ "Expected error when trying to send a request without tool_id"
55
+ )
56
+
57
+
58
+ def test_get_parameter_by_tool_public_name(self):
59
+ tool_parameters = self.__get_parameter(tool_public_name="test.sdk.beta.tool")
60
+
61
+ for param in tool_parameters:
62
+ self.assertIsInstance(param, ToolParameter, "Expected a tool parameter")
63
+
64
+
65
+ def test_get_parameter_by_invalid_public_name(self):
66
+ invalid_public_name = "test.sdk.beta.tool.invalid"
67
+
68
+ with self.assertRaises(APIResponseError) as exception:
69
+ self.__get_parameter(tool_public_name=invalid_public_name)
70
+ self.assertIn(
71
+ f"Tool not found [IdOrName= {invalid_public_name}]",
72
+ str(exception.exception),
73
+ "Expected error when trying to send a request without tool_id"
74
+ )
75
+
76
+
77
+ def test_get_parameter_by_past_revision(self):
78
+ filter_settings = copy.deepcopy(self.filter_settings)
79
+ filter_settings.revision = "3"
80
+
81
+ with self.assertRaises(APIResponseError) as exception:
82
+ self.__get_parameter(filter_settings=filter_settings)
83
+ self.assertIn(
84
+ "Requested revision not found [revision=3].",
85
+ str(exception.exception),
86
+ "Expected error when trying to send a request without tool_id"
87
+ )
88
+
89
+
90
+ def test_get_parameter_by_draft_revision(self):
91
+ filter_settings = copy.deepcopy(self.filter_settings)
92
+ filter_settings.revision = "10"
93
+ tool_parameters = self.__get_parameter(filter_settings=filter_settings)
94
+
95
+ for param in tool_parameters:
96
+ self.assertIsInstance(param, ToolParameter, "Expected a tool parameter")
97
+
98
+
@@ -0,0 +1,91 @@
1
+ from unittest import TestCase
2
+ import unittest
3
+ from pygeai.lab.managers import AILabManager
4
+ from pygeai.lab.models import Tool, FilterSettings
5
+ from pygeai.core.common.exceptions import APIError
6
+ import copy
7
+
8
+ ai_lab_manager: AILabManager
9
+
10
+ class TestAILabGetToolIntegration(TestCase):
11
+
12
+ def setUp(self):
13
+ self.ai_lab_manager = AILabManager(alias="beta")
14
+ self.tool_id = "e3e4d64f-ce52-467e-90a9-aa4d08425e82"
15
+ self.filter_settings = FilterSettings(
16
+ revision="0",
17
+ version="0"
18
+ )
19
+
20
+ def __get_tool(self, tool_id=None, filter_settings: FilterSettings = None):
21
+ return self.ai_lab_manager.get_tool(
22
+ tool_id=self.tool_id if tool_id is None else tool_id,
23
+ filter_settings=self.filter_settings if filter_settings is None else filter_settings
24
+ )
25
+
26
+ def test_get_tool(self):
27
+ tool = self.__get_tool()
28
+ self.assertIsInstance(tool, Tool, "Expected a tool")
29
+
30
+
31
+ @unittest.skip("Skipped: Validate that when no tool_id is provided, the complete tool list is returned")
32
+ def test_get_tool_no_tool_id(self):
33
+ with self.assertRaises(Exception) as context:
34
+ self.__get_tool(tool_id="")
35
+
36
+
37
+ def test_get_tool_invalid_tool_id(self):
38
+ invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
39
+ with self.assertRaises(APIError) as context:
40
+ self.__get_tool(tool_id=invalid_id)
41
+ self.assertIn(
42
+ f"Tool not found [IdOrName= {invalid_id}].",
43
+ str(context.exception),
44
+ "Expected an error for invalid tool id"
45
+ )
46
+
47
+
48
+ def test_get_tool_no_revision(self):
49
+ filter_settings = copy.deepcopy(self.filter_settings)
50
+ filter_settings.revision = None
51
+ tool = self.__get_tool(filter_settings=filter_settings)
52
+
53
+ self.assertIsInstance(tool, Tool, "Expected a tool")
54
+ self.assertGreaterEqual(tool.revision, 1, "Expected tool revision to be the latest")
55
+
56
+
57
+ def test_get_tool_by_revision(self):
58
+ filter_settings = copy.deepcopy(self.filter_settings)
59
+ filter_settings.revision = "6"
60
+ tool = self.__get_tool(filter_settings=filter_settings)
61
+
62
+ self.assertEqual(6, tool.revision, "Expected agent revision to be 6")
63
+
64
+
65
+ def test_get_tool_by_earlier_revision(self):
66
+ filter_settings = copy.deepcopy(self.filter_settings)
67
+ filter_settings.revision = "2"
68
+ with self.assertRaises(APIError) as context:
69
+ self.__get_tool(filter_settings=filter_settings)
70
+ self.assertIn(
71
+ f"Requested revision not found [revision={filter_settings.revision}].",
72
+ str(context.exception),
73
+ "Expected an error for revision not found"
74
+ )
75
+
76
+ #TODO: The API is returning the version of the tool, but the sdk does not
77
+ def test_get_tool_no_version(self):
78
+ filter_settings = copy.deepcopy(self.filter_settings)
79
+ filter_settings.version = None
80
+ tool = self.__get_tool(filter_settings=filter_settings)
81
+
82
+ self.assertIsInstance(tool, Tool, "Expected a tool")
83
+
84
+
85
+ #TODO: The API is returning the version of the tool, but the sdk does not
86
+ def test_get_tool_by_version(self):
87
+ filter_settings = copy.deepcopy(self.filter_settings)
88
+ filter_settings.version = "1"
89
+ tool = self.__get_tool(filter_settings=filter_settings)
90
+
91
+ self.assertIsInstance(tool, Tool, "Expected a tool")
@@ -0,0 +1,106 @@
1
+ from unittest import TestCase
2
+ from pygeai.lab.managers import AILabManager
3
+ from pygeai.lab.models import ToolList, FilterSettings
4
+ import copy
5
+
6
+ ai_lab_manager: AILabManager
7
+
8
+ class TestAILabListToolsIntegration(TestCase):
9
+
10
+ def setUp(self):
11
+ self.ai_lab_manager = AILabManager(alias="beta")
12
+ self.filter_settings = FilterSettings(
13
+ allow_external=False,
14
+ allow_drafts=True,
15
+ access_scope="private"
16
+ )
17
+
18
+
19
+ def __list_tools(self, filter_settings: FilterSettings = None):
20
+ filter_settings = filter_settings if filter_settings != None else self.filter_settings
21
+ return self.ai_lab_manager.list_tools(filter_settings=filter_settings)
22
+
23
+
24
+ def test_private_list_tools(self):
25
+ result = self.__list_tools()
26
+ self.assertIsInstance(result, ToolList , "Expected a list of tools")
27
+
28
+ for tool in result.tools:
29
+ self.assertTrue(tool.access_scope == "private", "Expected all tools to be private")
30
+
31
+
32
+ def test_public_list_tools(self):
33
+ filter_settings = copy.deepcopy(self.filter_settings)
34
+ filter_settings.access_scope = "public"
35
+
36
+ result = self.__list_tools(filter_settings=filter_settings)
37
+ self.assertIsInstance(result, ToolList , "Expected a list of tools")
38
+
39
+ for tool in result.tools:
40
+ self.assertTrue(tool.access_scope == "public", "Expected all tools to be public")
41
+
42
+
43
+ def test_list_tools_small_count(self):
44
+ filter_settings = copy.deepcopy(self.filter_settings)
45
+ filter_settings.count = 2
46
+
47
+ result = self.__list_tools(filter_settings=filter_settings)
48
+ self.assertIsInstance(result, ToolList , "Expected a list of tools")
49
+
50
+ self.assertEqual(len(result), 2, "Expected list of tools returned to be 2")
51
+
52
+
53
+ def test_list_tools_big_count(self):
54
+ filter_settings = copy.deepcopy(self.filter_settings)
55
+ filter_settings.count = 500
56
+
57
+ result = self.__list_tools(filter_settings=filter_settings)
58
+ self.assertIsInstance(result, ToolList , "Expected a list of tools")
59
+
60
+ self.assertLessEqual(len(result), 500, "Expected list of tools returned to be 500 or less")
61
+
62
+
63
+ def test_list_tools_allowing_draft(self):
64
+ result = self.__list_tools()
65
+ validated = any(tool.is_draft == True for tool in result.tools)
66
+ self.assertTrue(
67
+ validated,
68
+ "Expected at least one tool to be a draft"
69
+ )
70
+
71
+
72
+ def test_list_tools_no_draft(self):
73
+ filter_settings = copy.deepcopy(self.filter_settings)
74
+ filter_settings.allow_drafts = False
75
+ result = self.__list_tools(filter_settings=filter_settings)
76
+
77
+ validated = any(tool.is_draft == True for tool in result.tools)
78
+ self.assertFalse(
79
+ validated,
80
+ "Expected no draft tools in the list"
81
+ )
82
+
83
+
84
+ def test_list_tools_invalid_scope(self):
85
+ filter_settings = copy.deepcopy(self.filter_settings)
86
+ filter_settings.scope = "project"
87
+
88
+ with self.assertRaises(ValueError) as exception:
89
+ self.__list_tools(filter_settings=filter_settings)
90
+
91
+ self.assertIn(
92
+ "Scope must be one of builtin, external, api, proxied.",
93
+ str(exception.exception),
94
+ f"The expected error about invalid scope was not returned"
95
+ )
96
+
97
+
98
+ def test_list_tools_allowing_external(self):
99
+ filter_settings = copy.deepcopy(self.filter_settings)
100
+ filter_settings.allow_external = False
101
+
102
+ result = self.__list_tools(filter_settings=filter_settings)
103
+ self.assertIsInstance(result, ToolList , "Expected a list of tools")
104
+
105
+
106
+
@@ -0,0 +1,119 @@
1
+ from unittest import TestCase
2
+ import uuid
3
+ from pygeai.lab.managers import AILabManager
4
+ from pygeai.lab.models import Tool
5
+ from pygeai.core.common.exceptions import APIError
6
+
7
+ ai_lab_manager: AILabManager
8
+
9
+ class TestAILabPublishToolRevisionIntegration(TestCase):
10
+
11
+ def setUp(self):
12
+ self.ai_lab_manager = AILabManager(alias="beta")
13
+ self.tool_id = "c77e1f2e-0322-4dd0-b6ec-aff217f1cb32"
14
+
15
+
16
+ def __publish_tool_revision(self, revision: str, tool_id=None):
17
+ return self.ai_lab_manager.publish_tool_revision(
18
+ tool_id=self.tool_id if tool_id is None else tool_id,
19
+ revision=revision
20
+ )
21
+
22
+ def __load_tool(self):
23
+ self.random_str = str(uuid.uuid4())
24
+ return Tool(
25
+ id="c77e1f2e-0322-4dd0-b6ec-aff217f1cb32",
26
+ name=f"sdk_project_updated_tool_{self.random_str}",
27
+ description=f"Tool updated for sdk testing purposes {self.random_str}",
28
+ scope="builtin",
29
+ openApi="https://raw.usercontent.com//openapi.json",
30
+ openApiJson={"openapi": "3.0.0","info": {"title": f"Simple API overview {self.random_str}","version": "3.0.0"}},
31
+ accessScope="private",
32
+ reportEvents="None",
33
+ parameters=[{
34
+ "key": "param",
35
+ "description": f"param description {self.random_str}",
36
+ "type":"app",
37
+ "value": f"value {self.random_str}",
38
+ "data_type": "String",
39
+ "isRequired": False
40
+ }]
41
+ )
42
+
43
+
44
+ def __update_tool(self, tool: Tool = None, automatic_publish: bool = False, upsert: bool = False):
45
+ """
46
+ Helper method to update a tool.
47
+ """
48
+ tool = self.__load_tool()
49
+ return self.ai_lab_manager.update_tool(
50
+ tool = tool,
51
+ automatic_publish=False,
52
+ upsert=False
53
+ )
54
+
55
+
56
+ def test_publish_tool_revision(self):
57
+ updated_tool = self.__update_tool()
58
+ new_revision = updated_tool.revision
59
+
60
+ published_tool = self.__publish_tool_revision(revision=str(new_revision))
61
+
62
+ self.assertFalse(published_tool.is_draft, "Expected draft to be false after publishing the revision")
63
+ self.assertEqual(published_tool.revision, new_revision, "Expected last revision to be published")
64
+
65
+
66
+ def test_publish_tool_earlier_revision_with_newer_revision_published(self):
67
+ with self.assertRaises(APIError) as exception:
68
+ self.__publish_tool_revision(revision="1")
69
+ self.assertIn(
70
+ "There are newer published revisions.",
71
+ str(exception.exception),
72
+ "Expected error when trying to send a earlier revision"
73
+ )
74
+
75
+
76
+ def test_publish_tool_earlier_revision(self):
77
+ earlier_revision = (self.__update_tool()).revision
78
+ #update the tool to create a newer revision
79
+ self.__update_tool()
80
+
81
+ published_tool = self.__publish_tool_revision(revision=earlier_revision)
82
+
83
+ self.assertFalse(published_tool.is_draft, "Expected draft to be false after publishing the revision")
84
+ self.assertEqual(published_tool.revision, earlier_revision, "Expected last revision to be published")
85
+
86
+
87
+ def test_publish_tool_invalid_revision(self):
88
+ with self.assertRaises(APIError) as exception:
89
+ self.__publish_tool_revision(revision="10000000")
90
+ self.assertIn(
91
+ "Invalid revision [rev=10000000]",
92
+ str(exception.exception),
93
+ "Expected error when trying to send a revision that does not exist"
94
+ )
95
+
96
+
97
+ def test_publish_tool_string_revision(self):
98
+ with self.assertRaises(APIError) as exception:
99
+ self.__publish_tool_revision(revision="revision")
100
+ self.assertIn("Bad Request", str(exception.exception))
101
+ self.assertIn("400", str(exception.exception))
102
+
103
+
104
+ def test_publish_tool_invalid_tool_id(self):
105
+ invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
106
+ with self.assertRaises(APIError) as exception:
107
+ self.__publish_tool_revision(revision="103", tool_id=invalid_id)
108
+ self.assertIn(
109
+ f"Tool not found [IdOrName= {invalid_id}].",
110
+ str(exception.exception),
111
+ "Expected error when sending and invalid agent id"
112
+ )
113
+
114
+
115
+ def test_publish_tool_no_tool_id(self):
116
+ with self.assertRaises(APIError) as exception:
117
+ self.__publish_tool_revision(revision="103", tool_id="")
118
+ self.assertIn("Not Found", str(exception.exception))
119
+ self.assertIn("404", str(exception.exception))
@@ -0,0 +1,114 @@
1
+ from unittest import TestCase
2
+ import uuid
3
+ from pygeai.lab.managers import AILabManager
4
+ from pygeai.lab.models import ToolParameter
5
+ from pygeai.core.common.exceptions import MissingRequirementException, InvalidAPIResponseException
6
+
7
+ ai_lab_manager: AILabManager
8
+
9
+ class TestAILabSetParameterIntegration(TestCase):
10
+ def setUp(self):
11
+ self.ai_lab_manager = AILabManager(alias="beta")
12
+ self.tool_id = "42610b61-cb47-49bf-9475-36ee652f31f3"
13
+ self.tool_parameters = self.__load_parameters()
14
+
15
+
16
+ def __set_parameter(self, tool_id: str = None, tool_public_name: str = None, parameters: list = None):
17
+ return self.ai_lab_manager.set_parameter(
18
+ tool_id = self.tool_id if tool_id is None else tool_id,
19
+ tool_public_name = tool_public_name,
20
+ parameters = self.tool_parameters if parameters is None else parameters,
21
+ )
22
+
23
+
24
+ def __load_parameters(self):
25
+ random_str = str(uuid.uuid4())
26
+ return [
27
+ ToolParameter(
28
+ key="param3",
29
+ data_type="String",
30
+ description=f"{random_str}_config",
31
+ is_required=True,
32
+ type="config",
33
+ value=random_str
34
+ )
35
+ ]
36
+
37
+
38
+ def test_set_parameter(self):
39
+ result = self.__set_parameter()
40
+ self.assertEqual(
41
+ result.content,
42
+ "Parameter set successfully",
43
+ "Expected successful parameter update"
44
+ )
45
+
46
+
47
+ def test_set_parameter_invalid_tool_id(self):
48
+ invalid_id = "0026e53d-ea78-4cac-af9f-12650invalid"
49
+
50
+ with self.assertRaises(InvalidAPIResponseException) as context:
51
+ self.__set_parameter(tool_id=invalid_id)
52
+
53
+ self.assertIn(
54
+ f"Unable to set parameter for tool {invalid_id}",
55
+ str(context.exception),
56
+ "Expected error for invalid tool ID"
57
+ )
58
+
59
+
60
+ def test_set_parameter_no_tool_id(self):
61
+ with self.assertRaises(MissingRequirementException) as context:
62
+ self.__set_parameter(tool_id="")
63
+
64
+ self.assertIn(
65
+ "Either tool_id or tool_public_name must be provided.",
66
+ str(context.exception),
67
+ "Expected error for invalid tool ID"
68
+ )
69
+
70
+
71
+ def test_set_parameter_by_tool_public_name(self):
72
+ self.tool_parameters[0].key = "Param1"
73
+
74
+ result = self.__set_parameter(tool_id = "", tool_public_name="test.sdk.beta.tool")
75
+ self.assertEqual(
76
+ result.content,
77
+ "Parameter set successfully",
78
+ "Expected successful parameter update"
79
+ )
80
+
81
+
82
+ def test_set_parameter_by_invalid_public_name(self):
83
+ invalid_public_name = "test.sdk.beta.tool.invalid"
84
+
85
+ with self.assertRaises(InvalidAPIResponseException) as exception:
86
+ self.__set_parameter(tool_id = "", tool_public_name=invalid_public_name)
87
+ self.assertIn(
88
+ f"Unable to set parameter for tool {invalid_public_name}",
89
+ str(exception.exception),
90
+ "Expected error when trying to send a request without tool_id"
91
+ )
92
+
93
+
94
+ def test_set_parameter_no_parameters(self):
95
+ self.tool_parameters = []
96
+
97
+ with self.assertRaises(MissingRequirementException) as exception:
98
+ self.__set_parameter()
99
+ self.assertIn(
100
+ "Parameters list must be provided and non-empty.",
101
+ str(exception.exception),
102
+ "Expected error when trying to send a request without parameters"
103
+ )
104
+
105
+
106
+ def test_set_parameter_not_added_parameters(self):
107
+ #param3 set on self.tool_parameters, does not exist in the public tool
108
+ with self.assertRaises(InvalidAPIResponseException) as exception:
109
+ self.__set_parameter(tool_id = "", tool_public_name = "test.sdk.beta.tool")
110
+ self.assertIn(
111
+ "Parameter param3 not found in this tool",
112
+ str(exception.exception),
113
+ "Expected error when trying to send a request without parameters"
114
+ )