alita-sdk 0.3.403__py3-none-any.whl → 0.3.405__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.

@@ -1,5 +1,6 @@
1
1
  import ast
2
2
  import fnmatch
3
+ import json
3
4
  import logging
4
5
  from typing import Optional, List, Generator
5
6
 
@@ -117,6 +118,15 @@ class CodeIndexerToolkit(BaseIndexerToolkit):
117
118
  if not file_content:
118
119
  # empty file, skip
119
120
  continue
121
+ #
122
+ # ensure file content is a string
123
+ if isinstance(file_content, bytes):
124
+ file_content = file_content.decode("utf-8", errors="ignore")
125
+ elif isinstance(file_content, dict) and file.endswith('.json'):
126
+ file_content = json.dumps(file_content)
127
+ elif not isinstance(file_content, str):
128
+ file_content = str(file_content)
129
+ #
120
130
  # hash the file content to ensure uniqueness
121
131
  import hashlib
122
132
  file_hash = hashlib.sha256(file_content.encode("utf-8")).hexdigest()
@@ -127,8 +127,23 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
127
127
  result.append(temp_props)
128
128
  return result if result else ToolException("Can not get files or folder is empty. Please, double check folder name and read permissions.")
129
129
  except Exception as e:
130
- logging.error(f"Failed to load files from sharepoint: {e}")
131
- return ToolException("Can not get files. Please, double check folder name and read permissions.")
130
+ # attempt to get via graph api
131
+ try:
132
+ # attempt to get files via graph api
133
+ from .authorization_helper import SharepointAuthorizationHelper
134
+ auth_helper = SharepointAuthorizationHelper(
135
+ client_id=self.client_id,
136
+ client_secret=self.client_secret.get_secret_value(),
137
+ tenant="", # optional for graph api
138
+ scope="", # optional for graph api
139
+ token_json="", # optional for graph api
140
+ )
141
+ files = auth_helper.get_files_list(self.site_url, folder_name, limit_files)
142
+ return files
143
+ except Exception as graph_e:
144
+ logging.error(f"Failed to load files from sharepoint via base api: {e}")
145
+ logging.error(f"Failed to load files from sharepoint via graph api: {graph_e}")
146
+ return ToolException(f"Can not get files. Please, double check folder name and read permissions: {e} and {graph_e}")
132
147
 
133
148
  def read_file(self, path,
134
149
  is_capture_image: bool = False,
@@ -1,4 +1,5 @@
1
1
  from datetime import datetime, timezone
2
+ from urllib.parse import urlparse
2
3
 
3
4
  import jwt
4
5
  import requests
@@ -54,4 +55,102 @@ class SharepointAuthorizationHelper:
54
55
  except jwt.ExpiredSignatureError:
55
56
  return False
56
57
  except jwt.InvalidTokenError:
57
- return False
58
+ return False
59
+
60
+
61
+ def generate_token_and_site_id(self, site_url: str) -> tuple[str, str]:
62
+ try:
63
+ parsed = urlparse(site_url)
64
+ domain = parsed.hostname
65
+ site_path = parsed.path.strip('/')
66
+ if not domain or not site_path:
67
+ raise ValueError(f"site_url missing domain or site path: {site_url}")
68
+ #
69
+ app_name = domain.split('.')[0]
70
+ openid_config_url = f"https://login.microsoftonline.com/{app_name}.onmicrosoft.com/v2.0/.well-known/openid-configuration"
71
+ response = requests.get(openid_config_url)
72
+ if response.status_code != 200:
73
+ raise RuntimeError(f"Failed to get OpenID config: {response.status_code} {response.text}")
74
+ token_url = response.json().get("token_endpoint")
75
+ if not token_url:
76
+ raise KeyError("'token_endpoint' missing in OpenID config response")
77
+ #
78
+ token_data = {
79
+ "grant_type": "client_credentials",
80
+ "client_id": self.client_id,
81
+ "client_secret": self.client_secret,
82
+ "scope": "https://graph.microsoft.com/.default"
83
+ }
84
+ token_response = requests.post(token_url, data=token_data)
85
+ if token_response.status_code != 200:
86
+ raise RuntimeError(f"Failed to get access token: {token_response.status_code} {token_response.text}")
87
+ access_token = token_response.json().get("access_token")
88
+ if not access_token:
89
+ raise KeyError("'access_token' missing in token response")
90
+ #
91
+ graph_site_url = f"https://graph.microsoft.com/v1.0/sites/{domain}:/{site_path}"
92
+ headers = {"Authorization": f"Bearer {access_token}"}
93
+ site_response = requests.get(graph_site_url, headers=headers)
94
+ if site_response.status_code != 200:
95
+ raise RuntimeError(f"Failed to get site info: {site_response.status_code} {site_response.text}")
96
+ site_id = site_response.json().get("id")
97
+ if not site_id:
98
+ raise KeyError("'id' missing in site response")
99
+ #
100
+ return access_token, site_id
101
+ except Exception as e:
102
+ raise RuntimeError(f"Error while obtaining access_token and site_id: {e}")
103
+
104
+ def get_files_list(self, site_url: str, folder_name: str = None, limit_files: int = 100):
105
+ if not site_url or not site_url.startswith("https://"):
106
+ raise ValueError(f"Invalid site_url format: {site_url}")
107
+ if limit_files is not None and (not isinstance(limit_files, int) or limit_files <= 0):
108
+ raise ValueError(f"limit_files must be a positive integer, got: {limit_files}")
109
+ try:
110
+ access_token, site_id = self.generate_token_and_site_id(site_url)
111
+ headers = {"Authorization": f"Bearer {access_token}"}
112
+ drives_url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drives"
113
+ drives_response = requests.get(drives_url, headers=headers)
114
+ if drives_response.status_code != 200:
115
+ raise RuntimeError(f"Failed to get drives: {drives_response.status_code} {drives_response.text}")
116
+ drives_json = drives_response.json()
117
+ if "value" not in drives_json or not drives_json["value"]:
118
+ raise KeyError("'value' missing or empty in drives response")
119
+ drive_id = drives_json["value"][0].get("id")
120
+ if not drive_id:
121
+ raise KeyError("'id' missing in drive object")
122
+ #
123
+ # Build the correct endpoint for folder or root
124
+ if folder_name:
125
+ # Validate folder_name for safe URL usage
126
+ if any(c in folder_name for c in ['..', '//', '\\']):
127
+ raise ValueError(f"Unsafe folder_name: {folder_name}")
128
+ url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/root:/{folder_name}:/children?$top={limit_files}"
129
+ else:
130
+ url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/root/children?$top={limit_files}"
131
+ response = requests.get(url, headers=headers)
132
+ if response.status_code != 200:
133
+ raise RuntimeError(f"Failed to get files list: {response.status_code} {response.text}")
134
+ files_json = response.json()
135
+ if "value" not in files_json:
136
+ raise KeyError("'value' missing in files response")
137
+ #
138
+ result = []
139
+ for file in files_json["value"]:
140
+ temp_props = {
141
+ 'Name': file.get('name'),
142
+ 'Path': file.get('webUrl'),
143
+ 'Created': file.get('createdDateTime'),
144
+ 'Modified': file.get('lastModifiedDateTime'),
145
+ 'Link': file.get('webUrl'),
146
+ 'id': file.get('id')
147
+ }
148
+ if not all([temp_props['Name'], temp_props['Path'], temp_props['id']]):
149
+ raise KeyError(f"Missing required file fields in: {file}")
150
+ result.append(temp_props)
151
+ # If API doesn't respect $top, slice in Python
152
+ if limit_files is not None:
153
+ result = result[:limit_files]
154
+ return result
155
+ except Exception as e:
156
+ raise RuntimeError(f"Error in get_files_list: {e}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.403
3
+ Version: 0.3.405
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
@@ -137,7 +137,7 @@ alita_sdk/runtime/utils/toolkit_utils.py,sha256=I9QFqnaqfVgN26LUr6s3XlBlG6y0CoHU
137
137
  alita_sdk/runtime/utils/utils.py,sha256=PJK8A-JVIzY1IowOjGG8DIqsIiEFe65qDKvFcjJCKWA,1041
138
138
  alita_sdk/tools/__init__.py,sha256=wrcSP0AN6HukZHPXpObCKI58cY0lVpHyzbpq609CMhE,10726
139
139
  alita_sdk/tools/base_indexer_toolkit.py,sha256=7UTcrmvGvmIBF3WGKrsEp7zJL-XB1JIgaRkbE1ZSS9A,26439
140
- alita_sdk/tools/code_indexer_toolkit.py,sha256=0vFsNti6lLwXM1Tbv45eAFhv7DAvVFUjWEHFJjCdIrU,7298
140
+ alita_sdk/tools/code_indexer_toolkit.py,sha256=2VkOC8JfBDc25_jp-NWyMYqpaYRETIzTJFLrIYrfBpE,7814
141
141
  alita_sdk/tools/elitea_base.py,sha256=34fmVdYgd2YXifU5LFNjMQysr4OOIZ6AOZjq4GxLgSw,34417
142
142
  alita_sdk/tools/non_code_indexer_toolkit.py,sha256=6Lrqor1VeSLbPLDHAfg_7UAUqKFy1r_n6bdsc4-ak98,1315
143
143
  alita_sdk/tools/ado/__init__.py,sha256=NnNYpNFW0_N_v1td_iekYOoQRRB7PIunbpT2f9ZFJM4,1201
@@ -317,8 +317,8 @@ alita_sdk/tools/servicenow/__init__.py,sha256=ziEt2juPrGFyB98ZXbGf25v6gZo4UJTHsz
317
317
  alita_sdk/tools/servicenow/api_wrapper.py,sha256=WpH-bBLGFdhehs4g-K-WAkNuaD1CSrwsDpdgB3RG53s,6120
318
318
  alita_sdk/tools/servicenow/servicenow_client.py,sha256=Rdqfu-ll-qbnclMzChLZBsfXRDzgoX_FdeI2WLApWxc,3269
319
319
  alita_sdk/tools/sharepoint/__init__.py,sha256=5z2iSmm-0kbHKf70wN6OOgS4Px7tOzwkIpHXz0Vrbj4,4045
320
- alita_sdk/tools/sharepoint/api_wrapper.py,sha256=6D0pGsCx33KxfbZkG331I1gucmqLToI2qBMonFZtl6o,12245
321
- alita_sdk/tools/sharepoint/authorization_helper.py,sha256=n-nL5dlBoLMK70nHu7P2RYCb8C6c9HMA_gEaw8LxuhE,2007
320
+ alita_sdk/tools/sharepoint/api_wrapper.py,sha256=xUQOlJBHha0bmzkz00GVgzUnAsE28saGkRYHqXTj7Ac,13105
321
+ alita_sdk/tools/sharepoint/authorization_helper.py,sha256=WfkSZh28gfB2aOlWk1T4mHjc0PBW5SPwLzVVTPr_dkM,7476
322
322
  alita_sdk/tools/sharepoint/utils.py,sha256=fZ1YzAu5CTjKSZeslowpOPH974902S8vCp1Wu7L44LM,446
323
323
  alita_sdk/tools/slack/__init__.py,sha256=YiPAoRc6y6uVpfHl0K1Qi-flcyPlWFIMVcVbhicGWXY,3990
324
324
  alita_sdk/tools/slack/api_wrapper.py,sha256=5VrV7iSGno8ZcDzEHdGPNhInhtODGPPvAzoZ9W9iQWE,14009
@@ -353,8 +353,8 @@ alita_sdk/tools/zephyr_scale/api_wrapper.py,sha256=kT0TbmMvuKhDUZc0i7KO18O38JM9S
353
353
  alita_sdk/tools/zephyr_squad/__init__.py,sha256=0ne8XLJEQSLOWfzd2HdnqOYmQlUliKHbBED5kW_Vias,2895
354
354
  alita_sdk/tools/zephyr_squad/api_wrapper.py,sha256=kmw_xol8YIYFplBLWTqP_VKPRhL_1ItDD0_vXTe_UuI,14906
355
355
  alita_sdk/tools/zephyr_squad/zephyr_squad_cloud_client.py,sha256=R371waHsms4sllHCbijKYs90C-9Yu0sSR3N4SUfQOgU,5066
356
- alita_sdk-0.3.403.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
357
- alita_sdk-0.3.403.dist-info/METADATA,sha256=m6J_ENbHIf_JdB3fXvKsTDoULBNfh_lfYlTH6i2w66s,19071
358
- alita_sdk-0.3.403.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
359
- alita_sdk-0.3.403.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
360
- alita_sdk-0.3.403.dist-info/RECORD,,
356
+ alita_sdk-0.3.405.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
357
+ alita_sdk-0.3.405.dist-info/METADATA,sha256=zNo9z-qhfD29QynTObDSSd-1sgmJKEdTLqdM_NdmCCI,19071
358
+ alita_sdk-0.3.405.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
359
+ alita_sdk-0.3.405.dist-info/top_level.txt,sha256=0vJYy5p_jK6AwVb1aqXr7Kgqgk3WDtQ6t5C-XI9zkmg,10
360
+ alita_sdk-0.3.405.dist-info/RECORD,,