alita-sdk 0.3.355__py3-none-any.whl → 0.3.357__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.
Potentially problematic release.
This version of alita-sdk might be problematic. Click here for more details.
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +41 -12
- alita_sdk/runtime/langchain/document_loaders/constants.py +3 -1
- alita_sdk/runtime/langchain/langraph_agent.py +1 -0
- alita_sdk/runtime/langchain/utils.py +1 -1
- alita_sdk/runtime/toolkits/artifact.py +8 -1
- alita_sdk/tools/base_indexer_toolkit.py +7 -2
- alita_sdk/tools/figma/api_wrapper.py +2 -1
- alita_sdk/tools/gitlab/api_wrapper.py +40 -22
- alita_sdk/tools/postman/api_wrapper.py +3 -2
- alita_sdk/tools/qtest/api_wrapper.py +37 -2
- alita_sdk/tools/utils/content_parser.py +1 -1
- {alita_sdk-0.3.355.dist-info → alita_sdk-0.3.357.dist-info}/METADATA +1 -1
- {alita_sdk-0.3.355.dist-info → alita_sdk-0.3.357.dist-info}/RECORD +16 -16
- {alita_sdk-0.3.355.dist-info → alita_sdk-0.3.357.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.355.dist-info → alita_sdk-0.3.357.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.355.dist-info → alita_sdk-0.3.357.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import io
|
|
2
2
|
|
|
3
|
-
from langchain_community.document_loaders import UnstructuredPowerPointLoader
|
|
4
3
|
from langchain_core.tools import ToolException
|
|
5
4
|
from pptx import Presentation
|
|
6
5
|
from .utils import perform_llm_prediction_for_image_bytes, create_temp_file
|
|
7
6
|
from pptx.enum.shapes import MSO_SHAPE_TYPE
|
|
7
|
+
from langchain_core.documents import Document
|
|
8
8
|
|
|
9
9
|
class AlitaPowerPointLoader:
|
|
10
10
|
|
|
@@ -22,16 +22,26 @@ class AlitaPowerPointLoader:
|
|
|
22
22
|
self.extract_images = unstructured_kwargs.get('extract_images', False)
|
|
23
23
|
self.llm = unstructured_kwargs.get('llm', None)
|
|
24
24
|
self.prompt = unstructured_kwargs.get('prompt', "Describe image")
|
|
25
|
+
self.pages_per_chunk = unstructured_kwargs.get('pages_per_chunk', 5)
|
|
25
26
|
|
|
26
27
|
def get_content(self):
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
if hasattr(self, 'file_path'):
|
|
29
|
+
with open(self.file_path, 'rb') as f:
|
|
30
|
+
prs = Presentation(f)
|
|
31
|
+
elif hasattr(self, 'file_content'):
|
|
32
|
+
prs = Presentation(io.BytesIO(self.file_content))
|
|
33
|
+
pages = []
|
|
29
34
|
if self.page_number is not None:
|
|
30
|
-
|
|
35
|
+
pages.append(self.read_pptx_slide(prs.slides[self.page_number - 1], self.page_number))
|
|
31
36
|
else:
|
|
32
37
|
for index, slide in enumerate(prs.slides, start=1):
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
pages.append(self.read_pptx_slide(slide, index))
|
|
39
|
+
if self.mode == 'single':
|
|
40
|
+
return "\n".join(pages)
|
|
41
|
+
if self.mode == 'paged':
|
|
42
|
+
return pages
|
|
43
|
+
else:
|
|
44
|
+
raise ToolException(f"Unknown mode value: {self.mode}. Only 'single', 'paged' values allowed.")
|
|
35
45
|
|
|
36
46
|
def read_pptx_slide(self, slide, index):
|
|
37
47
|
text_content = f'Slide: {index}\n'
|
|
@@ -48,15 +58,34 @@ class AlitaPowerPointLoader:
|
|
|
48
58
|
text_content += "\n"
|
|
49
59
|
elif self.extract_images and shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
|
|
50
60
|
try:
|
|
51
|
-
caption = perform_llm_prediction_for_image_bytes(shape.image.blob, self.llm)
|
|
61
|
+
caption = perform_llm_prediction_for_image_bytes(shape.image.blob, self.llm, self.prompt)
|
|
52
62
|
except:
|
|
53
63
|
caption = "unknown"
|
|
54
64
|
text_content += "\n**Image Transcript:**\n" + caption + "\n--------------------\n"
|
|
55
65
|
return text_content + "\n"
|
|
56
66
|
|
|
57
67
|
def load(self):
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
content = self.get_content()
|
|
69
|
+
if isinstance(content, str):
|
|
70
|
+
yield Document(page_content=content, metadata={})
|
|
71
|
+
elif isinstance(content, list):
|
|
72
|
+
chunk = []
|
|
73
|
+
chunk_count = 0
|
|
74
|
+
for page_number, page in enumerate(content, start=1):
|
|
75
|
+
chunk.append(page)
|
|
76
|
+
if len(chunk) == self.pages_per_chunk:
|
|
77
|
+
chunk_content = "\n".join(chunk)
|
|
78
|
+
yield Document(
|
|
79
|
+
page_content=chunk_content,
|
|
80
|
+
metadata={"chunk_number": chunk_count + 1,
|
|
81
|
+
"pages_in_chunk": list(range(page_number - len(chunk) + 1, page_number + 1))}
|
|
82
|
+
)
|
|
83
|
+
chunk = []
|
|
84
|
+
chunk_count += 1
|
|
85
|
+
if chunk:
|
|
86
|
+
chunk_content = "\n".join(chunk)
|
|
87
|
+
yield Document(
|
|
88
|
+
page_content=chunk_content,
|
|
89
|
+
metadata={"chunk_number": chunk_count + 1,
|
|
90
|
+
"pages_in_chunk": list(range(len(content) - len(chunk) + 1, len(content) + 1))}
|
|
91
|
+
)
|
|
@@ -288,7 +288,9 @@ document_loaders_map = {
|
|
|
288
288
|
'allowed_to_override': [
|
|
289
289
|
'max_tokens', 'mode', LoaderProperties.LLM.value,
|
|
290
290
|
LoaderProperties.PROMPT.value,
|
|
291
|
-
LoaderProperties.PROMPT_DEFAULT.value
|
|
291
|
+
LoaderProperties.PROMPT_DEFAULT.value,
|
|
292
|
+
"pages_per_chunk",
|
|
293
|
+
"extract_images"
|
|
292
294
|
]
|
|
293
295
|
},
|
|
294
296
|
'.py': {
|
|
@@ -138,7 +138,7 @@ def create_state(data: Optional[dict] = None):
|
|
|
138
138
|
value = value['type'] if isinstance(value, dict) else value
|
|
139
139
|
if key == 'messages':
|
|
140
140
|
state_dict[key] = Annotated[list[AnyMessage], add_messages]
|
|
141
|
-
elif value in ['str', 'int', 'float', 'bool', 'list', 'dict', 'number']:
|
|
141
|
+
elif value in ['str', 'int', 'float', 'bool', 'list', 'dict', 'number', 'dict']:
|
|
142
142
|
state_dict[key] = parse_type(value)
|
|
143
143
|
logger.debug(f"Created state: {state_dict}")
|
|
144
144
|
return TypedDict('State', state_dict)
|
|
@@ -21,7 +21,14 @@ class ArtifactToolkit(BaseToolkit):
|
|
|
21
21
|
return create_model(
|
|
22
22
|
"artifact",
|
|
23
23
|
# client = (Any, FieldInfo(description="Client object", required=True, autopopulate=True)),
|
|
24
|
-
bucket
|
|
24
|
+
bucket=(str, FieldInfo(
|
|
25
|
+
description="Bucket name",
|
|
26
|
+
pattern=r'^[a-z][a-z0-9-]*$',
|
|
27
|
+
json_schema_extra={
|
|
28
|
+
'toolkit_name': True,
|
|
29
|
+
'max_toolkit_length': ArtifactToolkit.toolkit_max_length
|
|
30
|
+
}
|
|
31
|
+
)),
|
|
25
32
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
26
33
|
# indexer settings
|
|
27
34
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None, description="PgVector Configuration", json_schema_extra={'configuration_types': ['pgvector']})),
|
|
@@ -155,7 +155,7 @@ class BaseIndexerToolkit(VectorStoreWrapperBase):
|
|
|
155
155
|
#
|
|
156
156
|
if clean_index:
|
|
157
157
|
self._clean_index(collection_suffix)
|
|
158
|
-
#
|
|
158
|
+
#
|
|
159
159
|
self._log_tool_event(f"Indexing data into collection with suffix '{collection_suffix}'. It can take some time...")
|
|
160
160
|
self._log_tool_event(f"Loading the documents to index...{kwargs}")
|
|
161
161
|
documents = self._base_loader(**kwargs)
|
|
@@ -191,7 +191,7 @@ class BaseIndexerToolkit(VectorStoreWrapperBase):
|
|
|
191
191
|
logger.debug(f"Indexing base document #{base_doc_counter}: {base_doc} and all dependent documents: {documents}")
|
|
192
192
|
|
|
193
193
|
dependent_docs_counter = 0
|
|
194
|
-
#
|
|
194
|
+
#
|
|
195
195
|
for doc in documents:
|
|
196
196
|
if not doc.page_content:
|
|
197
197
|
# To avoid case when all documents have empty content
|
|
@@ -357,6 +357,11 @@ class BaseIndexerToolkit(VectorStoreWrapperBase):
|
|
|
357
357
|
**kwargs):
|
|
358
358
|
""" Searches indexed documents in the vector store."""
|
|
359
359
|
# build filter on top of collection_suffix
|
|
360
|
+
|
|
361
|
+
available_collections = super().list_collections()
|
|
362
|
+
if collection_suffix and collection_suffix not in available_collections:
|
|
363
|
+
return f"Collection '{collection_suffix}' not found. Available collections: {available_collections}"
|
|
364
|
+
|
|
360
365
|
filter = self._build_collection_filter(filter, collection_suffix)
|
|
361
366
|
found_docs = super().search_documents(
|
|
362
367
|
query,
|
|
@@ -345,7 +345,8 @@ class FigmaApiWrapper(NonCodeIndexerToolkit):
|
|
|
345
345
|
text_nodes[node['id']] = self.get_texts_recursive(node)
|
|
346
346
|
# process image nodes
|
|
347
347
|
if image_nodes:
|
|
348
|
-
|
|
348
|
+
file_images = self._client.get_file_images(file_key, image_nodes)
|
|
349
|
+
images = self._client.get_file_images(file_key, image_nodes).images or {} if file_images else {}
|
|
349
350
|
total_images = len(images)
|
|
350
351
|
if total_images == 0:
|
|
351
352
|
logging.info(f"No images found for file {file_key}.")
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
from typing import Any, Dict, List, Optional
|
|
3
3
|
import fnmatch
|
|
4
4
|
|
|
5
|
+
from langchain_core.tools import ToolException
|
|
6
|
+
|
|
5
7
|
from ..code_indexer_toolkit import CodeIndexerToolkit
|
|
6
8
|
from pydantic import create_model, Field, model_validator, SecretStr, PrivateAttr
|
|
7
9
|
|
|
@@ -106,9 +108,13 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
106
108
|
private_token: SecretStr
|
|
107
109
|
branch: Optional[str] = 'main'
|
|
108
110
|
_git: Any = PrivateAttr()
|
|
109
|
-
_repo_instance: Any = PrivateAttr()
|
|
110
111
|
_active_branch: Any = PrivateAttr()
|
|
111
112
|
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _sanitize_url(url: str) -> str:
|
|
115
|
+
"""Remove trailing slash from URL if present."""
|
|
116
|
+
return url.rstrip('/') if url else url
|
|
117
|
+
|
|
112
118
|
@model_validator(mode='before')
|
|
113
119
|
@classmethod
|
|
114
120
|
def validate_toolkit(cls, values: Dict) -> Dict:
|
|
@@ -119,22 +125,34 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
119
125
|
"python-gitlab is not installed. "
|
|
120
126
|
"Please install it with `pip install python-gitlab`"
|
|
121
127
|
)
|
|
122
|
-
|
|
128
|
+
values['repository'] = cls._sanitize_url(values['repository'])
|
|
123
129
|
g = gitlab.Gitlab(
|
|
124
|
-
url=values['url'],
|
|
130
|
+
url=cls._sanitize_url(values['url']),
|
|
125
131
|
private_token=values['private_token'],
|
|
126
132
|
keep_base_url=True,
|
|
127
133
|
)
|
|
128
134
|
|
|
129
135
|
g.auth()
|
|
130
|
-
cls._repo_instance = g.projects.get(values.get('repository'))
|
|
131
136
|
cls._git = g
|
|
132
137
|
cls._active_branch = values.get('branch')
|
|
133
138
|
return super().validate_toolkit(values)
|
|
134
139
|
|
|
140
|
+
@property
|
|
141
|
+
def repo_instance(self):
|
|
142
|
+
if not hasattr(self, "_repo_instance") or self._repo_instance is None:
|
|
143
|
+
try:
|
|
144
|
+
if self._git and self.repository:
|
|
145
|
+
self._repo_instance = self._git.projects.get(self.repository)
|
|
146
|
+
else:
|
|
147
|
+
self._repo_instance = None
|
|
148
|
+
except Exception as e:
|
|
149
|
+
# Only raise when accessed, not during initialization
|
|
150
|
+
raise ToolException(e)
|
|
151
|
+
return self._repo_instance
|
|
152
|
+
|
|
135
153
|
def set_active_branch(self, branch_name: str) -> str:
|
|
136
154
|
self._active_branch = branch_name
|
|
137
|
-
self.
|
|
155
|
+
self.repo_instance.default_branch = branch_name
|
|
138
156
|
return f"Active branch set to {branch_name}"
|
|
139
157
|
|
|
140
158
|
def list_branches_in_repo(self, limit: Optional[int] = 20, branch_wildcard: Optional[str] = None) -> List[str]:
|
|
@@ -149,7 +167,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
149
167
|
List[str]: List containing names of branches
|
|
150
168
|
"""
|
|
151
169
|
try:
|
|
152
|
-
branches = self.
|
|
170
|
+
branches = self.repo_instance.branches.list(get_all=True)
|
|
153
171
|
|
|
154
172
|
if branch_wildcard:
|
|
155
173
|
branches = [branch for branch in branches if fnmatch.fnmatch(branch.name, branch_wildcard)]
|
|
@@ -176,7 +194,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
176
194
|
|
|
177
195
|
def _get_all_files(self, path: str = None, recursive: bool = True, branch: str = None):
|
|
178
196
|
branch = branch if branch else self._active_branch
|
|
179
|
-
return self.
|
|
197
|
+
return self.repo_instance.repository_tree(path=path, ref=branch, recursive=recursive, all=True)
|
|
180
198
|
|
|
181
199
|
# overrided for indexer
|
|
182
200
|
def _get_files(self, path: str = None, recursive: bool = True, branch: str = None):
|
|
@@ -188,7 +206,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
188
206
|
Get the commit hash of a file in a specific branch.
|
|
189
207
|
"""
|
|
190
208
|
try:
|
|
191
|
-
file = self.
|
|
209
|
+
file = self.repo_instance.files.get(file_path, branch)
|
|
192
210
|
return file.commit_id
|
|
193
211
|
except Exception as e:
|
|
194
212
|
return f"Unable to get commit hash for {file_path} due to error:\n{e}"
|
|
@@ -198,7 +216,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
198
216
|
|
|
199
217
|
def create_branch(self, branch_name: str) -> str:
|
|
200
218
|
try:
|
|
201
|
-
self.
|
|
219
|
+
self.repo_instance.branches.create(
|
|
202
220
|
{
|
|
203
221
|
'branch': branch_name,
|
|
204
222
|
'ref': self._active_branch,
|
|
@@ -221,7 +239,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
221
239
|
return parsed
|
|
222
240
|
|
|
223
241
|
def get_issues(self) -> str:
|
|
224
|
-
issues = self.
|
|
242
|
+
issues = self.repo_instance.issues.list(state="opened")
|
|
225
243
|
if len(issues) > 0:
|
|
226
244
|
parsed_issues = self.parse_issues(issues)
|
|
227
245
|
parsed_issues_str = (
|
|
@@ -232,7 +250,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
232
250
|
return "No open issues available"
|
|
233
251
|
|
|
234
252
|
def get_issue(self, issue_number: int) -> Dict[str, Any]:
|
|
235
|
-
issue = self.
|
|
253
|
+
issue = self.repo_instance.issues.get(issue_number)
|
|
236
254
|
page = 0
|
|
237
255
|
comments: List[dict] = []
|
|
238
256
|
while len(comments) <= 10:
|
|
@@ -258,7 +276,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
258
276
|
commits are already in the {self.branch} branch"""
|
|
259
277
|
else:
|
|
260
278
|
try:
|
|
261
|
-
pr = self.
|
|
279
|
+
pr = self.repo_instance.mergerequests.create(
|
|
262
280
|
{
|
|
263
281
|
"source_branch": branch,
|
|
264
282
|
"target_branch": self.branch,
|
|
@@ -275,7 +293,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
275
293
|
issue_number = int(comment_query.split("\n\n")[0])
|
|
276
294
|
comment = comment_query[len(str(issue_number)) + 2 :]
|
|
277
295
|
try:
|
|
278
|
-
issue = self.
|
|
296
|
+
issue = self.repo_instance.issues.get(issue_number)
|
|
279
297
|
issue.notes.create({"body": comment})
|
|
280
298
|
return "Commented on issue " + str(issue_number)
|
|
281
299
|
except Exception as e:
|
|
@@ -284,7 +302,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
284
302
|
def create_file(self, file_path: str, file_contents: str, branch: str) -> str:
|
|
285
303
|
try:
|
|
286
304
|
self.set_active_branch(branch)
|
|
287
|
-
self.
|
|
305
|
+
self.repo_instance.files.get(file_path, branch)
|
|
288
306
|
return f"File already exists at {file_path}. Use update_file instead"
|
|
289
307
|
except Exception:
|
|
290
308
|
data = {
|
|
@@ -293,13 +311,13 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
293
311
|
"file_path": file_path,
|
|
294
312
|
"content": file_contents,
|
|
295
313
|
}
|
|
296
|
-
self.
|
|
314
|
+
self.repo_instance.files.create(data)
|
|
297
315
|
|
|
298
316
|
return "Created file " + file_path
|
|
299
317
|
|
|
300
318
|
def read_file(self, file_path: str, branch: str) -> str:
|
|
301
319
|
self.set_active_branch(branch)
|
|
302
|
-
file = self.
|
|
320
|
+
file = self.repo_instance.files.get(file_path, branch)
|
|
303
321
|
return file.decode().decode("utf-8")
|
|
304
322
|
|
|
305
323
|
def update_file(self, file_query: str, branch: str) -> str:
|
|
@@ -338,7 +356,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
338
356
|
],
|
|
339
357
|
}
|
|
340
358
|
|
|
341
|
-
self.
|
|
359
|
+
self.repo_instance.commits.create(commit)
|
|
342
360
|
return "Updated file " + file_path
|
|
343
361
|
except Exception as e:
|
|
344
362
|
return "Unable to update file due to error:\n" + str(e)
|
|
@@ -368,7 +386,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
368
386
|
],
|
|
369
387
|
}
|
|
370
388
|
|
|
371
|
-
self.
|
|
389
|
+
self.repo_instance.commits.create(commit)
|
|
372
390
|
return "Updated file " + file_path
|
|
373
391
|
except Exception as e:
|
|
374
392
|
return "Unable to update file due to error:\n" + str(e)
|
|
@@ -378,20 +396,20 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
378
396
|
self.set_active_branch(branch)
|
|
379
397
|
if not commit_message:
|
|
380
398
|
commit_message = f"Delete {file_path}"
|
|
381
|
-
self.
|
|
399
|
+
self.repo_instance.files.delete(file_path, branch, commit_message)
|
|
382
400
|
return f"Deleted file {file_path}"
|
|
383
401
|
except Exception as e:
|
|
384
402
|
return f"Unable to delete file due to error:\n{e}"
|
|
385
403
|
|
|
386
404
|
def get_pr_changes(self, pr_number: int) -> str:
|
|
387
|
-
mr = self.
|
|
405
|
+
mr = self.repo_instance.mergerequests.get(pr_number)
|
|
388
406
|
res = f"title: {mr.title}\ndescription: {mr.description}\n\n"
|
|
389
407
|
for change in mr.changes()["changes"]:
|
|
390
408
|
res += f"diff --git a/{change['old_path']} b/{change['new_path']}\n{change['diff']}\n"
|
|
391
409
|
return res
|
|
392
410
|
|
|
393
411
|
def create_pr_change_comment(self, pr_number: int, file_path: str, line_number: int, comment: str) -> str:
|
|
394
|
-
mr = self.
|
|
412
|
+
mr = self.repo_instance.mergerequests.get(pr_number)
|
|
395
413
|
position = {"position_type": "text", "new_path": file_path, "new_line": line_number}
|
|
396
414
|
mr.discussions.create({"body": comment, "position": position})
|
|
397
415
|
return "Comment added"
|
|
@@ -408,7 +426,7 @@ class GitLabAPIWrapper(CodeIndexerToolkit):
|
|
|
408
426
|
params["until"] = until
|
|
409
427
|
if author:
|
|
410
428
|
params["author"] = author
|
|
411
|
-
commits = self.
|
|
429
|
+
commits = self.repo_instance.commits.list(**params)
|
|
412
430
|
return [
|
|
413
431
|
{
|
|
414
432
|
"sha": commit.id,
|
|
@@ -760,8 +760,9 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
760
760
|
import re
|
|
761
761
|
def replace_var(match):
|
|
762
762
|
var_name = match.group(1)
|
|
763
|
-
|
|
764
|
-
|
|
763
|
+
value = all_variables.get(var_name, match.group(0))
|
|
764
|
+
return resolve_variables(value) if isinstance(value, str) else value
|
|
765
|
+
|
|
765
766
|
return re.sub(r'\{\{([^}]+)\}\}', replace_var, text)
|
|
766
767
|
|
|
767
768
|
# Prepare the request
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
from traceback import format_exc
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Optional
|
|
5
5
|
|
|
6
6
|
import swagger_client
|
|
7
7
|
from langchain_core.tools import ToolException
|
|
8
8
|
from pydantic import Field, PrivateAttr, model_validator, create_model, SecretStr
|
|
9
9
|
from sklearn.feature_extraction.text import strip_tags
|
|
10
|
-
from swagger_client import TestCaseApi, SearchApi, PropertyResource
|
|
10
|
+
from swagger_client import TestCaseApi, SearchApi, PropertyResource, ModuleApi
|
|
11
11
|
from swagger_client.rest import ApiException
|
|
12
12
|
|
|
13
13
|
from ..elitea_base import BaseToolApiWrapper
|
|
@@ -99,6 +99,17 @@ DeleteTestCase = create_model(
|
|
|
99
99
|
qtest_id=(int, Field(description="Qtest id e.g. 3253490123")),
|
|
100
100
|
)
|
|
101
101
|
|
|
102
|
+
GetModules = create_model(
|
|
103
|
+
"GetModules",
|
|
104
|
+
parent_id=(Optional[int],
|
|
105
|
+
Field(description="ID of the parent Module. Leave it blank to retrieve Modules under root",
|
|
106
|
+
default=None)),
|
|
107
|
+
search=(Optional[str],
|
|
108
|
+
Field(description="The free-text to search for Modules by names. You can utilize this parameter to search for Modules. Leave it blank to retrieve all Modules under root or the parent Module",
|
|
109
|
+
default=None)),
|
|
110
|
+
|
|
111
|
+
)
|
|
112
|
+
|
|
102
113
|
class QtestApiWrapper(BaseToolApiWrapper):
|
|
103
114
|
base_url: str
|
|
104
115
|
qtest_project_id: int
|
|
@@ -140,6 +151,9 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
140
151
|
# Instantiate the TestCaseApi instance according to the qtest api documentation and swagger client
|
|
141
152
|
return swagger_client.TestCaseApi(self._client)
|
|
142
153
|
|
|
154
|
+
def __instantiate_module_api_instance(self) -> ModuleApi:
|
|
155
|
+
return swagger_client.ModuleApi(self._client)
|
|
156
|
+
|
|
143
157
|
def __build_body_for_create_test_case(self, test_cases_data: list[dict],
|
|
144
158
|
folder_to_place_test_cases_to: str = '') -> list:
|
|
145
159
|
initial_project_properties = self.__get_properties_form_project()
|
|
@@ -401,6 +415,20 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
401
415
|
raise ToolException(
|
|
402
416
|
f"""Unable to delete test case in project with id - {self.qtest_project_id} and qtest_id - {qtest_id}. \n Exception: \n {stacktrace}""") from e
|
|
403
417
|
|
|
418
|
+
def get_modules(self, parent_id: int = None, search: str = None):
|
|
419
|
+
"""
|
|
420
|
+
:param int project_id: ID of the project (required)
|
|
421
|
+
:param int parent_id: ID of the parent Module. Leave it blank to retrieve Modules under root
|
|
422
|
+
:param str search: The free-text to search for Modules by names. You can utilize this parameter to search for Modules. Leave it blank to retrieve all Modules under root or the parent Module
|
|
423
|
+
"""
|
|
424
|
+
module_api = self.__instantiate_module_api_instance()
|
|
425
|
+
kwargs = {}
|
|
426
|
+
if parent_id:
|
|
427
|
+
kwargs["parent_id"] = parent_id
|
|
428
|
+
if search:
|
|
429
|
+
kwargs["search"] = search
|
|
430
|
+
return module_api.get_sub_modules_of(project_id=self.qtest_project_id, **kwargs)
|
|
431
|
+
|
|
404
432
|
def get_available_tools(self):
|
|
405
433
|
return [
|
|
406
434
|
{
|
|
@@ -444,5 +472,12 @@ class QtestApiWrapper(BaseToolApiWrapper):
|
|
|
444
472
|
"description": """Link tests to Jira requirements. The input is jira issue id and th list of test ids in format '["TC-123", "TC-234", "TC-345"]'""",
|
|
445
473
|
"args_schema": QtestLinkTestCaseToJiraRequirement,
|
|
446
474
|
"ref": self.link_tests_to_jira_requirement,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"name": "get_modules",
|
|
478
|
+
"mode": "get_modules",
|
|
479
|
+
"description": self.get_modules.__doc__,
|
|
480
|
+
"args_schema": GetModules,
|
|
481
|
+
"ref": self.get_modules,
|
|
447
482
|
}
|
|
448
483
|
]
|
|
@@ -270,7 +270,7 @@ def process_content_by_type(content, filename: str, llm=None, chunking_config=No
|
|
|
270
270
|
loader_kwargs.pop(LoaderProperties.PROMPT_DEFAULT.value)
|
|
271
271
|
loader_kwargs[LoaderProperties.PROMPT.value] = image_processing_prompt
|
|
272
272
|
loader = loader_cls(file_path=temp_file_path, **loader_kwargs)
|
|
273
|
-
|
|
273
|
+
yield from loader.load()
|
|
274
274
|
finally:
|
|
275
275
|
if temp_file_path and os.path.exists(temp_file_path):
|
|
276
276
|
os.remove(temp_file_path)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: alita_sdk
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.357
|
|
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 <lifedj27@gmail.com>, Artem Dubrovskiy <ad13box@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -44,11 +44,11 @@ alita_sdk/runtime/langchain/assistant.py,sha256=lF46zxtEg8Tnims5gm-24jvjvUoJ28GB
|
|
|
44
44
|
alita_sdk/runtime/langchain/chat_message_template.py,sha256=kPz8W2BG6IMyITFDA5oeb5BxVRkHEVZhuiGl4MBZKdc,2176
|
|
45
45
|
alita_sdk/runtime/langchain/constants.py,sha256=eHVJ_beJNTf1WJo4yq7KMK64fxsRvs3lKc34QCXSbpk,3319
|
|
46
46
|
alita_sdk/runtime/langchain/indexer.py,sha256=0ENHy5EOhThnAiYFc7QAsaTNp9rr8hDV_hTK8ahbatk,37592
|
|
47
|
-
alita_sdk/runtime/langchain/langraph_agent.py,sha256=
|
|
47
|
+
alita_sdk/runtime/langchain/langraph_agent.py,sha256=OAxSJ8tWLRQsPfUHHt94ubGFTgY_Hc08y-EaQ-Lpwfs,47353
|
|
48
48
|
alita_sdk/runtime/langchain/mixedAgentParser.py,sha256=M256lvtsL3YtYflBCEp-rWKrKtcY1dJIyRGVv7KW9ME,2611
|
|
49
49
|
alita_sdk/runtime/langchain/mixedAgentRenderes.py,sha256=asBtKqm88QhZRILditjYICwFVKF5KfO38hu2O-WrSWE,5964
|
|
50
50
|
alita_sdk/runtime/langchain/store_manager.py,sha256=i8Fl11IXJhrBXq1F1ukEVln57B1IBe-tqSUvfUmBV4A,2218
|
|
51
|
-
alita_sdk/runtime/langchain/utils.py,sha256=
|
|
51
|
+
alita_sdk/runtime/langchain/utils.py,sha256=fbtp6ZQcaRETEKAxuky_FJ0QqnXkWs3xVCDfjyTnwtw,6750
|
|
52
52
|
alita_sdk/runtime/langchain/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
53
53
|
alita_sdk/runtime/langchain/agents/xml_chat.py,sha256=Mx7PK5T97_GrFCwHHZ3JZP42S7MwtUzV0W-_8j6Amt8,6212
|
|
54
54
|
alita_sdk/runtime/langchain/document_loaders/AlitaBDDScenariosLoader.py,sha256=4kFU1ijrM1Jw7cywQv8mUiBHlE6w-uqfzSZP4hUV5P4,3771
|
|
@@ -63,14 +63,14 @@ alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py,sha256=Nav2cgCQK
|
|
|
63
63
|
alita_sdk/runtime/langchain/document_loaders/AlitaJiraLoader.py,sha256=M2q3YThkps0yAZOjfoLcyE7qycVTYKcXEGtpmp0N6C8,10950
|
|
64
64
|
alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py,sha256=RGHDfleYTn7AAc3H-yFZrjm06L0Ux14ZtEJpFlVBNCA,2474
|
|
65
65
|
alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py,sha256=olVThKX9Mmv4muTW0cAQBkgeNqU4IcdLVhqpBuzwly4,5904
|
|
66
|
-
alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py,sha256=
|
|
66
|
+
alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py,sha256=qsfAsbnaJJPo1jQM19_dYkkB4igGSsX6wOoGAvWefD4,4141
|
|
67
67
|
alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py,sha256=m_7aq-aCFVb4vXZsJNinfN1hAuyy_S0ylRknv_ahxDc,340
|
|
68
68
|
alita_sdk/runtime/langchain/document_loaders/AlitaQtestLoader.py,sha256=CUVVnisxm7b5yZWV6rn0Q3MEEaO1GWNcfnz5yWz8T0k,13283
|
|
69
69
|
alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py,sha256=EO1nJDRPVwNAe6PNT7U8GhRuKbWUi6tKPtBwOrn_MwM,4102
|
|
70
70
|
alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py,sha256=EiCIAF_OxSrbuwgOFk2IpxRMvFbctITt2jAI0g_atpk,3586
|
|
71
71
|
alita_sdk/runtime/langchain/document_loaders/ImageParser.py,sha256=RQ4zGdSw42ec8c6Eb48uFadayWuiT4FbwhGVwhSw60s,1065
|
|
72
72
|
alita_sdk/runtime/langchain/document_loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
alita_sdk/runtime/langchain/document_loaders/constants.py,sha256=
|
|
73
|
+
alita_sdk/runtime/langchain/document_loaders/constants.py,sha256=XUNC63S7U2HjE_1sxyDTUcwCVMeE4KBuW_G9wU5IQmw,10462
|
|
74
74
|
alita_sdk/runtime/langchain/document_loaders/utils.py,sha256=9xghESf3axBbwxATyVuS0Yu-TWe8zWZnXgCD1ZVyNW0,2414
|
|
75
75
|
alita_sdk/runtime/langchain/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
76
|
alita_sdk/runtime/langchain/interfaces/kwextractor.py,sha256=kSJA9L8g8UArmHu7Bd9dIO0Rrq86JPUb8RYNlnN68FQ,3072
|
|
@@ -96,7 +96,7 @@ alita_sdk/runtime/llms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
96
96
|
alita_sdk/runtime/llms/preloaded.py,sha256=3AaUbZK3d8fvxAQMjR3ftOoYa0SnkCOL1EvdvDCXIHE,11321
|
|
97
97
|
alita_sdk/runtime/toolkits/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
98
98
|
alita_sdk/runtime/toolkits/application.py,sha256=Mn8xwIdlbuyNzroH-WVVWJG0biOUV7u8qS15fQJ_XmI,2186
|
|
99
|
-
alita_sdk/runtime/toolkits/artifact.py,sha256=
|
|
99
|
+
alita_sdk/runtime/toolkits/artifact.py,sha256=YChNCX4QhVpaQG7Jk4TS-Wl0Aruc4slQ2K21zh9nNO0,3176
|
|
100
100
|
alita_sdk/runtime/toolkits/configurations.py,sha256=kIDAlnryPQfbZyFxV-9SzN2-Vefzx06TX1BBdIIpN90,141
|
|
101
101
|
alita_sdk/runtime/toolkits/datasource.py,sha256=qk78OdPoReYPCWwahfkKLbKc4pfsu-061oXRryFLP6I,2498
|
|
102
102
|
alita_sdk/runtime/toolkits/prompt.py,sha256=WIpTkkVYWqIqOWR_LlSWz3ug8uO9tm5jJ7aZYdiGRn0,1192
|
|
@@ -134,7 +134,7 @@ alita_sdk/runtime/utils/toolkit_runtime.py,sha256=MU63Fpxj0b5_r1IUUc0Q3-PN9VwL7r
|
|
|
134
134
|
alita_sdk/runtime/utils/toolkit_utils.py,sha256=I9QFqnaqfVgN26LUr6s3XlBlG6y0CoHURnCzG7XcwVs,5311
|
|
135
135
|
alita_sdk/runtime/utils/utils.py,sha256=VXNLsdeTmf6snn9EtUyobv4yL-xzLhUcH8P_ORMifYc,675
|
|
136
136
|
alita_sdk/tools/__init__.py,sha256=jUj1ztC2FbkIUB-YYmiqaz_rqW7Il5kWzDPn1mJmj5w,10545
|
|
137
|
-
alita_sdk/tools/base_indexer_toolkit.py,sha256=
|
|
137
|
+
alita_sdk/tools/base_indexer_toolkit.py,sha256=PyT3BDSn6gNJPXdbZw21tvTbE9WkhJD3m_pFWZJlYbU,23825
|
|
138
138
|
alita_sdk/tools/code_indexer_toolkit.py,sha256=6QvI1by0OFdnKTx5TfNoDJjnMrvnTi9T56xaDxzeleU,7306
|
|
139
139
|
alita_sdk/tools/elitea_base.py,sha256=up3HshASSDfjlHV_HPrs1aD4JIwwX0Ug26WGTzgIYvY,34724
|
|
140
140
|
alita_sdk/tools/non_code_indexer_toolkit.py,sha256=B3QvhpT1F9QidkCcsOi3J_QrTOaNlTxqWFwe90VivQQ,1329
|
|
@@ -237,7 +237,7 @@ alita_sdk/tools/custom_open_api/api_wrapper.py,sha256=sDSFpvEqpSvXHGiBISdQQcUecf
|
|
|
237
237
|
alita_sdk/tools/elastic/__init__.py,sha256=iwnSRppRpzvJ1da2K3Glu8Uu41MhBDCYbguboLkEbW0,2818
|
|
238
238
|
alita_sdk/tools/elastic/api_wrapper.py,sha256=pl8CqQxteJAGwyOhMcld-ZgtOTFwwbv42OITQVe8rM0,1948
|
|
239
239
|
alita_sdk/tools/figma/__init__.py,sha256=W6vIMMkZI2Lmpg6_CRRV3oadaIbVI-qTLmKUh6enqWs,4509
|
|
240
|
-
alita_sdk/tools/figma/api_wrapper.py,sha256=
|
|
240
|
+
alita_sdk/tools/figma/api_wrapper.py,sha256=k5V2ufv9k3LL5dwjSVi2qIZdx6H0613mlXId3gQudMw,33788
|
|
241
241
|
alita_sdk/tools/github/__init__.py,sha256=2rHu0zZyZGnLC5CkHgDIhe14N9yCyaEfrrt7ydH8478,5191
|
|
242
242
|
alita_sdk/tools/github/api_wrapper.py,sha256=mX23Rro6xnRa35tpeWhKYcRCJx0cDTzIe32pZAKDYno,7986
|
|
243
243
|
alita_sdk/tools/github/github_client.py,sha256=0YkpD6Zm4X46jMNN57ZIypo2YObtgxCGQokJAF-laFs,86597
|
|
@@ -246,7 +246,7 @@ alita_sdk/tools/github/schemas.py,sha256=TxEWR3SjDKVwzo9i2tLnss_uPAv85Mh7oWjvQvY
|
|
|
246
246
|
alita_sdk/tools/github/tool.py,sha256=Jnnv5lenV5ds8AAdyo2m8hSzyJ117HZBjzHC6T1ck-M,1037
|
|
247
247
|
alita_sdk/tools/github/tool_prompts.py,sha256=y6ZW_FpUCE87Uop3WuQAZVRnzxO5t7xjBOI5bCqiluw,30194
|
|
248
248
|
alita_sdk/tools/gitlab/__init__.py,sha256=iis7RHD3YgKWxF_ryTfdtA8RPGV-W8zUfy4BgiTDADw,4540
|
|
249
|
-
alita_sdk/tools/gitlab/api_wrapper.py,sha256=
|
|
249
|
+
alita_sdk/tools/gitlab/api_wrapper.py,sha256=jziPnjBkJE7TRIAyGsV7s9sX74NuL97yP1UiNKzzK8s,22626
|
|
250
250
|
alita_sdk/tools/gitlab/tools.py,sha256=vOGTlSaGaFmWn6LS6YFP-FuTqUPun9vnv1VrUcUHAZQ,16500
|
|
251
251
|
alita_sdk/tools/gitlab/utils.py,sha256=Z2XiqIg54ouqqt1to-geFybmkCb1I6bpE91wfnINH1I,2320
|
|
252
252
|
alita_sdk/tools/gitlab_org/__init__.py,sha256=PSTsC4BcPoyDv03Wj9VQHrEGUeR8hw4MRarB64VeqFg,3865
|
|
@@ -296,12 +296,12 @@ alita_sdk/tools/pandas/statsmodels/descriptive.py,sha256=APdofBnEiRhMrn6tLKwH076
|
|
|
296
296
|
alita_sdk/tools/pandas/statsmodels/hypothesis_testing.py,sha256=fdNAayMB3W7avMfKJCcbf2_P54vUXbq8KVebOB48348,10508
|
|
297
297
|
alita_sdk/tools/pandas/statsmodels/regression.py,sha256=Y1pWK4u_qzrfA740K-FX0nZ5FREGGPk8mfvykPIYoiI,9164
|
|
298
298
|
alita_sdk/tools/postman/__init__.py,sha256=2bvyhAqmAwXjswiPiuMaB7caU44k5rAWyeR58pc1ksU,4472
|
|
299
|
-
alita_sdk/tools/postman/api_wrapper.py,sha256=
|
|
299
|
+
alita_sdk/tools/postman/api_wrapper.py,sha256=TY8ddkrFWTsMWK9Dd0cTXNCmihhfbxFw8EqK-kBPwv4,96458
|
|
300
300
|
alita_sdk/tools/postman/postman_analysis.py,sha256=2d-Oi2UORosIePIUyncSONw9hY7dw8Zc7BQvCd4aqpg,45115
|
|
301
301
|
alita_sdk/tools/pptx/__init__.py,sha256=vVUrWnj7KWJgEk9oxGSsCAQ2SMSXrp_SFOdUHYQKcAo,3444
|
|
302
302
|
alita_sdk/tools/pptx/pptx_wrapper.py,sha256=yyCYcTlIY976kJ4VfPo4dyxj4yeii9j9TWP6W8ZIpN8,29195
|
|
303
303
|
alita_sdk/tools/qtest/__init__.py,sha256=bnD6rDM9dS0vpgaUmza4z67WLcZVhJk7S9ZG8OPij0Q,4116
|
|
304
|
-
alita_sdk/tools/qtest/api_wrapper.py,sha256=
|
|
304
|
+
alita_sdk/tools/qtest/api_wrapper.py,sha256=eCEjJ9r1j1VZpS25Y7pNVM-kuVx1jvLYg1lz6EEHmRU,23939
|
|
305
305
|
alita_sdk/tools/qtest/tool.py,sha256=kKzNPS4fUC76WQQttQ6kdVANViHEvKE8Kf174MQiNYU,562
|
|
306
306
|
alita_sdk/tools/rally/__init__.py,sha256=2BPPXJxAOKgfmaxVFVvxndfK0JxOXDLkoRmzu2dUwOE,3512
|
|
307
307
|
alita_sdk/tools/rally/api_wrapper.py,sha256=mouzU6g0KML4UNapdk0k6Q0pU3MpJuWnNo71n9PSEHM,11752
|
|
@@ -329,7 +329,7 @@ alita_sdk/tools/testrail/__init__.py,sha256=Xg4nVjULL_D8JpIXLYXppnwUfGF4-lguFwKH
|
|
|
329
329
|
alita_sdk/tools/testrail/api_wrapper.py,sha256=tQcGlFJmftvs5ZiO4tsP19fCo4CrJeq_UEvQR1liVfE,39891
|
|
330
330
|
alita_sdk/tools/utils/__init__.py,sha256=W9rCCUPtHCP5nGAbWp0n5jaNA84572aiRoqKneBnaS4,3330
|
|
331
331
|
alita_sdk/tools/utils/available_tools_decorator.py,sha256=IbrdfeQkswxUFgvvN7-dyLMZMyXLiwvX7kgi3phciCk,273
|
|
332
|
-
alita_sdk/tools/utils/content_parser.py,sha256=
|
|
332
|
+
alita_sdk/tools/utils/content_parser.py,sha256=4GCiTwoJ1zcTHi1nXLf_qJEET7aO-AWjk3yGgXhmO9g,14529
|
|
333
333
|
alita_sdk/tools/vector_adapters/VectorStoreAdapter.py,sha256=ypBEAkFRGHv5edW0N9rdo1yKurNGQ4pRVEWtrN_7SeA,17656
|
|
334
334
|
alita_sdk/tools/vector_adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
335
335
|
alita_sdk/tools/xray/__init__.py,sha256=eOMWP8VamFbbJgt1xrGpGPqB9ByOTA0Cd3LCaETzGk4,4376
|
|
@@ -351,8 +351,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
|
|
|
351
351
|
alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
|
|
352
352
|
alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
|
|
353
353
|
alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
|
|
354
|
-
alita_sdk-0.3.
|
|
355
|
-
alita_sdk-0.3.
|
|
356
|
-
alita_sdk-0.3.
|
|
357
|
-
alita_sdk-0.3.
|
|
358
|
-
alita_sdk-0.3.
|
|
354
|
+
alita_sdk-0.3.357.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
355
|
+
alita_sdk-0.3.357.dist-info/METADATA,sha256=vrcto71pw76iKFWB3WNDj3OSV7RlUSuRGJB1d3DXrwU,19071
|
|
356
|
+
alita_sdk-0.3.357.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
357
|
+
alita_sdk-0.3.357.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
|
|
358
|
+
alita_sdk-0.3.357.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|