alita-sdk 0.3.379__py3-none-any.whl → 0.3.627__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 (278) hide show
  1. alita_sdk/cli/__init__.py +10 -0
  2. alita_sdk/cli/__main__.py +17 -0
  3. alita_sdk/cli/agent/__init__.py +5 -0
  4. alita_sdk/cli/agent/default.py +258 -0
  5. alita_sdk/cli/agent_executor.py +156 -0
  6. alita_sdk/cli/agent_loader.py +245 -0
  7. alita_sdk/cli/agent_ui.py +228 -0
  8. alita_sdk/cli/agents.py +3113 -0
  9. alita_sdk/cli/callbacks.py +647 -0
  10. alita_sdk/cli/cli.py +168 -0
  11. alita_sdk/cli/config.py +306 -0
  12. alita_sdk/cli/context/__init__.py +30 -0
  13. alita_sdk/cli/context/cleanup.py +198 -0
  14. alita_sdk/cli/context/manager.py +731 -0
  15. alita_sdk/cli/context/message.py +285 -0
  16. alita_sdk/cli/context/strategies.py +289 -0
  17. alita_sdk/cli/context/token_estimation.py +127 -0
  18. alita_sdk/cli/formatting.py +182 -0
  19. alita_sdk/cli/input_handler.py +419 -0
  20. alita_sdk/cli/inventory.py +1073 -0
  21. alita_sdk/cli/mcp_loader.py +315 -0
  22. alita_sdk/cli/testcases/__init__.py +94 -0
  23. alita_sdk/cli/testcases/data_generation.py +119 -0
  24. alita_sdk/cli/testcases/discovery.py +96 -0
  25. alita_sdk/cli/testcases/executor.py +84 -0
  26. alita_sdk/cli/testcases/logger.py +85 -0
  27. alita_sdk/cli/testcases/parser.py +172 -0
  28. alita_sdk/cli/testcases/prompts.py +91 -0
  29. alita_sdk/cli/testcases/reporting.py +125 -0
  30. alita_sdk/cli/testcases/setup.py +108 -0
  31. alita_sdk/cli/testcases/test_runner.py +282 -0
  32. alita_sdk/cli/testcases/utils.py +39 -0
  33. alita_sdk/cli/testcases/validation.py +90 -0
  34. alita_sdk/cli/testcases/workflow.py +196 -0
  35. alita_sdk/cli/toolkit.py +327 -0
  36. alita_sdk/cli/toolkit_loader.py +85 -0
  37. alita_sdk/cli/tools/__init__.py +43 -0
  38. alita_sdk/cli/tools/approval.py +224 -0
  39. alita_sdk/cli/tools/filesystem.py +1751 -0
  40. alita_sdk/cli/tools/planning.py +389 -0
  41. alita_sdk/cli/tools/terminal.py +414 -0
  42. alita_sdk/community/__init__.py +72 -12
  43. alita_sdk/community/inventory/__init__.py +236 -0
  44. alita_sdk/community/inventory/config.py +257 -0
  45. alita_sdk/community/inventory/enrichment.py +2137 -0
  46. alita_sdk/community/inventory/extractors.py +1469 -0
  47. alita_sdk/community/inventory/ingestion.py +3172 -0
  48. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  49. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  50. alita_sdk/community/inventory/parsers/base.py +295 -0
  51. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  52. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  53. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  54. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  55. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  56. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  57. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  58. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  59. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  60. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  61. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  62. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  63. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  64. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  65. alita_sdk/community/inventory/patterns/loader.py +348 -0
  66. alita_sdk/community/inventory/patterns/registry.py +198 -0
  67. alita_sdk/community/inventory/presets.py +535 -0
  68. alita_sdk/community/inventory/retrieval.py +1403 -0
  69. alita_sdk/community/inventory/toolkit.py +173 -0
  70. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  71. alita_sdk/community/inventory/visualize.py +1370 -0
  72. alita_sdk/configurations/__init__.py +1 -1
  73. alita_sdk/configurations/ado.py +141 -20
  74. alita_sdk/configurations/bitbucket.py +94 -2
  75. alita_sdk/configurations/confluence.py +130 -1
  76. alita_sdk/configurations/figma.py +76 -0
  77. alita_sdk/configurations/gitlab.py +91 -0
  78. alita_sdk/configurations/jira.py +103 -0
  79. alita_sdk/configurations/openapi.py +329 -0
  80. alita_sdk/configurations/qtest.py +72 -1
  81. alita_sdk/configurations/report_portal.py +96 -0
  82. alita_sdk/configurations/sharepoint.py +148 -0
  83. alita_sdk/configurations/testio.py +83 -0
  84. alita_sdk/configurations/testrail.py +88 -0
  85. alita_sdk/configurations/xray.py +93 -0
  86. alita_sdk/configurations/zephyr_enterprise.py +93 -0
  87. alita_sdk/configurations/zephyr_essential.py +75 -0
  88. alita_sdk/runtime/clients/artifact.py +3 -3
  89. alita_sdk/runtime/clients/client.py +388 -46
  90. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  91. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  92. alita_sdk/runtime/clients/sandbox_client.py +8 -21
  93. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  94. alita_sdk/runtime/langchain/assistant.py +157 -39
  95. alita_sdk/runtime/langchain/constants.py +647 -1
  96. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  97. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
  98. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  99. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -4
  100. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
  101. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
  102. alita_sdk/runtime/langchain/document_loaders/constants.py +40 -19
  103. alita_sdk/runtime/langchain/langraph_agent.py +405 -84
  104. alita_sdk/runtime/langchain/utils.py +106 -7
  105. alita_sdk/runtime/llms/preloaded.py +2 -6
  106. alita_sdk/runtime/models/mcp_models.py +61 -0
  107. alita_sdk/runtime/skills/__init__.py +91 -0
  108. alita_sdk/runtime/skills/callbacks.py +498 -0
  109. alita_sdk/runtime/skills/discovery.py +540 -0
  110. alita_sdk/runtime/skills/executor.py +610 -0
  111. alita_sdk/runtime/skills/input_builder.py +371 -0
  112. alita_sdk/runtime/skills/models.py +330 -0
  113. alita_sdk/runtime/skills/registry.py +355 -0
  114. alita_sdk/runtime/skills/skill_runner.py +330 -0
  115. alita_sdk/runtime/toolkits/__init__.py +31 -0
  116. alita_sdk/runtime/toolkits/application.py +29 -10
  117. alita_sdk/runtime/toolkits/artifact.py +20 -11
  118. alita_sdk/runtime/toolkits/datasource.py +13 -6
  119. alita_sdk/runtime/toolkits/mcp.py +783 -0
  120. alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
  121. alita_sdk/runtime/toolkits/planning.py +178 -0
  122. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  123. alita_sdk/runtime/toolkits/subgraph.py +251 -6
  124. alita_sdk/runtime/toolkits/tools.py +356 -69
  125. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  126. alita_sdk/runtime/tools/__init__.py +10 -3
  127. alita_sdk/runtime/tools/application.py +27 -6
  128. alita_sdk/runtime/tools/artifact.py +511 -28
  129. alita_sdk/runtime/tools/data_analysis.py +183 -0
  130. alita_sdk/runtime/tools/function.py +67 -35
  131. alita_sdk/runtime/tools/graph.py +10 -4
  132. alita_sdk/runtime/tools/image_generation.py +148 -46
  133. alita_sdk/runtime/tools/llm.py +1003 -128
  134. alita_sdk/runtime/tools/loop.py +3 -1
  135. alita_sdk/runtime/tools/loop_output.py +3 -1
  136. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  137. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  138. alita_sdk/runtime/tools/mcp_server_tool.py +8 -5
  139. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  140. alita_sdk/runtime/tools/planning/models.py +246 -0
  141. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  142. alita_sdk/runtime/tools/router.py +2 -4
  143. alita_sdk/runtime/tools/sandbox.py +65 -48
  144. alita_sdk/runtime/tools/skill_router.py +776 -0
  145. alita_sdk/runtime/tools/tool.py +3 -1
  146. alita_sdk/runtime/tools/vectorstore.py +9 -3
  147. alita_sdk/runtime/tools/vectorstore_base.py +70 -14
  148. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  149. alita_sdk/runtime/utils/constants.py +5 -1
  150. alita_sdk/runtime/utils/mcp_client.py +492 -0
  151. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  152. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  153. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  154. alita_sdk/runtime/utils/serialization.py +155 -0
  155. alita_sdk/runtime/utils/streamlit.py +40 -13
  156. alita_sdk/runtime/utils/toolkit_utils.py +30 -9
  157. alita_sdk/runtime/utils/utils.py +36 -0
  158. alita_sdk/tools/__init__.py +134 -35
  159. alita_sdk/tools/ado/repos/__init__.py +51 -32
  160. alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
  161. alita_sdk/tools/ado/test_plan/__init__.py +25 -9
  162. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
  163. alita_sdk/tools/ado/utils.py +1 -18
  164. alita_sdk/tools/ado/wiki/__init__.py +25 -12
  165. alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
  166. alita_sdk/tools/ado/work_item/__init__.py +26 -13
  167. alita_sdk/tools/ado/work_item/ado_wrapper.py +73 -11
  168. alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
  169. alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
  170. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  171. alita_sdk/tools/azure_ai/search/__init__.py +11 -8
  172. alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
  173. alita_sdk/tools/base/tool.py +5 -1
  174. alita_sdk/tools/base_indexer_toolkit.py +271 -84
  175. alita_sdk/tools/bitbucket/__init__.py +17 -11
  176. alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
  177. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
  178. alita_sdk/tools/browser/__init__.py +5 -4
  179. alita_sdk/tools/carrier/__init__.py +5 -6
  180. alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
  181. alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
  182. alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
  183. alita_sdk/tools/chunkers/__init__.py +3 -1
  184. alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
  185. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  186. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  187. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  188. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  189. alita_sdk/tools/cloud/aws/__init__.py +10 -7
  190. alita_sdk/tools/cloud/azure/__init__.py +10 -7
  191. alita_sdk/tools/cloud/gcp/__init__.py +10 -7
  192. alita_sdk/tools/cloud/k8s/__init__.py +10 -7
  193. alita_sdk/tools/code/linter/__init__.py +10 -8
  194. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  195. alita_sdk/tools/code/sonar/__init__.py +11 -8
  196. alita_sdk/tools/code_indexer_toolkit.py +82 -22
  197. alita_sdk/tools/confluence/__init__.py +22 -16
  198. alita_sdk/tools/confluence/api_wrapper.py +107 -30
  199. alita_sdk/tools/confluence/loader.py +14 -2
  200. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  201. alita_sdk/tools/elastic/__init__.py +11 -8
  202. alita_sdk/tools/elitea_base.py +493 -30
  203. alita_sdk/tools/figma/__init__.py +58 -11
  204. alita_sdk/tools/figma/api_wrapper.py +1235 -143
  205. alita_sdk/tools/figma/figma_client.py +73 -0
  206. alita_sdk/tools/figma/toon_tools.py +2748 -0
  207. alita_sdk/tools/github/__init__.py +14 -15
  208. alita_sdk/tools/github/github_client.py +224 -100
  209. alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
  210. alita_sdk/tools/github/schemas.py +14 -5
  211. alita_sdk/tools/github/tool.py +5 -1
  212. alita_sdk/tools/github/tool_prompts.py +9 -22
  213. alita_sdk/tools/gitlab/__init__.py +16 -11
  214. alita_sdk/tools/gitlab/api_wrapper.py +218 -48
  215. alita_sdk/tools/gitlab_org/__init__.py +10 -9
  216. alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
  217. alita_sdk/tools/google/bigquery/__init__.py +13 -12
  218. alita_sdk/tools/google/bigquery/tool.py +5 -1
  219. alita_sdk/tools/google_places/__init__.py +11 -8
  220. alita_sdk/tools/google_places/api_wrapper.py +1 -1
  221. alita_sdk/tools/jira/__init__.py +17 -10
  222. alita_sdk/tools/jira/api_wrapper.py +92 -41
  223. alita_sdk/tools/keycloak/__init__.py +11 -8
  224. alita_sdk/tools/localgit/__init__.py +9 -3
  225. alita_sdk/tools/localgit/local_git.py +62 -54
  226. alita_sdk/tools/localgit/tool.py +5 -1
  227. alita_sdk/tools/memory/__init__.py +12 -4
  228. alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
  229. alita_sdk/tools/ocr/__init__.py +11 -8
  230. alita_sdk/tools/openapi/__init__.py +491 -106
  231. alita_sdk/tools/openapi/api_wrapper.py +1368 -0
  232. alita_sdk/tools/openapi/tool.py +20 -0
  233. alita_sdk/tools/pandas/__init__.py +20 -12
  234. alita_sdk/tools/pandas/api_wrapper.py +38 -25
  235. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  236. alita_sdk/tools/postman/__init__.py +10 -9
  237. alita_sdk/tools/pptx/__init__.py +11 -10
  238. alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
  239. alita_sdk/tools/qtest/__init__.py +31 -11
  240. alita_sdk/tools/qtest/api_wrapper.py +2135 -86
  241. alita_sdk/tools/rally/__init__.py +10 -9
  242. alita_sdk/tools/rally/api_wrapper.py +1 -1
  243. alita_sdk/tools/report_portal/__init__.py +12 -8
  244. alita_sdk/tools/salesforce/__init__.py +10 -8
  245. alita_sdk/tools/servicenow/__init__.py +17 -15
  246. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  247. alita_sdk/tools/sharepoint/__init__.py +10 -7
  248. alita_sdk/tools/sharepoint/api_wrapper.py +129 -38
  249. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  250. alita_sdk/tools/sharepoint/utils.py +8 -2
  251. alita_sdk/tools/slack/__init__.py +10 -7
  252. alita_sdk/tools/slack/api_wrapper.py +2 -2
  253. alita_sdk/tools/sql/__init__.py +12 -9
  254. alita_sdk/tools/testio/__init__.py +10 -7
  255. alita_sdk/tools/testrail/__init__.py +11 -10
  256. alita_sdk/tools/testrail/api_wrapper.py +1 -1
  257. alita_sdk/tools/utils/__init__.py +9 -4
  258. alita_sdk/tools/utils/content_parser.py +103 -18
  259. alita_sdk/tools/utils/text_operations.py +410 -0
  260. alita_sdk/tools/utils/tool_prompts.py +79 -0
  261. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +30 -13
  262. alita_sdk/tools/xray/__init__.py +13 -9
  263. alita_sdk/tools/yagmail/__init__.py +9 -3
  264. alita_sdk/tools/zephyr/__init__.py +10 -7
  265. alita_sdk/tools/zephyr_enterprise/__init__.py +11 -7
  266. alita_sdk/tools/zephyr_essential/__init__.py +10 -7
  267. alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
  268. alita_sdk/tools/zephyr_essential/client.py +2 -2
  269. alita_sdk/tools/zephyr_scale/__init__.py +11 -8
  270. alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
  271. alita_sdk/tools/zephyr_squad/__init__.py +10 -7
  272. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +154 -8
  273. alita_sdk-0.3.627.dist-info/RECORD +468 -0
  274. alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
  275. alita_sdk-0.3.379.dist-info/RECORD +0 -360
  276. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
  277. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
  278. {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,9 @@ from .api_wrapper import RallyApiWrapper
5
5
  from langchain_core.tools import BaseTool
6
6
  from ..base.tool import BaseAction
7
7
  from ..elitea_base import filter_missconfigured_index_tools
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
  from ...configurations.rally import RallyConfiguration
10
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
10
11
 
11
12
  name = "rally"
12
13
 
@@ -21,16 +22,12 @@ def get_tools(tool):
21
22
 
22
23
  class RallyToolkit(BaseToolkit):
23
24
  tools: List[BaseTool] = []
24
- toolkit_max_length: int = 0
25
25
 
26
26
  @staticmethod
27
27
  def toolkit_config_schema() -> BaseModel:
28
28
  selected_tools = {x['name']: x['args_schema'].schema() for x in RallyApiWrapper.model_construct().get_available_tools()}
29
- RallyToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
29
  return create_model(
31
30
  name,
32
- name=(str, Field(description="Toolkit name", json_schema_extra={'toolkit_name': True,
33
- 'max_toolkit_length': RallyToolkit.toolkit_max_length})),
34
31
  rally_configuration=(RallyConfiguration, Field(description="Rally configuration", json_schema_extra={'configuration_types': ['rally']})),
35
32
  workspace=(Optional[str], Field(default=None, description="Rally workspace")),
36
33
  project=(Optional[str], Field(default=None, description="Rally project")),
@@ -55,18 +52,22 @@ class RallyToolkit(BaseToolkit):
55
52
  **kwargs.get('rally_configuration'),
56
53
  }
57
54
  rally_api_wrapper = RallyApiWrapper(**wrapper_payload)
58
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
59
55
  available_tools = rally_api_wrapper.get_available_tools()
60
56
  tools = []
61
57
  for tool in available_tools:
62
58
  if selected_tools:
63
59
  if tool["name"] not in selected_tools:
64
60
  continue
61
+ description = f"{tool['description']}\nWorkspace: {rally_api_wrapper.workspace}. Project: {rally_api_wrapper.project}"
62
+ if toolkit_name:
63
+ description = f"{description}\nToolkit: {toolkit_name}"
64
+ description = description[:1000]
65
65
  tools.append(BaseAction(
66
66
  api_wrapper=rally_api_wrapper,
67
- name=prefix + tool["name"],
68
- description=f"{tool['description']}\nWorkspace: {rally_api_wrapper.workspace}. Project: {rally_api_wrapper.project}",
69
- args_schema=tool["args_schema"]
67
+ name=tool["name"],
68
+ description=description,
69
+ args_schema=tool["args_schema"],
70
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
70
71
  ))
71
72
  return cls(tools=tools)
72
73
 
@@ -40,7 +40,7 @@ RallyGetEntities = create_model(
40
40
  entity_type=(Optional[str], Field(description="Artifact type, e.g. 'HierarchicalRequirement', 'Defect', 'UserStory'", default="UserStory")),
41
41
  query=(Optional[str], Field(description="Query for searching Rally stories", default=None)),
42
42
  fetch=(Optional[bool], Field(description="Whether to fetch the full details of the stories", default=True)),
43
- limit=(Optional[int], Field(description="Limit the number of results", default=10))
43
+ limit=(Optional[int], Field(description="Limit the number of results", default=10, gt=0))
44
44
  )
45
45
 
46
46
  RallyGetProject = create_model(
@@ -7,8 +7,9 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
7
7
  from .api_wrapper import ReportPortalApiWrapper
8
8
  from ..base.tool import BaseAction
9
9
  from ..elitea_base import filter_missconfigured_index_tools
10
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
10
+ from ..utils import clean_string, get_max_toolkit_length
11
11
  from ...configurations.report_portal import ReportPortalConfiguration
12
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
12
13
 
13
14
  name = "report_portal"
14
15
 
@@ -21,13 +22,11 @@ def get_tools(tool):
21
22
 
22
23
 
23
24
  class ReportPortalToolkit(BaseToolkit):
24
- tools: list[BaseTool] = []
25
- toolkit_max_length: int = 0
25
+ tools: List[BaseTool] = []
26
26
 
27
27
  @staticmethod
28
28
  def toolkit_config_schema() -> BaseModel:
29
29
  selected_tools = {x['name']: x['args_schema'].schema() for x in ReportPortalApiWrapper.model_construct().get_available_tools()}
30
- ReportPortalToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
31
30
  return create_model(
32
31
  name,
33
32
  report_portal_configuration=(ReportPortalConfiguration, Field(description="Report Portal Configuration", json_schema_extra={'configuration_types': ['report_portal']})),
@@ -47,17 +46,22 @@ class ReportPortalToolkit(BaseToolkit):
47
46
  **kwargs.get('report_portal_configuration', {}),
48
47
  }
49
48
  report_portal_api_wrapper = ReportPortalApiWrapper(**wrapper_payload)
50
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
51
49
  available_tools = report_portal_api_wrapper.get_available_tools()
52
50
  tools = []
53
51
  for tool in available_tools:
54
52
  if selected_tools and tool["name"] not in selected_tools:
55
53
  continue
54
+ description = tool['description']
55
+ if toolkit_name:
56
+ description = f"Toolkit: {toolkit_name}\n{description}"
57
+ description = f"{description}\nReport portal configuration: 'url - {report_portal_api_wrapper.endpoint}, project - {report_portal_api_wrapper.project}'"
58
+ description = description[:1000]
56
59
  tools.append(BaseAction(
57
60
  api_wrapper=report_portal_api_wrapper,
58
- name=prefix + tool["name"],
59
- description=f"{tool['description']}\nReport portal configuration: 'url - {report_portal_api_wrapper.endpoint}, project - {report_portal_api_wrapper.project}'",
60
- args_schema=tool["args_schema"]
61
+ name=tool["name"],
62
+ description=description,
63
+ args_schema=tool["args_schema"],
64
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
61
65
  ))
62
66
  return cls(tools=tools)
63
67
 
@@ -5,8 +5,9 @@ from ..base.tool import BaseAction
5
5
  from pydantic import create_model, BaseModel, ConfigDict, Field
6
6
 
7
7
  from ..elitea_base import filter_missconfigured_index_tools
8
- from ..utils import clean_string, TOOLKIT_SPLITTER,get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
  from ...configurations.salesforce import SalesforceConfiguration
10
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
10
11
 
11
12
  name = "salesforce"
12
13
 
@@ -19,11 +20,9 @@ def get_tools(tool):
19
20
 
20
21
  class SalesforceToolkit(BaseToolkit):
21
22
  tools: List[BaseTool] = []
22
- toolkit_max_length: int = 0
23
23
  @staticmethod
24
24
  def toolkit_config_schema() -> BaseModel:
25
25
  available_tools = {x['name']: x['args_schema'].schema() for x in SalesforceApiWrapper.model_construct().get_available_tools()}
26
- SalesforceToolkit.toolkit_max_length = get_max_toolkit_length(available_tools)
27
26
  return create_model(
28
27
  name,
29
28
  api_version=(str, Field(description="Salesforce API Version", default='v59.0')),
@@ -47,18 +46,21 @@ class SalesforceToolkit(BaseToolkit):
47
46
  **kwargs.get('salesforce_configuration', {}),
48
47
  }
49
48
  api_wrapper = SalesforceApiWrapper(**wrapper_payload)
50
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
51
49
  tools = []
52
50
 
53
51
  for tool in api_wrapper.get_available_tools():
54
52
  if selected_tools and tool["name"] not in selected_tools:
55
53
  continue
56
-
54
+ description = f"Salesforce Tool: {tool['description']}"
55
+ if toolkit_name:
56
+ description = f"{description}\nToolkit: {toolkit_name}"
57
+ description = description[:1000]
57
58
  tools.append(BaseAction(
58
59
  api_wrapper=api_wrapper,
59
- name=prefix + tool["name"],
60
- description=f"Salesforce Tool: {tool['description']}",
61
- args_schema=tool["args_schema"]
60
+ name=tool["name"],
61
+ description=description,
62
+ args_schema=tool["args_schema"],
63
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
62
64
  ))
63
65
 
64
66
  return cls(tools=tools)
@@ -7,37 +7,33 @@ from ..base.tool import BaseAction
7
7
  from pydantic import create_model, BaseModel, ConfigDict, Field
8
8
 
9
9
  from ..elitea_base import filter_missconfigured_index_tools
10
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
11
10
  from ...configurations.service_now import ServiceNowConfiguration
11
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
12
12
 
13
13
 
14
14
  name = "service_now"
15
15
 
16
16
  def get_tools(tool):
17
+ settings = tool.get('settings') or {}
18
+
17
19
  return ServiceNowToolkit().get_toolkit(
18
- selected_tools=tool['settings'].get('selected_tools', []),
19
- instance_alias=tool['settings'].get('instance_alias', None),
20
- base_url=tool['settings']['base_url'],
21
- servicenow_configuration=tool['settings']['servicenow_configuration'],
22
- response_fields=tool['settings'].get('response_fields', None),
20
+ selected_tools=settings.get('selected_tools', []),
21
+ instance_alias=settings.get('instance_alias', None),
22
+ servicenow_configuration=settings.get('servicenow_configuration', None),
23
+ response_fields=settings.get('response_fields', None),
23
24
  toolkit_name=tool.get('toolkit_name')
24
25
  ).get_tools()
25
26
 
26
27
 
27
28
  class ServiceNowToolkit(BaseToolkit):
28
29
  tools: List[BaseTool] = []
29
- toolkit_max_length: int = 0
30
30
 
31
31
  @staticmethod
32
32
  def toolkit_config_schema() -> BaseModel:
33
33
  selected_tools = {x['name']: x['args_schema'].schema() for x in
34
34
  ServiceNowAPIWrapper.model_construct().get_available_tools()}
35
- ServiceNowToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
36
35
  return create_model(
37
36
  name,
38
- name=(str, Field(description="Toolkit name",
39
- json_schema_extra={
40
- 'toolkit_name': True, 'max_toolkit_length': ServiceNowToolkit.toolkit_max_length})),
41
37
  response_fields=(Optional[str], Field(description="Response fields", default=None)),
42
38
  servicenow_configuration=(ServiceNowConfiguration, Field(description="ServiceNow Configuration",
43
39
  json_schema_extra={
@@ -80,18 +76,24 @@ class ServiceNowToolkit(BaseToolkit):
80
76
  **kwargs['servicenow_configuration'],
81
77
  }
82
78
  servicenow_api_wrapper = ServiceNowAPIWrapper(**wrapper_payload)
83
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
84
79
  available_tools = servicenow_api_wrapper.get_available_tools()
85
80
  tools = []
86
81
  for tool in available_tools:
87
82
  if selected_tools:
88
83
  if tool["name"] not in selected_tools:
89
84
  continue
85
+ base_url = getattr(servicenow_api_wrapper, "base_url", "") or ""
86
+ description = tool.get("description", "") if isinstance(tool, dict) else ""
87
+ if toolkit_name:
88
+ description = f"Toolkit: {toolkit_name}\n{description}"
89
+ description = f"ServiceNow: {base_url}\n{description}".strip()
90
+ description = description[:1000]
90
91
  tools.append(BaseAction(
91
92
  api_wrapper=servicenow_api_wrapper,
92
- name=prefix + tool["name"],
93
- description=f"ServiceNow: {servicenow_api_wrapper.base_url} " + tool["description"],
94
- args_schema=tool["args_schema"]
93
+ name=tool["name"],
94
+ description=description,
95
+ args_schema=tool["args_schema"],
96
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
95
97
  ))
96
98
  return cls(tools=tools)
97
99
 
@@ -58,7 +58,7 @@ class ServiceNowAPIWrapper(BaseToolApiWrapper):
58
58
  password = SecretStr(values['password'])
59
59
  username = values['username']
60
60
  cls.fields = values.get('fields', ['sys_id', 'number', 'state', 'short_description', 'description', 'priority', 'category', 'urgency', 'impact', 'creation_date'])
61
- cls.client = ServiceNowClient(base_url, (username, password.get_secret_value()))
61
+ cls.client = ServiceNowClient(instance=base_url, auth=(username, password.get_secret_value()))
62
62
  return values
63
63
 
64
64
  def get_incidents(self, data: Optional[Dict[str, Any]] = None) -> ToolException | str:
@@ -5,9 +5,10 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
5
5
  from .api_wrapper import SharepointApiWrapper
6
6
  from ..base.tool import BaseAction
7
7
  from ..elitea_base import filter_missconfigured_index_tools
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
  from ...configurations.pgvector import PgVectorConfiguration
10
10
  from ...configurations.sharepoint import SharepointConfiguration
11
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
11
12
 
12
13
  name = "sharepoint"
13
14
 
@@ -29,12 +30,10 @@ def get_tools(tool):
29
30
 
30
31
  class SharepointToolkit(BaseToolkit):
31
32
  tools: List[BaseTool] = []
32
- toolkit_max_length: int = 0
33
33
 
34
34
  @staticmethod
35
35
  def toolkit_config_schema() -> BaseModel:
36
36
  selected_tools = {x['name']: x['args_schema'].schema() for x in SharepointApiWrapper.model_construct().get_available_tools()}
37
- SharepointToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
38
37
  return create_model(
39
38
  name,
40
39
  sharepoint_configuration=(SharepointConfiguration, Field(description="SharePoint Configuration", json_schema_extra={'configuration_types': ['sharepoint']})),
@@ -64,18 +63,22 @@ class SharepointToolkit(BaseToolkit):
64
63
  **(kwargs.get('pgvector_configuration') or {}),
65
64
  }
66
65
  sharepoint_api_wrapper = SharepointApiWrapper(**wrapper_payload)
67
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
68
66
  available_tools = sharepoint_api_wrapper.get_available_tools()
69
67
  tools = []
70
68
  for tool in available_tools:
71
69
  if selected_tools:
72
70
  if tool["name"] not in selected_tools:
73
71
  continue
72
+ description = f"Sharepoint {sharepoint_api_wrapper.site_url}\n{tool['description']}"
73
+ if toolkit_name:
74
+ description = f"{description}\nToolkit: {toolkit_name}"
75
+ description = description[:1000]
74
76
  tools.append(BaseAction(
75
77
  api_wrapper=sharepoint_api_wrapper,
76
- name=prefix + tool["name"],
77
- description=f"Sharepoint {sharepoint_api_wrapper.site_url}\n{tool['description']}",
78
- args_schema=tool["args_schema"]
78
+ name=tool["name"],
79
+ description=description,
80
+ args_schema=tool["args_schema"],
81
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
79
82
  ))
80
83
  return cls(tools=tools)
81
84
 
@@ -8,6 +8,7 @@ from office365.runtime.auth.client_credential import ClientCredential
8
8
  from office365.sharepoint.client_context import ClientContext
9
9
  from pydantic import Field, PrivateAttr, create_model, model_validator, SecretStr
10
10
 
11
+ from .utils import decode_sharepoint_string
11
12
  from ..non_code_indexer_toolkit import NonCodeIndexerToolkit
12
13
  from ..utils.content_parser import parse_file_content
13
14
  from ...runtime.utils.utils import IndexerKeywords
@@ -19,7 +20,7 @@ NoInput = create_model(
19
20
  ReadList = create_model(
20
21
  "ReadList",
21
22
  list_title=(str, Field(description="Name of a Sharepoint list to be read.")),
22
- limit=(Optional[int], Field(description="Limit (maximum number) of list items to be returned", default=1000))
23
+ limit=(Optional[int], Field(description="Limit (maximum number) of list items to be returned", default=1000, gt=0))
23
24
  )
24
25
 
25
26
  GetFiles = create_model(
@@ -29,7 +30,7 @@ GetFiles = create_model(
29
30
  "Can be called with synonyms, such as First, Top, etc., "
30
31
  "or can be reflected just by a number for example 'Top 10 files'. "
31
32
  "Use default value if not specified in a query WITH NO EXTRA "
32
- "CONFIRMATION FROM A USER", default=100)),
33
+ "CONFIRMATION FROM A USER", default=100, gt=0)),
33
34
  )
34
35
 
35
36
  ReadDocument = create_model(
@@ -91,44 +92,100 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
91
92
  target_list = self._client.web.lists.get_by_title(list_title)
92
93
  self._client.load(target_list)
93
94
  self._client.execute_query()
94
- items = target_list.items.get().top(limit).execute_query()
95
- logging.info("{0} items from sharepoint loaded successfully.".format(len(items)))
95
+ items = target_list.items.top(limit).get().execute_query()
96
+ logging.info("{0} items from sharepoint loaded successfully via SharePoint REST API.".format(len(items)))
96
97
  result = []
97
98
  for item in items:
98
99
  result.append(item.properties)
99
100
  return result
100
- except Exception as e:
101
- logging.error(f"Failed to load items from sharepoint: {e}")
102
- return ToolException("Can not list items. Please, double check List name and read permissions.")
101
+ except Exception as base_e:
102
+ logging.warning(f"Primary SharePoint REST list read failed: {base_e}. Attempting Graph API fallback.")
103
+ # Attempt Graph API fallback
104
+ try:
105
+ from .authorization_helper import SharepointAuthorizationHelper
106
+ auth_helper = SharepointAuthorizationHelper(
107
+ client_id=self.client_id,
108
+ client_secret=self.client_secret.get_secret_value() if self.client_secret else None,
109
+ tenant="", # optional for graph api (derived inside helper)
110
+ scope="", # optional for graph api
111
+ token_json="", # not needed for client credentials flow here
112
+ )
113
+ graph_items = auth_helper.get_list_items(self.site_url, list_title, limit)
114
+ if graph_items:
115
+ logging.info(f"{len(graph_items)} items from sharepoint loaded successfully via Graph API fallback.")
116
+ return graph_items
117
+ else:
118
+ return ToolException("List appears empty or inaccessible via both REST and Graph APIs.")
119
+ except Exception as graph_e:
120
+ logging.error(f"Graph API fallback failed: {graph_e}")
121
+ return ToolException(f"Cannot read list '{list_title}'. Check list name and permissions: {base_e} | {graph_e}")
103
122
 
104
123
 
105
124
  def get_files_list(self, folder_name: str = None, limit_files: int = 100):
106
125
  """ If folder name is specified, lists all files in this folder under Shared Documents path. If folder name is empty, lists all files under root catalog (Shared Documents). Number of files is limited by limit_files (default is 100)."""
107
126
  try:
127
+ # exclude default system libraries like 'Form Templates', 'Site Assets', 'Style Library'
128
+ all_libraries = self._client.web.lists.filter("BaseTemplate eq 101 and Title ne 'Form Templates' and Title ne 'Site Assets' and Title ne 'Style Library'").get().execute_query()
108
129
  result = []
109
130
  if not limit_files:
110
131
  limit_files = 100
111
- target_folder_url = f"Shared Documents/{folder_name}" if folder_name else "Shared Documents"
112
- files = (self._client.web.get_folder_by_server_relative_path(target_folder_url)
113
- .get_files(True)
114
- .execute_query())
115
-
116
- for file in files:
117
- if len(result) >= limit_files:
118
- break
119
- temp_props = {
120
- 'Name': file.properties['Name'],
121
- 'Path': file.properties['ServerRelativeUrl'],
122
- 'Created': file.properties['TimeCreated'],
123
- 'Modified': file.properties['TimeLastModified'],
124
- 'Link': file.properties['LinkingUrl'],
125
- 'id': file.properties['UniqueId']
126
- }
127
- result.append(temp_props)
132
+ #
133
+ site_segments = [seg for seg in self.site_url.strip('/').split('/') if seg][-2:]
134
+ full_path_prefix = '/'.join(site_segments)
135
+ #
136
+ for lib in all_libraries:
137
+ library_type = decode_sharepoint_string(lib.properties["EntityTypeName"])
138
+ target_folder_url = library_type
139
+ if folder_name:
140
+ folder_path = folder_name.strip('/')
141
+ expected_prefix = f'{full_path_prefix}/{library_type}'
142
+ if folder_path.startswith(full_path_prefix):
143
+ if folder_path.startswith(expected_prefix):
144
+ target_folder_url = folder_path.removeprefix(f'{full_path_prefix}/')
145
+ else:
146
+ # ignore full path folder which is not targeted to current library
147
+ continue
148
+ else:
149
+ target_folder_url = f"{library_type}/{folder_name}"
150
+ #
151
+ files = (self._client.web.get_folder_by_server_relative_path(target_folder_url)
152
+ .get_files(True)
153
+ .execute_query())
154
+ #
155
+ for file in files:
156
+ if f"{library_type}/Forms" in file.properties['ServerRelativeUrl']:
157
+ # skip files from system folder "Forms"
158
+ continue
159
+ if len(result) >= limit_files:
160
+ break
161
+ temp_props = {
162
+ 'Name': file.properties['Name'],
163
+ 'Path': file.properties['ServerRelativeUrl'],
164
+ 'Created': file.properties['TimeCreated'],
165
+ 'Modified': file.properties['TimeLastModified'],
166
+ 'Link': file.properties['LinkingUrl'],
167
+ 'id': file.properties['UniqueId']
168
+ }
169
+ result.append(temp_props)
128
170
  return result if result else ToolException("Can not get files or folder is empty. Please, double check folder name and read permissions.")
129
171
  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.")
172
+ # attempt to get via graph api
173
+ try:
174
+ # attempt to get files via graph api
175
+ from .authorization_helper import SharepointAuthorizationHelper
176
+ auth_helper = SharepointAuthorizationHelper(
177
+ client_id=self.client_id,
178
+ client_secret=self.client_secret.get_secret_value(),
179
+ tenant="", # optional for graph api
180
+ scope="", # optional for graph api
181
+ token_json="", # optional for graph api
182
+ )
183
+ files = auth_helper.get_files_list(self.site_url, folder_name, limit_files)
184
+ return files
185
+ except Exception as graph_e:
186
+ logging.error(f"Failed to load files from sharepoint via base api: {e}")
187
+ logging.error(f"Failed to load files from sharepoint via graph api: {graph_e}")
188
+ return ToolException(f"Can not get files. Please, double check folder name and read permissions: {e} and {graph_e}")
132
189
 
133
190
  def read_file(self, path,
134
191
  is_capture_image: bool = False,
@@ -141,11 +198,28 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
141
198
  self._client.load(file).execute_query()
142
199
 
143
200
  file_content = file.read()
201
+ file_name = file.name
144
202
  self._client.execute_query()
145
203
  except Exception as e:
146
- logging.error(f"Failed to load file from SharePoint: {e}. Path: {path}. Please, double check file name and path.")
147
- return ToolException("File not found. Please, check file name and path.")
148
- return parse_file_content(file_name=file.name,
204
+ # attempt to get via graph api
205
+ try:
206
+ # attempt to get files via graph api
207
+ from .authorization_helper import SharepointAuthorizationHelper
208
+ auth_helper = SharepointAuthorizationHelper(
209
+ client_id=self.client_id,
210
+ client_secret=self.client_secret.get_secret_value(),
211
+ tenant="", # optional for graph api
212
+ scope="", # optional for graph api
213
+ token_json="", # optional for graph api
214
+ )
215
+ file_content = auth_helper.get_file_content(self.site_url, path)
216
+ file_name = path.split('/')[-1]
217
+ except Exception as graph_e:
218
+ logging.error(f"Failed to load file from SharePoint via base api: {e}. Path: {path}. Please, double check file name and path.")
219
+ logging.error(f"Failed to load file from SharePoint via graph api: {graph_e}. Path: {path}. Please, double check file name and path.")
220
+ return ToolException(f"File not found. Please, check file name and path: {e} and {graph_e}")
221
+ #
222
+ return parse_file_content(file_name=file_name,
149
223
  file_content=file_content,
150
224
  is_capture_image=is_capture_image,
151
225
  page_number=page_number,
@@ -167,13 +241,18 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
167
241
  'skip_extensions': (Optional[List[str]], Field(
168
242
  description="List of file extensions to skip when processing: i.e. ['*.png', '*.jpg']",
169
243
  default=[])),
244
+ 'path': (Optional[str], Field(
245
+ description="Folder path. "
246
+ "Accepts either a full server-relative path (e.g., '/sites/SiteName/...') or a relative path. "
247
+ "If a relative path is provided, the search will be performed recursively under 'Shared Documents' and other private libraries.",
248
+ default=None)),
170
249
  }
171
250
 
172
251
  def _base_loader(self, **kwargs) -> Generator[Document, None, None]:
173
252
 
174
253
  self._log_tool_event(message="Starting SharePoint files extraction", tool_name="loader")
175
254
  try:
176
- all_files = self.get_files_list(limit_files=kwargs.get('limit_files', 10000))
255
+ all_files = self.get_files_list(kwargs.get('path'), kwargs.get('limit_files', 10000))
177
256
  self._log_tool_event(message="List of the files has been extracted", tool_name="loader")
178
257
  except Exception as e:
179
258
  raise ToolException(f"Unable to extract files: {e}")
@@ -192,13 +271,13 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
192
271
  file_name = file.get('Name', '')
193
272
 
194
273
  # Check if file should be skipped based on skip_extensions
195
- if any(re.match(pattern.replace('*', '.*') + '$', file_name, re.IGNORECASE)
274
+ if any(re.match(re.escape(pattern).replace(r'\*', '.*') + '$', file_name, re.IGNORECASE)
196
275
  for pattern in skip_extensions):
197
276
  continue
198
277
 
199
278
  # Check if file should be included based on include_extensions
200
279
  # If include_extensions is empty, process all files (that weren't skipped)
201
- if include_extensions and not (any(re.match(pattern.replace('*', '.*') + '$', file_name, re.IGNORECASE)
280
+ if include_extensions and not (any(re.match(re.escape(pattern).replace(r'\*', '.*') + '$', file_name, re.IGNORECASE)
202
281
  for pattern in include_extensions)):
203
282
  continue
204
283
 
@@ -219,12 +298,24 @@ class SharepointApiWrapper(NonCodeIndexerToolkit):
219
298
  yield document
220
299
 
221
300
  def _load_file_content_in_bytes(self, path):
222
- file = self._client.web.get_file_by_server_relative_path(path)
223
- self._client.load(file).execute_query()
224
- file_content = file.read()
225
- self._client.execute_query()
226
- #
227
- return file_content
301
+ try:
302
+ file = self._client.web.get_file_by_server_relative_path(path)
303
+ self._client.load(file).execute_query()
304
+ file_content = file.read()
305
+ self._client.execute_query()
306
+ #
307
+ return file_content
308
+ except Exception as e:
309
+ # attempt to get via graph api
310
+ from .authorization_helper import SharepointAuthorizationHelper
311
+ auth_helper = SharepointAuthorizationHelper(
312
+ client_id=self.client_id,
313
+ client_secret=self.client_secret.get_secret_value(),
314
+ tenant="", # optional for graph api
315
+ scope="", # optional for graph api
316
+ token_json="", # optional for graph api
317
+ )
318
+ return auth_helper.get_file_content(self.site_url, path)
228
319
 
229
320
  def get_available_tools(self):
230
321
  return super().get_available_tools() + [