alita-sdk 0.3.162__py3-none-any.whl → 0.3.163__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.
@@ -0,0 +1,278 @@
1
+ import logging
2
+ import json
3
+ import traceback
4
+ import re
5
+ from typing import Type
6
+ from langchain_core.tools import BaseTool, ToolException
7
+ from pydantic.fields import Field
8
+ from pydantic import create_model, BaseModel
9
+ from .api_wrapper import CarrierAPIWrapper
10
+
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class UpdateUITestScheduleTool(BaseTool):
16
+ api_wrapper: CarrierAPIWrapper = Field(..., description="Carrier API Wrapper instance")
17
+ name: str = "update_ui_test_schedule"
18
+ description: str = ("Update UI test schedule on the Carrier platform. Use this tool when user wants to update, modify, or change a UI test schedule. "
19
+ "Provide test_id, schedule_name, and cron_timer, or leave empty to see available tests.")
20
+ args_schema: Type[BaseModel] = create_model(
21
+ "UpdateUITestScheduleInput",
22
+ test_id=(str, Field(default="", description="Test ID to update schedule for")),
23
+ schedule_name=(str, Field(default="", description="Name for the new schedule")),
24
+ cron_timer=(str, Field(default="", description="Cron expression for schedule timing (e.g., '0 2 * * *')")),
25
+ )
26
+
27
+ def _run(self, test_id: str = "", schedule_name: str = "", cron_timer: str = ""):
28
+ try:
29
+ # Check if no parameters provided - show available tests
30
+ if (not test_id or test_id.strip() == "") and (not schedule_name or schedule_name.strip() == "") and (not cron_timer or cron_timer.strip() == ""):
31
+ return self._show_available_tests_and_instructions()
32
+
33
+ # Check if test_id is missing but other params provided
34
+ if (not test_id or test_id.strip() == ""):
35
+ return self._show_missing_test_id_message()
36
+
37
+ # Check if schedule_name or cron_timer is missing
38
+ if (not schedule_name or schedule_name.strip() == "") or (not cron_timer or cron_timer.strip() == ""):
39
+ return self._show_missing_parameters_message(test_id, schedule_name, cron_timer)
40
+
41
+ # Validate cron timer format
42
+ if not self._validate_cron_timer(cron_timer):
43
+ return self._show_invalid_cron_message(cron_timer)
44
+
45
+ # Get UI tests list to verify test exists
46
+ ui_tests = self.api_wrapper.get_ui_tests_list()
47
+ test_data = None
48
+ test_id_int = None
49
+
50
+ # Try to find test by ID
51
+ if test_id.isdigit():
52
+ test_id_int = int(test_id)
53
+ for test in ui_tests:
54
+ if test.get("id") == test_id_int:
55
+ test_data = test
56
+ break
57
+
58
+ if not test_data:
59
+ available_tests = []
60
+ for test in ui_tests:
61
+ available_tests.append(f"ID: {test.get('id')}, Name: {test.get('name')}")
62
+
63
+ return f"❌ **Test not found for ID: {test_id}**\n\n**Available UI tests:**\n" + "\n".join([f"- {test}" for test in available_tests])
64
+
65
+ # Get detailed test configuration
66
+ test_details = self.api_wrapper.get_ui_test_details(str(test_id_int))
67
+
68
+ if not test_details:
69
+ return f"❌ **Could not retrieve test details for test ID {test_id_int}.**"
70
+
71
+ # Parse and update the test configuration
72
+ updated_config = self._parse_and_update_test_data(test_details, schedule_name, cron_timer)
73
+
74
+ # Execute the PUT request to update the test
75
+ result = self.api_wrapper.update_ui_test(str(test_id_int), updated_config)
76
+
77
+ return self._format_success_message(test_data.get('name', 'Unknown'), test_id_int, schedule_name, cron_timer)
78
+
79
+ except Exception:
80
+ stacktrace = traceback.format_exc()
81
+ logger.error(f"Error updating UI test schedule: {stacktrace}")
82
+ raise ToolException(stacktrace)
83
+
84
+ def _show_available_tests_and_instructions(self):
85
+ """Show available tests and instructions when no parameters provided."""
86
+ try:
87
+ ui_tests = self.api_wrapper.get_ui_tests_list()
88
+
89
+ if not ui_tests:
90
+ return "❌ **No UI tests found.**"
91
+
92
+ message = ["# 📋 Update UI Test Schedule\n"]
93
+ message.append("## Available UI Tests:")
94
+
95
+ for test in ui_tests:
96
+ message.append(f"- **ID: {test.get('id')}**, Name: `{test.get('name')}`, Runner: `{test.get('runner')}`")
97
+
98
+ message.append("\n## 📝 Instructions:")
99
+ message.append("For updating UI test schedule, please provide me:")
100
+ message.append("- **`test_id`** - The ID of the test you want to update")
101
+ message.append("- **`schedule_name`** - A name for your new schedule")
102
+ message.append("- **`cron_timer`** - Cron expression for timing (e.g., `0 2 * * *` for daily at 2 AM)")
103
+
104
+ message.append("\n## 💡 Example:")
105
+ message.append("```")
106
+ message.append("test_id: 42")
107
+ message.append("schedule_name: Daily Morning Test")
108
+ message.append("cron_timer: 0 2 * * *")
109
+ message.append("```")
110
+
111
+ return "\n".join(message)
112
+
113
+ except Exception:
114
+ stacktrace = traceback.format_exc()
115
+ logger.error(f"Error fetching UI tests list: {stacktrace}")
116
+ raise ToolException(stacktrace)
117
+
118
+ def _show_missing_test_id_message(self):
119
+ """Show message when test_id is missing."""
120
+ return """# ❌ Missing Test ID
121
+
122
+ **For updating UI test schedule, please provide me:**
123
+ - **`test_id`** - The ID of the test you want to update
124
+ - **`schedule_name`** - A name for your new schedule
125
+ - **`cron_timer`** - Cron expression for timing
126
+
127
+ Use the tool without parameters to see available tests."""
128
+
129
+ def _show_missing_parameters_message(self, test_id: str, schedule_name: str, cron_timer: str):
130
+ """Show message when some parameters are missing."""
131
+ missing = []
132
+ if not schedule_name or schedule_name.strip() == "":
133
+ missing.append("**`schedule_name`**")
134
+ if not cron_timer or cron_timer.strip() == "":
135
+ missing.append("**`cron_timer`**")
136
+
137
+ message = [f"# ❌ Missing Parameters for Test ID: {test_id}\n"]
138
+ message.append("**Missing parameters:**")
139
+ for param in missing:
140
+ message.append(f"- {param}")
141
+
142
+ message.append("\n**For updating UI test schedule, please provide:**")
143
+ message.append("- **`test_id`** ✅ (provided)")
144
+ message.append("- **`schedule_name`** - A name for your new schedule")
145
+ message.append("- **`cron_timer`** - Cron expression for timing (e.g., `0 2 * * *`)")
146
+
147
+ return "\n".join(message)
148
+
149
+ def _validate_cron_timer(self, cron_timer: str) -> bool:
150
+ """Validate cron timer format."""
151
+ # Basic cron validation - should have 5 parts separated by spaces
152
+ parts = cron_timer.strip().split()
153
+ if len(parts) != 5:
154
+ return False
155
+
156
+ # Each part should contain only digits, *, /, -, or ,
157
+ cron_pattern = re.compile(r'^[0-9*,/-]+$')
158
+ return all(cron_pattern.match(part) for part in parts)
159
+
160
+ def _show_invalid_cron_message(self, cron_timer: str):
161
+ """Show message for invalid cron timer."""
162
+ return f"""# ❌ Invalid Cron Timer Format
163
+
164
+ **Provided:** `{cron_timer}`
165
+
166
+ **Cron format should be:** `minute hour day month weekday`
167
+
168
+ ## Valid Examples:
169
+ - `0 2 * * *` - Daily at 2:00 AM
170
+ - `30 14 * * 1` - Every Monday at 2:30 PM
171
+ - `0 */6 * * *` - Every 6 hours
172
+ - `15 10 1 * *` - First day of every month at 10:15 AM
173
+ - `0 9 * * 1-5` - Weekdays at 9:00 AM
174
+
175
+ ## Format Rules:
176
+ - **Minute:** 0-59
177
+ - **Hour:** 0-23
178
+ - **Day:** 1-31
179
+ - **Month:** 1-12
180
+ - **Weekday:** 0-7 (0 and 7 are Sunday)
181
+ - Use **`*`** for "any value"
182
+ - Use **`,`** for multiple values
183
+ - Use **`-`** for ranges
184
+ - Use **`/`** for step values"""
185
+
186
+ def _parse_and_update_test_data(self, get_data: dict, schedule_name: str, cron_timer: str) -> dict:
187
+ """Parse GET response data and transform it into the required format for PUT request."""
188
+
189
+ # Extract environment and test type from test parameters
190
+ env_type = ""
191
+ test_type = ""
192
+ for param in get_data.get("test_parameters", []):
193
+ if param.get("name") == "env_type":
194
+ env_type = param.get("default", "")
195
+ elif param.get("name") == "test_type":
196
+ test_type = param.get("default", "")
197
+
198
+ # Construct common_params from GET data
199
+ common_params = {
200
+ "aggregation": get_data.get("aggregation", "max"),
201
+ "cc_env_vars": get_data.get("cc_env_vars", {}),
202
+ "entrypoint": get_data.get("entrypoint", ""),
203
+ "env_type": env_type,
204
+ "env_vars": get_data.get("env_vars", {}),
205
+ "location": get_data.get("location", ""),
206
+ "loops": get_data.get("loops", 1),
207
+ "name": get_data.get("name", ""),
208
+ "parallel_runners": get_data.get("parallel_runners", 1),
209
+ "runner": get_data.get("runner", ""),
210
+ "source": get_data.get("source", {}),
211
+ "test_type": test_type
212
+ }
213
+
214
+ # Extract only required integrations (reporters and system)
215
+ integrations = {
216
+ "reporters": get_data.get("integrations", {}).get("reporters", {}),
217
+ "system": get_data.get("integrations", {}).get("system", {})
218
+ }
219
+
220
+ # Process existing schedules and add the new one
221
+ schedules = []
222
+
223
+ # Keep existing schedules
224
+ for schedule in get_data.get("schedules", []):
225
+ existing_schedule = {
226
+ "active": schedule.get("active", False),
227
+ "cron": schedule.get("cron", ""),
228
+ "cron_radio": "custom",
229
+ "errors": {},
230
+ "id": schedule.get("id"),
231
+ "name": schedule.get("name", ""),
232
+ "project_id": schedule.get("project_id"),
233
+ "rpc_kwargs": schedule.get("rpc_kwargs"),
234
+ "test_id": schedule.get("test_id"),
235
+ "test_params": schedule.get("test_params", [])
236
+ }
237
+ schedules.append(existing_schedule)
238
+
239
+ # Add the new schedule
240
+ new_schedule = {
241
+ "active": True,
242
+ "cron": cron_timer,
243
+ "cron_radio": "custom",
244
+ "errors": {},
245
+ "id": None, # New schedule, no ID yet
246
+ "name": schedule_name,
247
+ "test_params": []
248
+ }
249
+ schedules.append(new_schedule)
250
+
251
+ # Assemble the final PUT request data
252
+ put_data = {
253
+ "common_params": common_params,
254
+ "integrations": integrations,
255
+ "run_test": False,
256
+ "schedules": schedules,
257
+ "test_parameters": [] # Empty as required in PUT request
258
+ }
259
+
260
+ return put_data
261
+
262
+ def _format_success_message(self, test_name: str, test_id: int, schedule_name: str, cron_timer: str) -> str:
263
+ """Format success message in markdown."""
264
+ return f"""# ✅ UI Test Schedule Updated Successfully!
265
+
266
+ ## Test Information:
267
+ - **Test Name:** `{test_name}`
268
+ - **Test ID:** `{test_id}`
269
+
270
+ ## New Schedule Added:
271
+ - **Schedule Name:** `{schedule_name}`
272
+ - **Cron Timer:** `{cron_timer}`
273
+ - **Status:** Active ✅
274
+
275
+ ## 🎯 What happens next:
276
+ The test will now run automatically according to the specified schedule. You can view and manage schedules in the Carrier platform UI.
277
+
278
+ **Schedule will execute:** Based on cron expression `{cron_timer}`"""
@@ -0,0 +1,62 @@
1
+ from typing import List, Literal, Optional
2
+
3
+ from langchain_community.agent_toolkits.base import BaseToolkit
4
+ from langchain_core.tools import BaseTool
5
+ from pydantic import create_model, BaseModel, Field, SecretStr
6
+
7
+ from .api_wrapper import ZephyrSquadApiWrapper
8
+ from ..base.tool import BaseAction
9
+ from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
10
+
11
+ name = "zephyr"
12
+
13
+ def get_tools(tool):
14
+ return ZephyrSquadToolkit().get_toolkit(
15
+ selected_tools=tool['settings'].get('selected_tools', []),
16
+ account_id=tool['settings']["account_id"],
17
+ access_key=tool['settings']["access_key"],
18
+ secret_key=tool['settings']["secret_key"],
19
+ toolkit_name=tool.get('toolkit_name')
20
+ ).get_tools()
21
+
22
+ class ZephyrSquadToolkit(BaseToolkit):
23
+ tools: List[BaseTool] = []
24
+ toolkit_max_length: int = 0
25
+
26
+ @staticmethod
27
+ def toolkit_config_schema() -> BaseModel:
28
+ selected_tools = {x['name']: x['args_schema'].schema() for x in ZephyrSquadApiWrapper.model_construct().get_available_tools()}
29
+ ZephyrSquadToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
+ return create_model(
31
+ "zephyr_squad",
32
+ account_id=(str, Field(description="AccountID for the user that is going to be authenticating")),
33
+ access_key=(str, Field(description="Generated access key")),
34
+ secret_key=(SecretStr, Field(description="Generated secret key")),
35
+ selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
36
+ __config__={'json_schema_extra': {'metadata': {"label": "Zephyr Squad", "icon_url": "zephyr.svg",
37
+ "categories": ["test management"],
38
+ "extra_categories": ["test automation", "test case management", "test planning"]
39
+ }}}
40
+ )
41
+
42
+ @classmethod
43
+ def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
44
+ zephyr_api_wrapper = ZephyrSquadApiWrapper(**kwargs)
45
+ prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
46
+ available_tools = zephyr_api_wrapper.get_available_tools()
47
+ tools = []
48
+ for tool in available_tools:
49
+ if selected_tools:
50
+ if tool["name"] not in selected_tools:
51
+ continue
52
+ tools.append(BaseAction(
53
+ api_wrapper=zephyr_api_wrapper,
54
+ name=prefix + tool["name"],
55
+ description=tool["description"],
56
+ args_schema=tool["args_schema"]
57
+ ))
58
+ return cls(tools=tools)
59
+
60
+ def get_tools(self):
61
+ return self.tools
62
+
@@ -0,0 +1,135 @@
1
+ from typing import List, Literal
2
+
3
+ from pydantic import model_validator, create_model, Field, SecretStr, BaseModel, PrivateAttr
4
+
5
+ from .zephyr_squad_cloud_client import ZephyrSquadCloud
6
+ from ..elitea_base import BaseToolApiWrapper
7
+
8
+
9
+ class ZephyrSquadApiWrapper(BaseToolApiWrapper):
10
+ account_id: str
11
+ access_key: str
12
+ secret_key: SecretStr
13
+ _client: ZephyrSquadCloud = PrivateAttr()
14
+
15
+ @model_validator(mode='before')
16
+ @classmethod
17
+ def validate_toolkit(cls, values):
18
+ account_id = values.get("account_id", None)
19
+ access_key = values.get("access_key", None)
20
+ secret_key = values.get("secret_key", None)
21
+ if not account_id:
22
+ raise ValueError("account_id is required.")
23
+ if not access_key:
24
+ raise ValueError("access_key is required.")
25
+ if not secret_key:
26
+ raise ValueError("secret_key is required.")
27
+ cls._client = ZephyrSquadCloud(
28
+ account_id=account_id,
29
+ access_key=access_key,
30
+ secret_key=secret_key
31
+ )
32
+ return values
33
+
34
+ def get_test_step(self, issue_id, step_id, project_id):
35
+ """Retrieve details for a specific test step in a Jira test case."""
36
+ return self._client.get_test_step(issue_id, step_id, project_id)
37
+
38
+ def update_test_step(self, issue_id, step_id, project_id, json):
39
+ """Update the content or a specific test step in a Jira test case."""
40
+ return self._client.update_test_step(issue_id, step_id, project_id, json)
41
+
42
+ def delete_test_step(self, issue_id, step_id, project_id):
43
+ """Remove a specific test step from a Jira test case."""
44
+ return self._client.delete_test_step(issue_id, step_id, project_id)
45
+
46
+ def create_new_test_step(self, issue_id, project_id, json):
47
+ """Add a new test step to a Jira test case."""
48
+ return self._client.create_new_test_step(issue_id, project_id, json)
49
+
50
+ def get_all_test_steps(self, issue_id, project_id):
51
+ """List all test steps associated with a Jira test case."""
52
+ return self._client.get_all_test_steps(issue_id, project_id)
53
+
54
+ def get_all_test_step_statuses(self):
55
+ """Retrieve all possible statuses for test steps in Jira."""
56
+ return self._client.get_all_test_step_statuses()
57
+
58
+ def get_available_tools(self):
59
+ return [
60
+ {
61
+ "name": "get_test_step",
62
+ "description": self.get_test_step.__doc__,
63
+ "args_schema": ProjectIssueStep,
64
+ "ref": self.get_test_step,
65
+ },
66
+ {
67
+ "name": "update_test_step",
68
+ "description": self.update_test_step.__doc__,
69
+ "args_schema": UpdateTestStep,
70
+ "ref": self.update_test_step,
71
+ },
72
+ {
73
+ "name": "delete_test_step",
74
+ "description": self.delete_test_step.__doc__,
75
+ "args_schema": ProjectIssueStep,
76
+ "ref": self.delete_test_step,
77
+ },
78
+ {
79
+ "name": "create_new_test_step",
80
+ "description": self.create_new_test_step.__doc__,
81
+ "args_schema": CreateNewTestStep,
82
+ "ref": self.create_new_test_step,
83
+ },
84
+ {
85
+ "name": "get_all_test_steps",
86
+ "description": self.get_all_test_steps.__doc__,
87
+ "args_schema": ProjectIssue,
88
+ "ref": self.get_all_test_steps,
89
+ },
90
+ {
91
+ "name": "get_all_test_step_statuses",
92
+ "description": self.get_all_test_step_statuses.__doc__,
93
+ "args_schema": create_model("NoInput"),
94
+ "ref": self.get_all_test_step_statuses,
95
+ }
96
+ ]
97
+
98
+
99
+ ProjectIssue = create_model(
100
+ "ProjectIssue",
101
+ issue_id=(int, Field(description="Jira ticket id of test case to which the test step belongs.")),
102
+ project_id=(int, Field(description="Jira project id to which test case belongs."))
103
+ )
104
+
105
+ ProjectIssueStep = create_model(
106
+ "ProjectIssueStep",
107
+ step_id=(str, Field(description="Test step id to operate.")),
108
+ __base__=ProjectIssue
109
+ )
110
+
111
+ UpdateTestStep = create_model(
112
+ "UpdateTestStep",
113
+ json=(str, Field(description=(
114
+ "JSON body to update a Zephyr test step. Fields:\n"
115
+ "- id (string, required): Unique identifier for the test step. Example: \"0001481146115453-3a0480a3ffffc384-0001\"\n"
116
+ "- step (string, required): Description of the test step. Example: \"Sample Test Step\"\n"
117
+ "- data (string, optional): Test data used in this step. Example: \"Sample Test Data\"\n"
118
+ "- result (string, optional): Expected result after executing the step. Example: \"Expected Test Result\"\n"
119
+ "- customFieldValues (array[object], optional): List of custom field values for the test step. Each object contains:\n"
120
+ " - customFieldId (string, required): ID of the custom field. Example: \"3ce1c679-7c43-4d37-89f6-757603379e31\"\n"
121
+ " - value (object, required): Value for the custom field. Example: {\"value\": \"08/21/2018\"}\n"
122
+ "*IMPORTANT*: Use double quotes for all field names and string values."))),
123
+ __base__=ProjectIssueStep
124
+ )
125
+
126
+ CreateNewTestStep = create_model(
127
+ "CreateNewTestStep",
128
+ json=(str, Field(description=(
129
+ "JSON body to create a Zephyr test step. Fields:\n"
130
+ "- step (string, required): Description of the test step. Example: \"Sample Test Step\"\n"
131
+ "- data (string, optional): Test data used in this step. Example: \"Sample Test Data\"\n"
132
+ "- result (string, optional): Expected result after executing the step. Example: \"Expected Test Result\"\n"
133
+ "*IMPORTANT*: Use double quotes for all field names and string values."))),
134
+ __base__=ProjectIssue
135
+ )
@@ -0,0 +1,79 @@
1
+ import hashlib
2
+ import time
3
+
4
+ import jwt
5
+ import requests
6
+ from langchain_core.tools import ToolException
7
+
8
+
9
+ class ZephyrSquadCloud(object):
10
+ """
11
+ Reference: https://zephyrsquad.docs.apiary.io//
12
+ """
13
+
14
+ def __init__(self, account_id, access_key, secret_key):
15
+ self.account_id = account_id
16
+ self.access_key = access_key
17
+ self.secret_key = secret_key
18
+ self.base_url = "https://prod-api.zephyr4jiracloud.com/connect"
19
+
20
+ def get_test_step(self, issue_id, step_id, project_id):
21
+ canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
22
+ api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
23
+ return self._do_request(method="GET", api_path=api_path, canonical_path=canonical_path)
24
+
25
+ def update_test_step(self, issue_id, step_id, project_id, json):
26
+ canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
27
+ api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
28
+ return self._do_request(method="PUT", api_path=api_path, canonical_path=canonical_path, json=json)
29
+
30
+ def delete_test_step(self, issue_id, step_id, project_id):
31
+ canonical_path = "/public/rest/api/1.0/teststep/issueId/id?projectId="
32
+ api_path = f"/public/rest/api/1.0/teststep/{issue_id}/{step_id}?projectId={project_id}"
33
+ return self._do_request(method="DELETE", api_path=api_path, canonical_path=canonical_path)
34
+
35
+ def create_new_test_step(self, issue_id, project_id, json):
36
+ canonical_path = "/public/rest/api/1.0/teststep/issueId?projectId="
37
+ api_path = f"/public/rest/api/1.0/teststep/{issue_id}?projectId={project_id}"
38
+ return self._do_request(method="POST", api_path=api_path, canonical_path=canonical_path, json=json)
39
+
40
+ def get_all_test_steps(self, issue_id, project_id):
41
+ canonical_path = "/public/rest/api/2.0/teststep/issueId?projectId="
42
+ api_path = f"/public/rest/api/2.0/teststep/{issue_id}?projectId={project_id}"
43
+ return self._do_request(method='GET', api_path=api_path, canonical_path=canonical_path)
44
+
45
+ def get_all_test_step_statuses(self):
46
+ api_path = "/public/rest/api/1.0/teststep/statuses"
47
+ return self._do_request(method='GET', api_path=api_path)
48
+
49
+ def _do_request(self, method, api_path, canonical_path=None, json=None):
50
+ url = f"{self.base_url}{api_path}"
51
+ headers = {
52
+ "Authorization": f"JWT {self._generate_jwt_token(method, canonical_path or api_path)}",
53
+ "zapiAccessKey": self.access_key,
54
+ "Content-Type": "application/json"
55
+ }
56
+
57
+ try:
58
+ resp = requests.request(method=method, url=url, json=json, headers=headers)
59
+
60
+ if resp.ok:
61
+ if resp.headers.get("Content-Type", "").startswith("application/json"):
62
+ return str(resp.json())
63
+ else:
64
+ return resp.text
65
+ else:
66
+ raise ToolException(f"Request failed with status {resp.status_code}: {resp.text}")
67
+ except Exception as e:
68
+ raise ToolException(f"Error performing request {method}:{api_path}: {e}")
69
+
70
+ def _generate_jwt_token(self, method, path):
71
+ canonical_path = f"{method}&{path}&"
72
+ payload_token = {
73
+ 'sub': self.account_id,
74
+ 'qsh': hashlib.sha256(canonical_path.encode('utf-8')).hexdigest(),
75
+ 'iss': self.access_key,
76
+ 'exp': int(time.time()) + 3600,
77
+ 'iat': int(time.time())
78
+ }
79
+ return jwt.encode(payload_token, self.secret_key, algorithm='HS256').strip()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.162
3
+ Version: 0.3.163
4
4
  Summary: SDK for building langchain agents using resources from Alita
5
5
  Author-email: Artem Rozumenko <artyom.rozumenko@gmail.com>, Mikalai Biazruchka <mikalai_biazruchka@epam.com>, Roman Mitusov <roman_mitusov@epam.com>, Ivan Krakhmaliuk <lifedjik@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -129,7 +129,7 @@ alita_sdk/runtime/utils/logging.py,sha256=svPyiW8ztDfhqHFITv5FBCj8UhLxz6hWcqGIY6
129
129
  alita_sdk/runtime/utils/save_dataframe.py,sha256=i-E1wp-t4wb17Zq3nA3xYwgSILjoXNizaQAA9opWvxY,1576
130
130
  alita_sdk/runtime/utils/streamlit.py,sha256=z4J_bdxkA0zMROkvTB4u379YBRFCkKh-h7PD8RlnZWQ,85644
131
131
  alita_sdk/runtime/utils/utils.py,sha256=dM8whOJAuFJFe19qJ69-FLzrUp6d2G-G6L7d4ss2XqM,346
132
- alita_sdk/tools/__init__.py,sha256=qsF21SiBa7P5gcWybCLP4K3xqA34LW9TVuM1QKaU-xc,9716
132
+ alita_sdk/tools/__init__.py,sha256=Ttjp6AVkjuh-WqGE_cc_nUwi4qvU1khf7_BVKdwO7gU,9801
133
133
  alita_sdk/tools/elitea_base.py,sha256=NQaIxPX6DVIerHCb18jwUR6maZxxk73NZaTsFHkBQWE,21119
134
134
  alita_sdk/tools/ado/__init__.py,sha256=mD6GHcYMTtffPJkJvFPe2rzvye_IRmXmWfI7xYuZhO4,912
135
135
  alita_sdk/tools/ado/utils.py,sha256=PTCludvaQmPLakF2EbCGy66Mro4-rjDtavVP-xcB2Wc,1252
@@ -160,14 +160,20 @@ alita_sdk/tools/browser/google_search_rag.py,sha256=QVHFbVwymiJGuno_HLSJOK1c_Mpg
160
160
  alita_sdk/tools/browser/utils.py,sha256=4k3YM_f1Kqlhjz9vt2pNsGkvCjhy-EmY3nvcwdFCsLA,2501
161
161
  alita_sdk/tools/browser/wiki.py,sha256=Qh3HBFd4dkS2VavXbFJOm4b8SjVSIe5xSD7CY1vEkKE,1126
162
162
  alita_sdk/tools/carrier/__init__.py,sha256=pP-nk-dpqOkrvwcRY_szgwqoowyVNl_GobD4Inp-Qus,4435
163
- alita_sdk/tools/carrier/api_wrapper.py,sha256=Ns0lGbtGKRGBTdOWseWtz4heyY3hP4AcnB9QEx_d5JU,5344
163
+ alita_sdk/tools/carrier/api_wrapper.py,sha256=smcc1Q7H6U1_18qDYBFpeGnu5cX3OrsUoKaSn3s6vkw,8728
164
164
  alita_sdk/tools/carrier/backend_reports_tool.py,sha256=WNZVGBIZusakOdbd7lG6o6xL180VZfER-uDw_SSGupo,11005
165
165
  alita_sdk/tools/carrier/backend_tests_tool.py,sha256=arq275qiP9t3ST-MPn7FlxbLLSPiIGEnyPdgJ-AvOoQ,5917
166
- alita_sdk/tools/carrier/carrier_sdk.py,sha256=1QXbO3BrIYaZFd30GZzATXw9Wfh8ga7CfmUihD9ueks,9709
166
+ alita_sdk/tools/carrier/cancel_ui_test_tool.py,sha256=pD1sKEcZGBWJqFpgjeohMk93uuUPWruVJRPVVg90rpo,6438
167
+ alita_sdk/tools/carrier/carrier_sdk.py,sha256=sYdPWcpH8ti0MggOvU2pbsKYiaKR1zuXlbiCtcTfc3A,12913
168
+ alita_sdk/tools/carrier/create_ui_excel_report_tool.py,sha256=sYAz54ILk8CIF_n76zH_hcmbW9xw7oTNnf_d9d-N-_Q,20171
169
+ alita_sdk/tools/carrier/create_ui_test_tool.py,sha256=sHi7-D1uqIUHEyoywI92h6MdUVybKfBXs_XttTu-Ck4,8624
167
170
  alita_sdk/tools/carrier/excel_reporter.py,sha256=fXptz7iaBDBcFSc8Ah8nZ9CSgugTONc5JMC1XcQEnfM,21487
171
+ alita_sdk/tools/carrier/lighthouse_excel_reporter.py,sha256=mVuU63tl2n-Gntx9RuedjEU0U5AP1APKsSx1DvJs7wk,6684
172
+ alita_sdk/tools/carrier/run_ui_test_tool.py,sha256=vmEtP-cpnOCyLLZfbw9Nq2ItGUFlcnsf1LmI_XyLrM8,21053
168
173
  alita_sdk/tools/carrier/tickets_tool.py,sha256=d-wFyFWWTvV01o-hyssb2S-oLnr51b6tlNTUqA_CohY,8099
169
- alita_sdk/tools/carrier/tools.py,sha256=GeV5KtB3kfMygQ9y-z2Mgk2x0A2pg0SRoZkev3Dqx-M,996
170
- alita_sdk/tools/carrier/ui_reports_tool.py,sha256=haOZuGWYsLg2rj_dO1zaPpUmj77Rxjs8e4LyTaqeV1E,13525
174
+ alita_sdk/tools/carrier/tools.py,sha256=cCLYcNzC_z0-AaqB46fyt7iOeP20LStVQKI5Dg1zWA4,1588
175
+ alita_sdk/tools/carrier/ui_reports_tool.py,sha256=Y6EstTRCa9d11ipFUFGOYlpiEhFx7aOQcgZ_M5Gd1lQ,13708
176
+ alita_sdk/tools/carrier/update_ui_test_schedule_tool.py,sha256=jh9Q86cMCEqpsFopJPNIP0wlr7sYVa_3lhlq6lRmkGg,11850
171
177
  alita_sdk/tools/carrier/utils.py,sha256=rl7aq-F6ed_PapDM15w8EtS0BkgsjpDrNdKYuDCMOaI,4376
172
178
  alita_sdk/tools/chunkers/__init__.py,sha256=myaBVvPbUsz6PXtBDpA4EiPQgLvIv3q_WPh86kxlccI,774
173
179
  alita_sdk/tools/chunkers/models.py,sha256=NNkLSljZboYDj6vbqeHmcjj9JrTHbkVWmoHGsL98q3k,3032
@@ -317,8 +323,11 @@ alita_sdk/tools/zephyr_enterprise/api_wrapper.py,sha256=Ir3zHljhbZQJRJJQOBzS_GL5
317
323
  alita_sdk/tools/zephyr_enterprise/zephyr_enterprise.py,sha256=hV9LIrYfJT6oYp-ZfQR0YHflqBFPsUw2Oc55HwK0H48,6809
318
324
  alita_sdk/tools/zephyr_scale/__init__.py,sha256=2NTcdrfkx4GSegqyXhsPLsEpc4FlACuDy85b0fk6cAo,4572
319
325
  alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=UHVQUVqcBc3SZvDfO78HSuBzwAsRw2cCDQa-xMOzndE,68663
320
- alita_sdk-0.3.162.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
321
- alita_sdk-0.3.162.dist-info/METADATA,sha256=rOXYxNG9XRAmQ1BhPz2Fkb3CRmq-I_oaG3atjj67JBg,18667
322
- alita_sdk-0.3.162.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
323
- alita_sdk-0.3.162.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
324
- alita_sdk-0.3.162.dist-info/RECORD,,
326
+ alita_sdk/tools/zephyr_squad/__init__.py,sha256=rq4jOb3lRW2GXvAguk4H1KinO5f-zpygzhBJf-E1Ucw,2773
327
+ alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=iOMxyE7vOc_LwFB_nBMiSFXkNtvbptA4i-BrTlo7M0A,5854
328
+ alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=IYUJoMFOMA70knLhLtAnuGoy3OK80RuqeQZ710oyIxE,3631
329
+ alita_sdk-0.3.163.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
330
+ alita_sdk-0.3.163.dist-info/METADATA,sha256=3Fd8T3ods52lKrlnTjGDxEAn_svB00x64xg65cCi8rY,18667
331
+ alita_sdk-0.3.163.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
332
+ alita_sdk-0.3.163.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
333
+ alita_sdk-0.3.163.dist-info/RECORD,,