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

Files changed (281) 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 +155 -0
  6. alita_sdk/cli/agent_loader.py +215 -0
  7. alita_sdk/cli/agent_ui.py +228 -0
  8. alita_sdk/cli/agents.py +3794 -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/toolkit.py +327 -0
  23. alita_sdk/cli/toolkit_loader.py +85 -0
  24. alita_sdk/cli/tools/__init__.py +43 -0
  25. alita_sdk/cli/tools/approval.py +224 -0
  26. alita_sdk/cli/tools/filesystem.py +1751 -0
  27. alita_sdk/cli/tools/planning.py +389 -0
  28. alita_sdk/cli/tools/terminal.py +414 -0
  29. alita_sdk/community/__init__.py +72 -12
  30. alita_sdk/community/inventory/__init__.py +236 -0
  31. alita_sdk/community/inventory/config.py +257 -0
  32. alita_sdk/community/inventory/enrichment.py +2137 -0
  33. alita_sdk/community/inventory/extractors.py +1469 -0
  34. alita_sdk/community/inventory/ingestion.py +3172 -0
  35. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  36. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  37. alita_sdk/community/inventory/parsers/base.py +295 -0
  38. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  39. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  40. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  41. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  42. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  43. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  44. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  45. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  46. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  47. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  48. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  49. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  50. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  51. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  52. alita_sdk/community/inventory/patterns/loader.py +348 -0
  53. alita_sdk/community/inventory/patterns/registry.py +198 -0
  54. alita_sdk/community/inventory/presets.py +535 -0
  55. alita_sdk/community/inventory/retrieval.py +1403 -0
  56. alita_sdk/community/inventory/toolkit.py +173 -0
  57. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  58. alita_sdk/community/inventory/visualize.py +1370 -0
  59. alita_sdk/configurations/__init__.py +11 -0
  60. alita_sdk/configurations/ado.py +148 -2
  61. alita_sdk/configurations/azure_search.py +1 -1
  62. alita_sdk/configurations/bigquery.py +1 -1
  63. alita_sdk/configurations/bitbucket.py +94 -2
  64. alita_sdk/configurations/browser.py +18 -0
  65. alita_sdk/configurations/carrier.py +19 -0
  66. alita_sdk/configurations/confluence.py +130 -1
  67. alita_sdk/configurations/delta_lake.py +1 -1
  68. alita_sdk/configurations/figma.py +76 -5
  69. alita_sdk/configurations/github.py +65 -1
  70. alita_sdk/configurations/gitlab.py +81 -0
  71. alita_sdk/configurations/google_places.py +17 -0
  72. alita_sdk/configurations/jira.py +103 -0
  73. alita_sdk/configurations/openapi.py +323 -0
  74. alita_sdk/configurations/postman.py +1 -1
  75. alita_sdk/configurations/qtest.py +72 -3
  76. alita_sdk/configurations/report_portal.py +115 -0
  77. alita_sdk/configurations/salesforce.py +19 -0
  78. alita_sdk/configurations/service_now.py +1 -12
  79. alita_sdk/configurations/sharepoint.py +167 -0
  80. alita_sdk/configurations/sonar.py +18 -0
  81. alita_sdk/configurations/sql.py +20 -0
  82. alita_sdk/configurations/testio.py +101 -0
  83. alita_sdk/configurations/testrail.py +88 -0
  84. alita_sdk/configurations/xray.py +94 -1
  85. alita_sdk/configurations/zephyr_enterprise.py +94 -1
  86. alita_sdk/configurations/zephyr_essential.py +95 -0
  87. alita_sdk/runtime/clients/artifact.py +21 -4
  88. alita_sdk/runtime/clients/client.py +458 -67
  89. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  90. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  91. alita_sdk/runtime/clients/sandbox_client.py +352 -0
  92. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  93. alita_sdk/runtime/langchain/assistant.py +183 -43
  94. alita_sdk/runtime/langchain/constants.py +647 -1
  95. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  96. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
  97. alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
  98. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  99. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
  100. alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
  101. alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
  102. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
  103. alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
  104. alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
  105. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
  106. alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
  107. alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
  108. alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
  109. alita_sdk/runtime/langchain/langraph_agent.py +493 -105
  110. alita_sdk/runtime/langchain/utils.py +118 -8
  111. alita_sdk/runtime/llms/preloaded.py +2 -6
  112. alita_sdk/runtime/models/mcp_models.py +61 -0
  113. alita_sdk/runtime/skills/__init__.py +91 -0
  114. alita_sdk/runtime/skills/callbacks.py +498 -0
  115. alita_sdk/runtime/skills/discovery.py +540 -0
  116. alita_sdk/runtime/skills/executor.py +610 -0
  117. alita_sdk/runtime/skills/input_builder.py +371 -0
  118. alita_sdk/runtime/skills/models.py +330 -0
  119. alita_sdk/runtime/skills/registry.py +355 -0
  120. alita_sdk/runtime/skills/skill_runner.py +330 -0
  121. alita_sdk/runtime/toolkits/__init__.py +28 -0
  122. alita_sdk/runtime/toolkits/application.py +14 -4
  123. alita_sdk/runtime/toolkits/artifact.py +25 -9
  124. alita_sdk/runtime/toolkits/datasource.py +13 -6
  125. alita_sdk/runtime/toolkits/mcp.py +782 -0
  126. alita_sdk/runtime/toolkits/planning.py +178 -0
  127. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  128. alita_sdk/runtime/toolkits/subgraph.py +11 -6
  129. alita_sdk/runtime/toolkits/tools.py +314 -70
  130. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  131. alita_sdk/runtime/tools/__init__.py +24 -0
  132. alita_sdk/runtime/tools/application.py +16 -4
  133. alita_sdk/runtime/tools/artifact.py +367 -33
  134. alita_sdk/runtime/tools/data_analysis.py +183 -0
  135. alita_sdk/runtime/tools/function.py +100 -4
  136. alita_sdk/runtime/tools/graph.py +81 -0
  137. alita_sdk/runtime/tools/image_generation.py +218 -0
  138. alita_sdk/runtime/tools/llm.py +1032 -177
  139. alita_sdk/runtime/tools/loop.py +3 -1
  140. alita_sdk/runtime/tools/loop_output.py +3 -1
  141. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  142. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  143. alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
  144. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  145. alita_sdk/runtime/tools/planning/models.py +246 -0
  146. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  147. alita_sdk/runtime/tools/router.py +2 -1
  148. alita_sdk/runtime/tools/sandbox.py +375 -0
  149. alita_sdk/runtime/tools/skill_router.py +776 -0
  150. alita_sdk/runtime/tools/tool.py +3 -1
  151. alita_sdk/runtime/tools/vectorstore.py +69 -65
  152. alita_sdk/runtime/tools/vectorstore_base.py +163 -90
  153. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  154. alita_sdk/runtime/utils/constants.py +5 -1
  155. alita_sdk/runtime/utils/mcp_client.py +492 -0
  156. alita_sdk/runtime/utils/mcp_oauth.py +361 -0
  157. alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
  158. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  159. alita_sdk/runtime/utils/streamlit.py +41 -14
  160. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  161. alita_sdk/runtime/utils/utils.py +48 -0
  162. alita_sdk/tools/__init__.py +135 -37
  163. alita_sdk/tools/ado/__init__.py +2 -2
  164. alita_sdk/tools/ado/repos/__init__.py +16 -19
  165. alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
  166. alita_sdk/tools/ado/test_plan/__init__.py +27 -8
  167. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
  168. alita_sdk/tools/ado/wiki/__init__.py +28 -12
  169. alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
  170. alita_sdk/tools/ado/work_item/__init__.py +28 -12
  171. alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
  172. alita_sdk/tools/advanced_jira_mining/__init__.py +13 -8
  173. alita_sdk/tools/aws/delta_lake/__init__.py +15 -11
  174. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  175. alita_sdk/tools/azure_ai/search/__init__.py +14 -8
  176. alita_sdk/tools/base/tool.py +5 -1
  177. alita_sdk/tools/base_indexer_toolkit.py +454 -110
  178. alita_sdk/tools/bitbucket/__init__.py +28 -19
  179. alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
  180. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
  181. alita_sdk/tools/browser/__init__.py +41 -16
  182. alita_sdk/tools/browser/crawler.py +3 -1
  183. alita_sdk/tools/browser/utils.py +15 -6
  184. alita_sdk/tools/carrier/__init__.py +18 -17
  185. alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
  186. alita_sdk/tools/carrier/excel_reporter.py +8 -4
  187. alita_sdk/tools/chunkers/__init__.py +3 -1
  188. alita_sdk/tools/chunkers/code/codeparser.py +1 -1
  189. alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
  190. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  191. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  192. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  193. alita_sdk/tools/cloud/aws/__init__.py +12 -7
  194. alita_sdk/tools/cloud/azure/__init__.py +12 -7
  195. alita_sdk/tools/cloud/gcp/__init__.py +12 -7
  196. alita_sdk/tools/cloud/k8s/__init__.py +12 -7
  197. alita_sdk/tools/code/linter/__init__.py +10 -8
  198. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  199. alita_sdk/tools/code/sonar/__init__.py +21 -13
  200. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  201. alita_sdk/tools/confluence/__init__.py +22 -14
  202. alita_sdk/tools/confluence/api_wrapper.py +197 -58
  203. alita_sdk/tools/confluence/loader.py +14 -2
  204. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  205. alita_sdk/tools/elastic/__init__.py +11 -8
  206. alita_sdk/tools/elitea_base.py +546 -64
  207. alita_sdk/tools/figma/__init__.py +60 -11
  208. alita_sdk/tools/figma/api_wrapper.py +1400 -167
  209. alita_sdk/tools/figma/figma_client.py +73 -0
  210. alita_sdk/tools/figma/toon_tools.py +2748 -0
  211. alita_sdk/tools/github/__init__.py +18 -17
  212. alita_sdk/tools/github/api_wrapper.py +9 -26
  213. alita_sdk/tools/github/github_client.py +81 -12
  214. alita_sdk/tools/github/schemas.py +2 -1
  215. alita_sdk/tools/github/tool.py +5 -1
  216. alita_sdk/tools/gitlab/__init__.py +19 -13
  217. alita_sdk/tools/gitlab/api_wrapper.py +256 -80
  218. alita_sdk/tools/gitlab_org/__init__.py +14 -10
  219. alita_sdk/tools/google/bigquery/__init__.py +14 -13
  220. alita_sdk/tools/google/bigquery/tool.py +5 -1
  221. alita_sdk/tools/google_places/__init__.py +21 -11
  222. alita_sdk/tools/jira/__init__.py +22 -11
  223. alita_sdk/tools/jira/api_wrapper.py +315 -168
  224. alita_sdk/tools/keycloak/__init__.py +11 -8
  225. alita_sdk/tools/localgit/__init__.py +9 -3
  226. alita_sdk/tools/localgit/local_git.py +62 -54
  227. alita_sdk/tools/localgit/tool.py +5 -1
  228. alita_sdk/tools/memory/__init__.py +38 -14
  229. alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
  230. alita_sdk/tools/ocr/__init__.py +11 -8
  231. alita_sdk/tools/openapi/__init__.py +491 -106
  232. alita_sdk/tools/openapi/api_wrapper.py +1357 -0
  233. alita_sdk/tools/openapi/tool.py +20 -0
  234. alita_sdk/tools/pandas/__init__.py +20 -12
  235. alita_sdk/tools/pandas/api_wrapper.py +40 -45
  236. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  237. alita_sdk/tools/postman/__init__.py +11 -11
  238. alita_sdk/tools/postman/api_wrapper.py +19 -8
  239. alita_sdk/tools/postman/postman_analysis.py +8 -1
  240. alita_sdk/tools/pptx/__init__.py +11 -10
  241. alita_sdk/tools/qtest/__init__.py +22 -14
  242. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  243. alita_sdk/tools/rally/__init__.py +13 -10
  244. alita_sdk/tools/report_portal/__init__.py +23 -16
  245. alita_sdk/tools/salesforce/__init__.py +22 -16
  246. alita_sdk/tools/servicenow/__init__.py +21 -16
  247. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  248. alita_sdk/tools/sharepoint/__init__.py +17 -14
  249. alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
  250. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  251. alita_sdk/tools/sharepoint/utils.py +8 -2
  252. alita_sdk/tools/slack/__init__.py +13 -8
  253. alita_sdk/tools/sql/__init__.py +22 -19
  254. alita_sdk/tools/sql/api_wrapper.py +71 -23
  255. alita_sdk/tools/testio/__init__.py +21 -13
  256. alita_sdk/tools/testrail/__init__.py +13 -11
  257. alita_sdk/tools/testrail/api_wrapper.py +214 -46
  258. alita_sdk/tools/utils/__init__.py +28 -4
  259. alita_sdk/tools/utils/content_parser.py +241 -55
  260. alita_sdk/tools/utils/text_operations.py +254 -0
  261. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
  262. alita_sdk/tools/xray/__init__.py +18 -14
  263. alita_sdk/tools/xray/api_wrapper.py +58 -113
  264. alita_sdk/tools/yagmail/__init__.py +9 -3
  265. alita_sdk/tools/zephyr/__init__.py +12 -7
  266. alita_sdk/tools/zephyr_enterprise/__init__.py +16 -9
  267. alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
  268. alita_sdk/tools/zephyr_essential/__init__.py +16 -10
  269. alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
  270. alita_sdk/tools/zephyr_essential/client.py +6 -4
  271. alita_sdk/tools/zephyr_scale/__init__.py +13 -8
  272. alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
  273. alita_sdk/tools/zephyr_squad/__init__.py +12 -7
  274. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/METADATA +184 -37
  275. alita_sdk-0.3.584.dist-info/RECORD +452 -0
  276. alita_sdk-0.3.584.dist-info/entry_points.txt +2 -0
  277. alita_sdk/tools/bitbucket/tools.py +0 -304
  278. alita_sdk-0.3.257.dist-info/RECORD +0 -343
  279. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/WHEEL +0 -0
  280. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/licenses/LICENSE +0 -0
  281. {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,8 @@ from pydantic import BaseModel, ConfigDict, create_model, Field, SecretStr
5
5
 
6
6
  from .api_wrapper import KeycloakApiWrapper
7
7
  from ..base.tool import BaseAction
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
9
10
 
10
11
  name = "keycloak"
11
12
 
@@ -21,15 +22,13 @@ def get_tools(tool):
21
22
 
22
23
  class KeycloakToolkit(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 KeycloakApiWrapper.model_construct().get_available_tools()}
29
- KeycloakToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
29
  return create_model(
31
30
  name,
32
- base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': KeycloakToolkit.toolkit_max_length})),
31
+ base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True})),
33
32
  realm=(str, Field(default="", title="Realm", description="Keycloak realm")),
34
33
  client_id=(str, Field(default="", title="Client ID", description="Keycloak client ID")),
35
34
  client_secret=(SecretStr, Field(default="", title="Client sercet", description="Keycloak client secret", json_schema_extra={'secret': True})),
@@ -42,17 +41,21 @@ class KeycloakToolkit(BaseToolkit):
42
41
  if selected_tools is None:
43
42
  selected_tools = []
44
43
  keycloak_api_wrapper = KeycloakApiWrapper(**kwargs)
45
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
46
44
  available_tools = keycloak_api_wrapper.get_available_tools()
47
45
  tools = []
48
46
  for tool in available_tools:
49
47
  if selected_tools and tool["name"] not in selected_tools:
50
48
  continue
49
+ description = f"{tool['description']}\nUrl: {keycloak_api_wrapper.base_url}"
50
+ if toolkit_name:
51
+ description = f"{description}\nToolkit: {toolkit_name}"
52
+ description = description[:1000]
51
53
  tools.append(BaseAction(
52
54
  api_wrapper=keycloak_api_wrapper,
53
- name=prefix + tool["name"],
54
- description=f"{tool['description']}\nUrl: {keycloak_api_wrapper.base_url}",
55
- args_schema=tool["args_schema"]
55
+ name=tool["name"],
56
+ description=description,
57
+ args_schema=tool["args_schema"],
58
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
56
59
  ))
57
60
  return cls(tools=tools)
58
61
 
@@ -5,6 +5,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field
5
5
 
6
6
  from .local_git import LocalGit
7
7
  from .tool import LocalGitAction
8
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
8
9
 
9
10
  name = "localgit"
10
11
 
@@ -34,7 +35,7 @@ class AlitaLocalGitToolkit(BaseToolkit):
34
35
  )
35
36
 
36
37
  @classmethod
37
- def get_toolkit(cls, selected_tools: list[str] | None = None, **kwargs):
38
+ def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
38
39
  if selected_tools is None:
39
40
  selected_tools = []
40
41
  local_git_tool = LocalGit(**kwargs)
@@ -45,12 +46,17 @@ class AlitaLocalGitToolkit(BaseToolkit):
45
46
  if selected_tools:
46
47
  if tool["name"] not in selected_tools:
47
48
  continue
49
+ description = tool["description"]
50
+ if toolkit_name:
51
+ description = f"Toolkit: {toolkit_name}\n{description}"
52
+ description = description[:1000]
48
53
  tools.append(LocalGitAction(
49
54
  api_wrapper=local_git_tool,
50
55
  name=repo + "_" + tool["name"],
51
56
  mode=tool["mode"],
52
- description=tool["description"],
53
- args_schema=tool["args_schema"]
57
+ description=description,
58
+ args_schema=tool["args_schema"],
59
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
54
60
  ))
55
61
  return cls(tools=tools)
56
62
 
@@ -8,7 +8,8 @@ from git import Repo
8
8
  from pydantic import BaseModel, Field, create_model, model_validator
9
9
  from langchain_core.tools import ToolException
10
10
 
11
- from ..elitea_base import BaseToolApiWrapper
11
+ from ..elitea_base import BaseToolApiWrapper, extend_with_file_operations, BaseCodeToolApiWrapper
12
+ from ..utils.text_operations import parse_old_new_markers
12
13
 
13
14
  logger = logging.getLogger(__name__)
14
15
  CREATE_FILE_PROMPT = """Create new file in your local repository."""
@@ -110,6 +111,12 @@ class LocalGit(BaseToolApiWrapper):
110
111
  repo_url: str = None
111
112
  commit_sha: str = None
112
113
  path_pattern: str = '**/*.py'
114
+
115
+ # Import file operation methods from BaseCodeToolApiWrapper
116
+ read_file_chunk = BaseCodeToolApiWrapper.read_file_chunk
117
+ read_multiple_files = BaseCodeToolApiWrapper.read_multiple_files
118
+ search_file = BaseCodeToolApiWrapper.search_file
119
+ edit_file = BaseCodeToolApiWrapper.edit_file
113
120
 
114
121
  @model_validator(mode='before')
115
122
  @classmethod
@@ -128,58 +135,6 @@ class LocalGit(BaseToolApiWrapper):
128
135
  repo.head.reset(commit=commit_sha, working_tree=True)
129
136
  return values
130
137
 
131
- def extract_old_new_pairs(self, file_query):
132
- # Split the file content by lines
133
- code_lines = file_query.split("\n")
134
-
135
- # Initialize lists to hold the contents of OLD and NEW sections
136
- old_contents = []
137
- new_contents = []
138
-
139
- # Initialize variables to track whether the current line is within an OLD or NEW section
140
- in_old_section = False
141
- in_new_section = False
142
-
143
- # Temporary storage for the current section's content
144
- current_section_content = []
145
-
146
- # Iterate through each line in the file content
147
- for line in code_lines:
148
- # Check for OLD section start
149
- if "OLD <<<" in line:
150
- in_old_section = True
151
- current_section_content = [] # Reset current section content
152
- continue # Skip the line with the marker
153
-
154
- # Check for OLD section end
155
- if ">>>> OLD" in line:
156
- in_old_section = False
157
- old_contents.append("\n".join(current_section_content).strip()) # Add the captured content
158
- current_section_content = [] # Reset current section content
159
- continue # Skip the line with the marker
160
-
161
- # Check for NEW section start
162
- if "NEW <<<" in line:
163
- in_new_section = True
164
- current_section_content = [] # Reset current section content
165
- continue # Skip the line with the marker
166
-
167
- # Check for NEW section end
168
- if ">>>> NEW" in line:
169
- in_new_section = False
170
- new_contents.append("\n".join(current_section_content).strip()) # Add the captured content
171
- current_section_content = [] # Reset current section content
172
- continue # Skip the line with the marker
173
-
174
- # If currently in an OLD or NEW section, add the line to the current section content
175
- if in_old_section or in_new_section:
176
- current_section_content.append(line)
177
-
178
- # Pair the OLD and NEW contents
179
- paired_contents = list(zip(old_contents, new_contents))
180
-
181
- return paired_contents
182
-
183
138
  def checkout_commit(self, commit_sha: str) -> str:
184
139
  """ Checkout specific commit from repository """
185
140
  try:
@@ -233,6 +188,58 @@ class LocalGit(BaseToolApiWrapper):
233
188
  return f.read()
234
189
  else:
235
190
  return "File '{}' cannot be read because it is not existed".format(file_path)
191
+
192
+ def _read_file(self, file_path: str, branch: str = None, **kwargs) -> str:
193
+ """
194
+ Read a file from the repository with optional partial read support.
195
+
196
+ Parameters:
197
+ file_path: the file path (relative to repo root)
198
+ branch: branch name (not used for local git, always reads from working dir)
199
+ **kwargs: Additional parameters (offset, limit, head, tail) - currently ignored,
200
+ partial read handled client-side by base class methods
201
+
202
+ Returns:
203
+ File content as string
204
+ """
205
+ return self.read_file(file_path)
206
+
207
+ def _write_file(
208
+ self,
209
+ file_path: str,
210
+ content: str,
211
+ branch: str = None,
212
+ commit_message: str = None
213
+ ) -> str:
214
+ """
215
+ Write content to a file (create or update).
216
+
217
+ Parameters:
218
+ file_path: Path to the file (relative to repo root)
219
+ content: New file content
220
+ branch: Branch name (not used for local git)
221
+ commit_message: Commit message (not used - files are written without commit)
222
+
223
+ Returns:
224
+ Success message
225
+ """
226
+ try:
227
+ full_path = os.path.normpath(os.path.join(self.repo.working_dir, file_path))
228
+
229
+ # Ensure directory exists
230
+ os.makedirs(os.path.dirname(full_path), exist_ok=True)
231
+
232
+ # Write the file
233
+ with open(full_path, 'w') as f:
234
+ f.write(content)
235
+
236
+ # Determine if file was created or updated
237
+ if os.path.exists(full_path):
238
+ return f"Updated file {file_path}"
239
+ else:
240
+ return f"Created file {file_path}"
241
+ except Exception as e:
242
+ raise ToolException(f"Unable to write file {file_path}: {str(e)}")
236
243
 
237
244
  def update_file_content_by_lines(self, file_path: str, start_line_index: int, end_line_index: int,
238
245
  new_content: str) -> str:
@@ -314,7 +321,7 @@ class LocalGit(BaseToolApiWrapper):
314
321
  file_path = os.path.normpath(os.path.join(self.repo.working_dir, file_path))
315
322
  file_content = self.read_file(file_path)
316
323
  updated_file_content = file_content
317
- for old, new in self.extract_old_new_pairs(file_query):
324
+ for old, new in parse_old_new_markers(file_query): # Use shared utility
318
325
  if not old.strip():
319
326
  continue
320
327
  updated_file_content = updated_file_content.replace(old, new)
@@ -332,6 +339,7 @@ class LocalGit(BaseToolApiWrapper):
332
339
  except Exception as e:
333
340
  return "Unable to update file due to error:\n" + str(e)
334
341
 
342
+ @extend_with_file_operations
335
343
  def get_available_tools(self):
336
344
  return [
337
345
  {
@@ -29,6 +29,10 @@ class LocalGitAction(BaseTool):
29
29
  ) -> str:
30
30
  """Use the GitHub API to run an operation."""
31
31
  try:
32
- return self.api_wrapper.run(self.mode, *args, **kwargs)
32
+ # Strip numeric suffix added for deduplication (_2, _3, etc.)
33
+ # to get the original tool name that exists in the wrapper
34
+ import re
35
+ mode = re.sub(r'_\d+$', '', self.mode) if self.mode else self.mode
36
+ return self.api_wrapper.run(mode, *args, **kwargs)
33
37
  except Exception as e:
34
38
  return f"Error: {format_exc()}"
@@ -1,6 +1,8 @@
1
- from typing import Optional, List
1
+ from typing import List, Literal
2
2
 
3
- from langchain_core.tools import BaseToolkit, BaseTool
3
+ from langchain_core.tools import BaseToolkit, BaseTool, ToolException
4
+
5
+ from alita_sdk.configurations.pgvector import PgVectorConfiguration
4
6
 
5
7
  try:
6
8
  from langmem import create_manage_memory_tool, create_search_memory_tool
@@ -15,7 +17,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field, SecretStr
15
17
 
16
18
  name = "memory"
17
19
 
18
- def get_tools(tools_list: list, alita_client, llm, memory_store=None):
20
+ def get_tools(tools_list: list, memory_store=None):
19
21
  """
20
22
  Get memory tools for the provided tool configurations.
21
23
 
@@ -35,8 +37,9 @@ def get_tools(tools_list: list, alita_client, llm, memory_store=None):
35
37
  try:
36
38
  toolkit_instance = MemoryToolkit().get_toolkit(
37
39
  namespace=tool['settings'].get('namespace', str(tool['id'])),
38
- username=tool['settings'].get('username', ''),
40
+ # username=tool['settings'].get('username', ''),
39
41
  store=tool['settings'].get('store', memory_store),
42
+ pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
40
43
  toolkit_name=tool.get('toolkit_name', '')
41
44
  )
42
45
  all_tools.extend(toolkit_instance.get_tools())
@@ -53,18 +56,23 @@ class MemoryToolkit(BaseToolkit):
53
56
 
54
57
  @staticmethod
55
58
  def toolkit_config_schema() -> BaseModel:
59
+ memory_tools = [create_manage_memory_tool('test'), create_search_memory_tool('test')]
60
+ selected_tools = {x.name: x.args_schema.schema() for x in memory_tools}
61
+
56
62
  return create_model(
57
- 'MemoryConfig',
58
- namespace=(str, Field(description="Memory namespace", json_schema_extra={'toolkit_name': True})),
59
- username=(Optional[str], Field(description="Username", default='Tester', json_schema_extra={'hidden': True})),
60
- connection_string=(Optional[SecretStr], Field(description="Connection string for vectorstore",
61
- default=None,
62
- json_schema_extra={'secret': True})),
63
+ 'memory',
64
+ namespace=(str, Field(description="Memory namespace")),
65
+ pgvector_configuration=(PgVectorConfiguration, Field(description="PgVector Configuration",
66
+ json_schema_extra={
67
+ 'configuration_types': ['pgvector']})),
68
+ selected_tools=(List[Literal[tuple(selected_tools)]],
69
+ Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
70
+
63
71
  __config__=ConfigDict(json_schema_extra={
64
72
  'metadata': {
65
73
  "label": "Memory",
66
74
  "icon_url": "memory.svg",
67
- "hidden": True,
75
+ "hidden": False,
68
76
  "categories": ["other"],
69
77
  "extra_categories": ["long-term memory", "langmem"],
70
78
  }
@@ -72,13 +80,14 @@ class MemoryToolkit(BaseToolkit):
72
80
  )
73
81
 
74
82
  @classmethod
75
- def get_toolkit(cls, namespace: str, store=None, **kwargs):
83
+ def get_toolkit(cls, namespace: str, store=None, toolkit_name: str = None, **kwargs):
76
84
  """
77
85
  Get toolkit with memory tools.
78
86
 
79
87
  Args:
80
88
  namespace: Memory namespace
81
89
  store: PostgresStore instance (imported dynamically)
90
+ toolkit_name: Optional toolkit name for metadata
82
91
  **kwargs: Additional arguments
83
92
  """
84
93
  try:
@@ -88,15 +97,30 @@ class MemoryToolkit(BaseToolkit):
88
97
  "PostgreSQL dependencies (psycopg) are required for MemoryToolkit. "
89
98
  "Install with: pip install psycopg[binary]"
90
99
  )
100
+
101
+ if store is None:
102
+ # The store is not provided, attempt to create it from configuration
103
+ from ...runtime.langchain.store_manager import get_manager
104
+ conn_str = (kwargs.get('pgvector_configuration') or {}).get('connection_string', '')
105
+ if not conn_str:
106
+ raise ToolException("Connection string is required to create PostgresStore for memory toolkit.")
107
+ store = get_manager().get_store(conn_str)
91
108
 
92
109
  # Validate store type
93
110
  if store is not None and not isinstance(store, PostgresStore):
94
111
  raise TypeError(f"Expected PostgresStore, got {type(store)}")
95
112
 
96
- return cls(tools=[
113
+ tools = [
97
114
  create_manage_memory_tool(namespace=namespace, store=store),
98
115
  create_search_memory_tool(namespace=namespace, store=store)
99
- ])
116
+ ]
117
+
118
+ # Add metadata to tools if toolkit_name is provided
119
+ if toolkit_name:
120
+ for tool in tools:
121
+ tool.metadata = {"toolkit_name": toolkit_name, "toolkit_type": name}
122
+
123
+ return cls(tools=tools)
100
124
 
101
125
  def get_tools(self):
102
126
  return self.tools
@@ -1,12 +1,17 @@
1
1
  from langchain_core.documents import Document
2
+ from langchain_core.tools import ToolException
2
3
 
3
4
  from alita_sdk.runtime.utils.utils import IndexerKeywords
4
5
  from alita_sdk.tools.base_indexer_toolkit import BaseIndexerToolkit
5
6
 
6
7
 
7
8
  class NonCodeIndexerToolkit(BaseIndexerToolkit):
8
- def _get_indexed_data(self, collection_suffix: str):
9
- return self.vector_adapter.get_indexed_data(self, collection_suffix)
9
+ def _get_indexed_data(self, index_name: str):
10
+ self._ensure_vectorstore_initialized()
11
+ if not self.vector_adapter:
12
+ raise ToolException("Vector adapter is not initialized. "
13
+ "Check your configuration: embedding_model and vectorstore_type.")
14
+ return self.vector_adapter.get_indexed_data(self, index_name)
10
15
 
11
16
  def key_fn(self, document: Document):
12
17
  return document.metadata.get('id')
@@ -5,7 +5,8 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
5
5
 
6
6
  from .api_wrapper import OCRApiWrapper
7
7
  from ..base.tool import BaseAction
8
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
8
+ from ..utils import clean_string, get_max_toolkit_length
9
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
9
10
 
10
11
  name = "ocr"
11
12
 
@@ -23,15 +24,13 @@ def get_tools(tool):
23
24
 
24
25
  class OCRToolkit(BaseToolkit):
25
26
  tools: list[BaseTool] = []
26
- toolkit_max_length: int = 0
27
27
 
28
28
  @staticmethod
29
29
  def toolkit_config_schema() -> BaseModel:
30
30
  selected_tools = {x['name']: x['args_schema'].schema() for x in OCRApiWrapper.model_construct().get_available_tools()}
31
- OCRToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
32
31
  return create_model(
33
32
  name,
34
- artifacts_folder=(str, Field(description="Folder path containing artifacts to process", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': OCRToolkit.toolkit_max_length})),
33
+ artifacts_folder=(str, Field(description="Folder path containing artifacts to process", json_schema_extra={'toolkit_name': True})),
35
34
  tesseract_settings=(dict, Field(description="Settings for Tesseract OCR processing", default={})),
36
35
  structured_output=(bool, Field(description="Whether to return structured JSON output", default=False)),
37
36
  expected_fields=(dict, Field(description="Expected fields for structured output", default={})),
@@ -47,17 +46,21 @@ class OCRToolkit(BaseToolkit):
47
46
  if selected_tools is None:
48
47
  selected_tools = []
49
48
  ocr_api_wrapper = OCRApiWrapper(**kwargs)
50
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
51
49
  available_tools = ocr_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 = description[:1000]
56
58
  tools.append(BaseAction(
57
59
  api_wrapper=ocr_api_wrapper,
58
- name=prefix + tool["name"],
59
- description=tool["description"],
60
- 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"]}
61
64
  ))
62
65
  return cls(tools=tools)
63
66