alita-sdk 0.3.462__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 (261) hide show
  1. alita_sdk/cli/agent/__init__.py +5 -0
  2. alita_sdk/cli/agent/default.py +258 -0
  3. alita_sdk/cli/agent_executor.py +15 -3
  4. alita_sdk/cli/agent_loader.py +56 -8
  5. alita_sdk/cli/agent_ui.py +93 -31
  6. alita_sdk/cli/agents.py +2274 -230
  7. alita_sdk/cli/callbacks.py +96 -25
  8. alita_sdk/cli/cli.py +10 -1
  9. alita_sdk/cli/config.py +162 -9
  10. alita_sdk/cli/context/__init__.py +30 -0
  11. alita_sdk/cli/context/cleanup.py +198 -0
  12. alita_sdk/cli/context/manager.py +731 -0
  13. alita_sdk/cli/context/message.py +285 -0
  14. alita_sdk/cli/context/strategies.py +289 -0
  15. alita_sdk/cli/context/token_estimation.py +127 -0
  16. alita_sdk/cli/input_handler.py +419 -0
  17. alita_sdk/cli/inventory.py +1073 -0
  18. alita_sdk/cli/testcases/__init__.py +94 -0
  19. alita_sdk/cli/testcases/data_generation.py +119 -0
  20. alita_sdk/cli/testcases/discovery.py +96 -0
  21. alita_sdk/cli/testcases/executor.py +84 -0
  22. alita_sdk/cli/testcases/logger.py +85 -0
  23. alita_sdk/cli/testcases/parser.py +172 -0
  24. alita_sdk/cli/testcases/prompts.py +91 -0
  25. alita_sdk/cli/testcases/reporting.py +125 -0
  26. alita_sdk/cli/testcases/setup.py +108 -0
  27. alita_sdk/cli/testcases/test_runner.py +282 -0
  28. alita_sdk/cli/testcases/utils.py +39 -0
  29. alita_sdk/cli/testcases/validation.py +90 -0
  30. alita_sdk/cli/testcases/workflow.py +196 -0
  31. alita_sdk/cli/toolkit.py +14 -17
  32. alita_sdk/cli/toolkit_loader.py +35 -5
  33. alita_sdk/cli/tools/__init__.py +36 -2
  34. alita_sdk/cli/tools/approval.py +224 -0
  35. alita_sdk/cli/tools/filesystem.py +910 -64
  36. alita_sdk/cli/tools/planning.py +389 -0
  37. alita_sdk/cli/tools/terminal.py +414 -0
  38. alita_sdk/community/__init__.py +72 -12
  39. alita_sdk/community/inventory/__init__.py +236 -0
  40. alita_sdk/community/inventory/config.py +257 -0
  41. alita_sdk/community/inventory/enrichment.py +2137 -0
  42. alita_sdk/community/inventory/extractors.py +1469 -0
  43. alita_sdk/community/inventory/ingestion.py +3172 -0
  44. alita_sdk/community/inventory/knowledge_graph.py +1457 -0
  45. alita_sdk/community/inventory/parsers/__init__.py +218 -0
  46. alita_sdk/community/inventory/parsers/base.py +295 -0
  47. alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
  48. alita_sdk/community/inventory/parsers/go_parser.py +851 -0
  49. alita_sdk/community/inventory/parsers/html_parser.py +389 -0
  50. alita_sdk/community/inventory/parsers/java_parser.py +593 -0
  51. alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
  52. alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
  53. alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
  54. alita_sdk/community/inventory/parsers/python_parser.py +604 -0
  55. alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
  56. alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
  57. alita_sdk/community/inventory/parsers/text_parser.py +322 -0
  58. alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
  59. alita_sdk/community/inventory/patterns/__init__.py +61 -0
  60. alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
  61. alita_sdk/community/inventory/patterns/loader.py +348 -0
  62. alita_sdk/community/inventory/patterns/registry.py +198 -0
  63. alita_sdk/community/inventory/presets.py +535 -0
  64. alita_sdk/community/inventory/retrieval.py +1403 -0
  65. alita_sdk/community/inventory/toolkit.py +173 -0
  66. alita_sdk/community/inventory/toolkit_utils.py +176 -0
  67. alita_sdk/community/inventory/visualize.py +1370 -0
  68. alita_sdk/configurations/__init__.py +1 -1
  69. alita_sdk/configurations/ado.py +141 -20
  70. alita_sdk/configurations/bitbucket.py +0 -3
  71. alita_sdk/configurations/confluence.py +76 -42
  72. alita_sdk/configurations/figma.py +76 -0
  73. alita_sdk/configurations/gitlab.py +17 -5
  74. alita_sdk/configurations/openapi.py +329 -0
  75. alita_sdk/configurations/qtest.py +72 -1
  76. alita_sdk/configurations/report_portal.py +96 -0
  77. alita_sdk/configurations/sharepoint.py +148 -0
  78. alita_sdk/configurations/testio.py +83 -0
  79. alita_sdk/runtime/clients/artifact.py +3 -3
  80. alita_sdk/runtime/clients/client.py +353 -48
  81. alita_sdk/runtime/clients/sandbox_client.py +0 -21
  82. alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
  83. alita_sdk/runtime/langchain/assistant.py +123 -26
  84. alita_sdk/runtime/langchain/constants.py +642 -1
  85. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
  86. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
  87. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +6 -3
  88. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
  89. alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
  90. alita_sdk/runtime/langchain/document_loaders/constants.py +12 -7
  91. alita_sdk/runtime/langchain/langraph_agent.py +279 -73
  92. alita_sdk/runtime/langchain/utils.py +82 -15
  93. alita_sdk/runtime/llms/preloaded.py +2 -6
  94. alita_sdk/runtime/skills/__init__.py +91 -0
  95. alita_sdk/runtime/skills/callbacks.py +498 -0
  96. alita_sdk/runtime/skills/discovery.py +540 -0
  97. alita_sdk/runtime/skills/executor.py +610 -0
  98. alita_sdk/runtime/skills/input_builder.py +371 -0
  99. alita_sdk/runtime/skills/models.py +330 -0
  100. alita_sdk/runtime/skills/registry.py +355 -0
  101. alita_sdk/runtime/skills/skill_runner.py +330 -0
  102. alita_sdk/runtime/toolkits/__init__.py +7 -0
  103. alita_sdk/runtime/toolkits/application.py +21 -9
  104. alita_sdk/runtime/toolkits/artifact.py +15 -5
  105. alita_sdk/runtime/toolkits/datasource.py +13 -6
  106. alita_sdk/runtime/toolkits/mcp.py +139 -251
  107. alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
  108. alita_sdk/runtime/toolkits/planning.py +178 -0
  109. alita_sdk/runtime/toolkits/skill_router.py +238 -0
  110. alita_sdk/runtime/toolkits/subgraph.py +251 -6
  111. alita_sdk/runtime/toolkits/tools.py +238 -32
  112. alita_sdk/runtime/toolkits/vectorstore.py +11 -5
  113. alita_sdk/runtime/tools/__init__.py +3 -1
  114. alita_sdk/runtime/tools/application.py +20 -6
  115. alita_sdk/runtime/tools/artifact.py +511 -28
  116. alita_sdk/runtime/tools/data_analysis.py +183 -0
  117. alita_sdk/runtime/tools/function.py +43 -15
  118. alita_sdk/runtime/tools/image_generation.py +50 -44
  119. alita_sdk/runtime/tools/llm.py +852 -67
  120. alita_sdk/runtime/tools/loop.py +3 -1
  121. alita_sdk/runtime/tools/loop_output.py +3 -1
  122. alita_sdk/runtime/tools/mcp_remote_tool.py +25 -10
  123. alita_sdk/runtime/tools/mcp_server_tool.py +7 -6
  124. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  125. alita_sdk/runtime/tools/planning/models.py +246 -0
  126. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  127. alita_sdk/runtime/tools/router.py +2 -4
  128. alita_sdk/runtime/tools/sandbox.py +9 -6
  129. alita_sdk/runtime/tools/skill_router.py +776 -0
  130. alita_sdk/runtime/tools/tool.py +3 -1
  131. alita_sdk/runtime/tools/vectorstore.py +7 -2
  132. alita_sdk/runtime/tools/vectorstore_base.py +51 -11
  133. alita_sdk/runtime/utils/AlitaCallback.py +137 -21
  134. alita_sdk/runtime/utils/constants.py +5 -1
  135. alita_sdk/runtime/utils/mcp_client.py +492 -0
  136. alita_sdk/runtime/utils/mcp_oauth.py +202 -5
  137. alita_sdk/runtime/utils/mcp_sse_client.py +36 -7
  138. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  139. alita_sdk/runtime/utils/serialization.py +155 -0
  140. alita_sdk/runtime/utils/streamlit.py +6 -10
  141. alita_sdk/runtime/utils/toolkit_utils.py +16 -5
  142. alita_sdk/runtime/utils/utils.py +36 -0
  143. alita_sdk/tools/__init__.py +113 -29
  144. alita_sdk/tools/ado/repos/__init__.py +51 -33
  145. alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
  146. alita_sdk/tools/ado/test_plan/__init__.py +25 -9
  147. alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
  148. alita_sdk/tools/ado/utils.py +1 -18
  149. alita_sdk/tools/ado/wiki/__init__.py +25 -8
  150. alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
  151. alita_sdk/tools/ado/work_item/__init__.py +26 -9
  152. alita_sdk/tools/ado/work_item/ado_wrapper.py +56 -3
  153. alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
  154. alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
  155. alita_sdk/tools/aws/delta_lake/tool.py +5 -1
  156. alita_sdk/tools/azure_ai/search/__init__.py +11 -8
  157. alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
  158. alita_sdk/tools/base/tool.py +5 -1
  159. alita_sdk/tools/base_indexer_toolkit.py +170 -45
  160. alita_sdk/tools/bitbucket/__init__.py +17 -12
  161. alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
  162. alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
  163. alita_sdk/tools/browser/__init__.py +5 -4
  164. alita_sdk/tools/carrier/__init__.py +5 -6
  165. alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
  166. alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
  167. alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
  168. alita_sdk/tools/chunkers/__init__.py +3 -1
  169. alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
  170. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  171. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  172. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  173. alita_sdk/tools/cloud/aws/__init__.py +10 -7
  174. alita_sdk/tools/cloud/azure/__init__.py +10 -7
  175. alita_sdk/tools/cloud/gcp/__init__.py +10 -7
  176. alita_sdk/tools/cloud/k8s/__init__.py +10 -7
  177. alita_sdk/tools/code/linter/__init__.py +10 -8
  178. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  179. alita_sdk/tools/code/sonar/__init__.py +10 -7
  180. alita_sdk/tools/code_indexer_toolkit.py +73 -23
  181. alita_sdk/tools/confluence/__init__.py +21 -15
  182. alita_sdk/tools/confluence/api_wrapper.py +78 -23
  183. alita_sdk/tools/confluence/loader.py +4 -2
  184. alita_sdk/tools/custom_open_api/__init__.py +12 -5
  185. alita_sdk/tools/elastic/__init__.py +11 -8
  186. alita_sdk/tools/elitea_base.py +493 -30
  187. alita_sdk/tools/figma/__init__.py +58 -11
  188. alita_sdk/tools/figma/api_wrapper.py +1235 -143
  189. alita_sdk/tools/figma/figma_client.py +73 -0
  190. alita_sdk/tools/figma/toon_tools.py +2748 -0
  191. alita_sdk/tools/github/__init__.py +13 -14
  192. alita_sdk/tools/github/github_client.py +224 -100
  193. alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
  194. alita_sdk/tools/github/schemas.py +14 -5
  195. alita_sdk/tools/github/tool.py +5 -1
  196. alita_sdk/tools/github/tool_prompts.py +9 -22
  197. alita_sdk/tools/gitlab/__init__.py +15 -11
  198. alita_sdk/tools/gitlab/api_wrapper.py +207 -41
  199. alita_sdk/tools/gitlab_org/__init__.py +10 -8
  200. alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
  201. alita_sdk/tools/google/bigquery/__init__.py +13 -12
  202. alita_sdk/tools/google/bigquery/tool.py +5 -1
  203. alita_sdk/tools/google_places/__init__.py +10 -8
  204. alita_sdk/tools/google_places/api_wrapper.py +1 -1
  205. alita_sdk/tools/jira/__init__.py +17 -11
  206. alita_sdk/tools/jira/api_wrapper.py +91 -40
  207. alita_sdk/tools/keycloak/__init__.py +11 -8
  208. alita_sdk/tools/localgit/__init__.py +9 -3
  209. alita_sdk/tools/localgit/local_git.py +62 -54
  210. alita_sdk/tools/localgit/tool.py +5 -1
  211. alita_sdk/tools/memory/__init__.py +11 -3
  212. alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
  213. alita_sdk/tools/ocr/__init__.py +11 -8
  214. alita_sdk/tools/openapi/__init__.py +490 -114
  215. alita_sdk/tools/openapi/api_wrapper.py +1368 -0
  216. alita_sdk/tools/openapi/tool.py +20 -0
  217. alita_sdk/tools/pandas/__init__.py +20 -12
  218. alita_sdk/tools/pandas/api_wrapper.py +38 -25
  219. alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
  220. alita_sdk/tools/postman/__init__.py +11 -11
  221. alita_sdk/tools/pptx/__init__.py +10 -9
  222. alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
  223. alita_sdk/tools/qtest/__init__.py +30 -10
  224. alita_sdk/tools/qtest/api_wrapper.py +430 -13
  225. alita_sdk/tools/rally/__init__.py +10 -8
  226. alita_sdk/tools/rally/api_wrapper.py +1 -1
  227. alita_sdk/tools/report_portal/__init__.py +12 -9
  228. alita_sdk/tools/salesforce/__init__.py +10 -9
  229. alita_sdk/tools/servicenow/__init__.py +17 -14
  230. alita_sdk/tools/servicenow/api_wrapper.py +1 -1
  231. alita_sdk/tools/sharepoint/__init__.py +10 -8
  232. alita_sdk/tools/sharepoint/api_wrapper.py +4 -4
  233. alita_sdk/tools/slack/__init__.py +10 -8
  234. alita_sdk/tools/slack/api_wrapper.py +2 -2
  235. alita_sdk/tools/sql/__init__.py +11 -9
  236. alita_sdk/tools/testio/__init__.py +10 -8
  237. alita_sdk/tools/testrail/__init__.py +11 -8
  238. alita_sdk/tools/testrail/api_wrapper.py +1 -1
  239. alita_sdk/tools/utils/__init__.py +9 -4
  240. alita_sdk/tools/utils/content_parser.py +77 -3
  241. alita_sdk/tools/utils/text_operations.py +410 -0
  242. alita_sdk/tools/utils/tool_prompts.py +79 -0
  243. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +17 -13
  244. alita_sdk/tools/xray/__init__.py +12 -9
  245. alita_sdk/tools/yagmail/__init__.py +9 -3
  246. alita_sdk/tools/zephyr/__init__.py +9 -7
  247. alita_sdk/tools/zephyr_enterprise/__init__.py +11 -8
  248. alita_sdk/tools/zephyr_essential/__init__.py +10 -8
  249. alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
  250. alita_sdk/tools/zephyr_essential/client.py +2 -2
  251. alita_sdk/tools/zephyr_scale/__init__.py +11 -9
  252. alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
  253. alita_sdk/tools/zephyr_squad/__init__.py +10 -8
  254. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +147 -7
  255. alita_sdk-0.3.627.dist-info/RECORD +468 -0
  256. alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
  257. alita_sdk-0.3.462.dist-info/RECORD +0 -384
  258. alita_sdk-0.3.462.dist-info/entry_points.txt +0 -2
  259. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
  260. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
  261. {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,8 @@ from pydantic import create_model, BaseModel, Field, SecretStr
8
8
  from ..base.tool import BaseAction
9
9
  from .api_wrapper import ZephyrV1ApiWrapper
10
10
  from ..elitea_base import filter_missconfigured_index_tools
11
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
11
+ from ..utils import clean_string, get_max_toolkit_length
12
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
12
13
 
13
14
  name = "zephyr"
14
15
 
@@ -23,12 +24,10 @@ def get_tools(tool):
23
24
 
24
25
  class ZephyrToolkit(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 ZephyrV1ApiWrapper.model_construct().get_available_tools()}
31
- ZephyrToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
32
31
  return create_model(
33
32
  name,
34
33
  base_url=(str, Field(description="Base URL")),
@@ -40,7 +39,6 @@ class ZephyrToolkit(BaseToolkit):
40
39
  {
41
40
  'metadata': {
42
41
  "label": "Zephyr", "icon_url": "zephyr.svg", "hidden": True,
43
- "max_length": ZephyrToolkit.toolkit_max_length,
44
42
  "categories": ["test management"],
45
43
  "extra_categories": ["test automation", "test case management", "test planning"]
46
44
  }}}
@@ -50,18 +48,22 @@ class ZephyrToolkit(BaseToolkit):
50
48
  @filter_missconfigured_index_tools
51
49
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
52
50
  zephyr_api_wrapper = ZephyrV1ApiWrapper(**kwargs)
53
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
54
51
  available_tools = zephyr_api_wrapper.get_available_tools()
55
52
  tools = []
56
53
  for tool in available_tools:
57
54
  if selected_tools:
58
55
  if tool["name"] not in selected_tools:
59
56
  continue
57
+ description = tool["description"]
58
+ if toolkit_name:
59
+ description = f"Toolkit: {toolkit_name}\n{description}"
60
+ description = description[:1000]
60
61
  tools.append(BaseAction(
61
62
  api_wrapper=zephyr_api_wrapper,
62
63
  name=tool["name"],
63
- description=tool["description"],
64
- args_schema=tool["args_schema"]
64
+ description=description,
65
+ args_schema=tool["args_schema"],
66
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
65
67
  ))
66
68
  return cls(tools=tools)
67
69
 
@@ -5,9 +5,10 @@ from typing import List, Literal, Optional
5
5
  from .api_wrapper import ZephyrApiWrapper
6
6
  from ..base.tool import BaseAction
7
7
  from ..elitea_base import filter_missconfigured_index_tools
8
- from ..utils import clean_string, get_max_toolkit_length, TOOLKIT_SPLITTER
8
+ from ..utils import clean_string, get_max_toolkit_length
9
9
  from ...configurations.pgvector import PgVectorConfiguration
10
10
  from ...configurations.zephyr_enterprise import ZephyrEnterpriseConfiguration
11
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
11
12
 
12
13
  name = "zephyr_enterprise"
13
14
 
@@ -28,13 +29,11 @@ def get_tools(tool):
28
29
 
29
30
  class ZephyrEnterpriseToolkit(BaseToolkit):
30
31
  tools: List[BaseTool] = []
31
- toolkit_max_length: int = 0
32
32
 
33
33
  @staticmethod
34
34
  def toolkit_config_schema() -> BaseModel:
35
35
  selected_tools = {x['name']: x['args_schema'].schema() for x in
36
36
  ZephyrApiWrapper.model_construct().get_available_tools()}
37
- ZephyrEnterpriseToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
38
37
  return create_model(
39
38
  name,
40
39
  zephyr_configuration=(ZephyrEnterpriseConfiguration, Field(description="Zephyr Configuration", json_schema_extra={'configuration_types': ['zephyr_enterprise']})),
@@ -49,7 +48,6 @@ class ZephyrEnterpriseToolkit(BaseToolkit):
49
48
  __config__=ConfigDict(json_schema_extra={
50
49
  'metadata': {
51
50
  "label": "Zephyr Enterprise", "icon_url": "zephyr.svg",
52
- "max_length": ZephyrEnterpriseToolkit.toolkit_max_length,
53
51
  "categories": ["test management"],
54
52
  "extra_categories": ["test automation", "test case management", "test planning"]
55
53
  }})
@@ -68,17 +66,22 @@ class ZephyrEnterpriseToolkit(BaseToolkit):
68
66
  **(kwargs.get('embedding_configuration') or {}),
69
67
  }
70
68
  zephyr_api_wrapper = ZephyrApiWrapper(**wrapper_payload)
71
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
72
69
  available_tools = zephyr_api_wrapper.get_available_tools()
73
70
  tools = []
74
71
  for tool in available_tools:
75
72
  if selected_tools and tool["name"] not in selected_tools:
76
73
  continue
74
+ description = tool["description"]
75
+ if toolkit_name:
76
+ description = f"Toolkit: {toolkit_name}\n{description}"
77
+ description = description + "\nZephyr Enterprise instance: " + zephyr_api_wrapper.base_url
78
+ description = description[:1000]
77
79
  tools.append(BaseAction(
78
80
  api_wrapper=zephyr_api_wrapper,
79
- name=prefix + tool["name"],
80
- description=tool["description"] + "\nZephyr Enterprise instance: " + zephyr_api_wrapper.base_url,
81
- args_schema=tool["args_schema"]
81
+ name=tool["name"],
82
+ description=description,
83
+ args_schema=tool["args_schema"],
84
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
82
85
  ))
83
86
  return cls(tools=tools)
84
87
 
@@ -6,9 +6,10 @@ from pydantic import create_model, BaseModel, Field
6
6
  from .api_wrapper import ZephyrEssentialApiWrapper
7
7
  from ..base.tool import BaseAction
8
8
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
9
+ from ..utils import clean_string, get_max_toolkit_length
10
10
  from ...configurations.pgvector import PgVectorConfiguration
11
11
  from ...configurations.zephyr_essential import ZephyrEssentialConfiguration
12
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
12
13
 
13
14
  name = "zephyr_essential"
14
15
 
@@ -29,12 +30,10 @@ def get_tools(tool):
29
30
 
30
31
  class ZephyrEssentialToolkit(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 ZephyrEssentialApiWrapper.model_construct().get_available_tools()}
37
- ZephyrEssentialToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
38
37
  return create_model(
39
38
  name,
40
39
  zephyr_essential_configuration=(ZephyrEssentialConfiguration, Field(description="Zephyr Essential Configuration", json_schema_extra={'configuration_types': ['zephyr_essential']})),
@@ -46,7 +45,6 @@ class ZephyrEssentialToolkit(BaseToolkit):
46
45
  # embedder settings
47
46
  embedding_model=(Optional[str], Field(default=None, description="Embedding configuration.", json_schema_extra={'configuration_model': 'embedding'})),
48
47
  __config__={'json_schema_extra': {'metadata': {"label": "Zephyr Essential", "icon_url": "zephyr.svg",
49
- "max_length": ZephyrEssentialToolkit.toolkit_max_length,
50
48
  "categories": ["test management"],
51
49
  "extra_categories": ["test automation", "test case management", "test planning"]
52
50
  }}}
@@ -63,18 +61,22 @@ class ZephyrEssentialToolkit(BaseToolkit):
63
61
  **(kwargs.get('pgvector_configuration') or {}),
64
62
  }
65
63
  zephyr_api_wrapper = ZephyrEssentialApiWrapper(**wrapper_payload)
66
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
67
64
  available_tools = zephyr_api_wrapper.get_available_tools()
68
65
  tools = []
69
66
  for tool in available_tools:
70
67
  if selected_tools:
71
68
  if tool["name"] not in selected_tools:
72
69
  continue
70
+ description = tool["description"]
71
+ if toolkit_name:
72
+ description = f"Toolkit: {toolkit_name}\n{description}"
73
+ description = description[:1000]
73
74
  tools.append(BaseAction(
74
75
  api_wrapper=zephyr_api_wrapper,
75
- name=prefix + tool["name"],
76
- description=tool["description"],
77
- args_schema=tool["args_schema"]
76
+ name=tool["name"],
77
+ description=description,
78
+ args_schema=tool["args_schema"],
79
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
78
80
  ))
79
81
  return cls(tools=tools)
80
82
 
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import json
2
3
  import logging
3
4
  from typing import Optional, Generator, Literal
@@ -55,6 +56,7 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
55
56
  def create_test_case_issue_link(self, test_case_key: str, json: str):
56
57
  """Create an issue link for a test case."""
57
58
  issue_link_data = self._parse_json(json)
59
+ self._validate_issue_link_data(issue_link_data, "test case")
58
60
  return self._client.create_test_case_issue_link(test_case_key, issue_link_data)
59
61
 
60
62
  def create_test_case_web_link(self, test_case_key: str, json: str):
@@ -119,6 +121,7 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
119
121
  def create_test_cycle_issue_link(self, test_cycle_id_or_key: str, json: str):
120
122
  """Create an issue link for a test cycle."""
121
123
  issue_link_data = self._parse_json(json)
124
+ self._validate_issue_link_data(issue_link_data, "test cycle")
122
125
  return self._client.create_test_cycle_issue_link(test_cycle_id_or_key, issue_link_data)
123
126
 
124
127
  def create_test_cycle_web_link(self, test_cycle_id_or_key: str, json: str):
@@ -164,6 +167,7 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
164
167
  def create_test_execution_issue_link(self, test_execution_id_or_key: str, json: str):
165
168
  """Create an issue link for a test execution."""
166
169
  issue_link_data = self._parse_json(json)
170
+ self._validate_issue_link_data(issue_link_data, "test execution")
167
171
  return self._client.create_test_execution_issue_link(test_execution_id_or_key, issue_link_data)
168
172
 
169
173
  def list_projects(self, max_results: int = None, start_at: int = None):
@@ -266,6 +270,21 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
266
270
  except json.JSONDecodeError as e:
267
271
  raise ValueError(f"Invalid JSON string: {str(e)}")
268
272
 
273
+ def _validate_issue_link_data(self, issue_link_data: dict, entity_type: str):
274
+ """Validate issue link payload has issueId, not issueKey."""
275
+ if 'issueId' not in issue_link_data:
276
+ if 'issueKey' in issue_link_data:
277
+ raise ToolException(
278
+ f"Zephyr Essential API requires 'issueId' (numeric Jira issue ID), "
279
+ f"not 'issueKey'. You provided issueKey='{issue_link_data['issueKey']}'. "
280
+ f"To find the issueId, Jira toolkit can be used or raw Jira API: GET /rest/api/2/issue/{issue_link_data['issueKey']} "
281
+ f"and look for the 'id' field in the response."
282
+ )
283
+ raise ToolException(
284
+ f"Missing required field 'issueId' in JSON payload for {entity_type} issue link. "
285
+ f"Example: {{\"issueId\": 10100}}"
286
+ )
287
+
269
288
  def _index_tool_params(self):
270
289
  return {
271
290
  'chunking_tool':(Literal['json', ''], Field(description="Name of chunking tool", default='json'))
@@ -284,22 +303,20 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
284
303
  if isinstance(v, (str, int, float, bool, list, dict))
285
304
  }
286
305
  metadata['type'] = "TEST_CASE"
287
-
288
- yield Document(page_content="", metadata=metadata)
289
-
290
- def _extend_data(self, documents: Generator[Document, None, None]) -> Generator[Document, None, None]:
291
- for document in documents:
306
+ #
292
307
  try:
293
- if 'type' in document.metadata and document.metadata['type'] == "TEST_CASE":
294
- additional_content = self._process_test_case(document.metadata['key'])
295
- for steps_type, content in additional_content.items():
296
- if content:
297
- page_content = json.dumps(content)
298
- document.metadata[IndexerKeywords.CONTENT_IN_BYTES.value] = page_content.encode('utf-8')
299
- document.metadata["steps_type"] = steps_type
308
+ additional_content = self._process_test_case(metadata['key'])
309
+ for steps_type, content in additional_content.items():
310
+ if content:
311
+ page_content = json.dumps(content)
312
+ content_hash = hashlib.sha256(page_content.encode('utf-8')).hexdigest()
313
+ metadata[IndexerKeywords.UPDATED_ON.value] = content_hash
314
+ metadata[IndexerKeywords.CONTENT_IN_BYTES.value] = page_content.encode('utf-8')
315
+ metadata["steps_type"] = steps_type
300
316
  except Exception as e:
301
317
  logging.error(f"Failed to process document: {e}")
302
- yield document
318
+ #
319
+ yield Document(page_content="", metadata=metadata)
303
320
 
304
321
  def _process_test_case(self, key) -> dict:
305
322
  steps = self.get_test_case_test_steps(key)
@@ -19,9 +19,9 @@ class ZephyrEssentialAPI:
19
19
  if resp.headers.get("Content-Type", "").startswith("application/json"):
20
20
  return resp.json()
21
21
  return resp.text
22
- return ToolException(f"Error performing request {method} {api_path}: {resp.content}")
22
+ return ToolException(f"Unexpected status code {resp.status_code} for {method} {api_path}: {resp.content}")
23
23
  except requests.RequestException as e:
24
- raise Exception(f"Error performing request {method} {api_path}: {str(e)}")
24
+ raise Exception(f"Unexpected error while performing request {method} {api_path}: {str(e)}")
25
25
 
26
26
  # Test Cases
27
27
  def list_test_cases(self, project_key=None, folder_id=None, max_results=10, start_at=0):
@@ -7,9 +7,10 @@ from pydantic import create_model, BaseModel, Field
7
7
  from .api_wrapper import ZephyrScaleApiWrapper
8
8
  from ..base.tool import BaseAction
9
9
  from ..elitea_base import filter_missconfigured_index_tools
10
- from ..utils import clean_string, get_max_toolkit_length, TOOLKIT_SPLITTER
10
+ from ..utils import clean_string, get_max_toolkit_length
11
11
  from ...configurations.pgvector import PgVectorConfiguration
12
12
  from ...configurations.zephyr import ZephyrConfiguration
13
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
13
14
 
14
15
  name = "zephyr_scale"
15
16
 
@@ -32,15 +33,13 @@ def get_tools(tool):
32
33
 
33
34
  class ZephyrScaleToolkit(BaseToolkit):
34
35
  tools: List[BaseTool] = []
35
- toolkit_max_length: int = 0
36
36
 
37
37
  @staticmethod
38
38
  def toolkit_config_schema() -> BaseModel:
39
39
  selected_tools = {x['name']: x['args_schema'].schema() for x in ZephyrScaleApiWrapper.model_construct().get_available_tools()}
40
- ZephyrScaleToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
41
40
  return create_model(
42
41
  name,
43
- max_results=(int, Field(default=100, description="Results count to show")),
42
+ max_results=(int, Field(default=100, description="Results count to show", gt=0)),
44
43
  zephyr_configuration=(ZephyrConfiguration, Field(description="Zephyr Configuration",
45
44
  json_schema_extra={'configuration_types': ['zephyr']})),
46
45
  pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None, description="PgVector Configuration",
@@ -56,7 +55,6 @@ class ZephyrScaleToolkit(BaseToolkit):
56
55
  'metadata': {
57
56
  "label": "Zephyr Scale",
58
57
  "icon_url": "zephyr.svg",
59
- "max_length": ZephyrScaleToolkit.toolkit_max_length,
60
58
  "categories": ["test management"],
61
59
  "extra_categories": ["test automation", "test case management", "test planning"],
62
60
  }
@@ -76,18 +74,22 @@ class ZephyrScaleToolkit(BaseToolkit):
76
74
  **(kwargs.get('pgvector_configuration') or {}),
77
75
  }
78
76
  zephyr_wrapper = ZephyrScaleApiWrapper(**wrapper_payload)
79
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
80
77
  available_tools = zephyr_wrapper.get_available_tools()
81
78
  tools = []
82
79
  for tool in available_tools:
83
80
  if selected_tools:
84
81
  if tool["name"] not in selected_tools:
85
82
  continue
83
+ description = tool["description"]
84
+ if toolkit_name:
85
+ description = f"Toolkit: {toolkit_name}\n{description}"
86
+ description = description[:1000]
86
87
  tools.append(BaseAction(
87
88
  api_wrapper=zephyr_wrapper,
88
- name=prefix + tool["name"],
89
- description=tool["description"],
90
- args_schema=tool["args_schema"]
89
+ name=tool["name"],
90
+ description=description,
91
+ args_schema=tool["args_schema"],
92
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
91
93
  ))
92
94
  return cls(tools=tools)
93
95
 
@@ -177,13 +177,13 @@ ZephyrSearchTestCases = create_model(
177
177
  "ZephyrSearchTestCases",
178
178
  project_key=(str, Field(description="Jira project key filter")),
179
179
  search_term=(Optional[str], Field(description="Optional search term to filter test cases", default=None)),
180
- max_results=(Optional[int], Field(description="Maximum number of results to query from the API", default=1000)),
180
+ max_results=(Optional[int], Field(description="Maximum number of results to query from the API", default=1000, gt=0)),
181
181
  start_at=(Optional[int], Field(description="Zero-indexed starting position", default=0)),
182
182
  order_by=(Optional[str], Field(description="Field to order results by", default="name")),
183
183
  order_direction=(Optional[str], Field(description="Order direction", default="ASC")),
184
184
  archived=(Optional[bool], Field(description="Include archived test cases", default=False)),
185
185
  fields=(Optional[List[str]], Field(description="Fields to include in the response (default: key, name). Regular fields include key, name, id, labels, folder, etc. Custom fields can be included in the following ways:Individual custom fields via customFields.field_name format, All custom fields via customFields in the fields list", default=["key", "name"])),
186
- limit_results=(Optional[int], Field(description="Maximum number of filtered results to return", default=10)),
186
+ limit_results=(Optional[int], Field(description="Maximum number of filtered results to return", default=10, gt=0)),
187
187
  folder_id=(Optional[str], Field(description="Filter test cases by folder ID", default=None)),
188
188
  folder_name=(Optional[str], Field(description="Filter test cases by folder name (full or partial)", default=None)),
189
189
  exact_folder_match=(Optional[bool], Field(description="Whether to match the folder name exactly or allow partial matches", default=False)),
@@ -6,7 +6,8 @@ from pydantic import create_model, BaseModel, Field, SecretStr
6
6
  from .api_wrapper import ZephyrSquadApiWrapper
7
7
  from ..base.tool import BaseAction
8
8
  from ..elitea_base import filter_missconfigured_index_tools
9
- from ..utils import clean_string, TOOLKIT_SPLITTER, get_max_toolkit_length
9
+ from ..utils import clean_string, get_max_toolkit_length
10
+ from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
10
11
 
11
12
  name = "zephyr_squad"
12
13
 
@@ -21,12 +22,10 @@ def get_tools(tool):
21
22
 
22
23
  class ZephyrSquadToolkit(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 ZephyrSquadApiWrapper.model_construct().get_available_tools()}
29
- ZephyrSquadToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
30
29
  return create_model(
31
30
  name,
32
31
  account_id=(str, Field(description="AccountID for the user that is going to be authenticating")),
@@ -34,7 +33,6 @@ class ZephyrSquadToolkit(BaseToolkit):
34
33
  secret_key=(SecretStr, Field(description="Generated secret key", json_schema_extra={'secret': True})),
35
34
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
36
35
  __config__={'json_schema_extra': {'metadata': {"label": "Zephyr Squad", "icon_url": "zephyr.svg",
37
- "max_length": ZephyrSquadToolkit.toolkit_max_length,
38
36
  "categories": ["test management"],
39
37
  "extra_categories": ["test automation", "test case management", "test planning"]
40
38
  }}}
@@ -44,18 +42,22 @@ class ZephyrSquadToolkit(BaseToolkit):
44
42
  @filter_missconfigured_index_tools
45
43
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
46
44
  zephyr_api_wrapper = ZephyrSquadApiWrapper(**kwargs)
47
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
48
45
  available_tools = zephyr_api_wrapper.get_available_tools()
49
46
  tools = []
50
47
  for tool in available_tools:
51
48
  if selected_tools:
52
49
  if tool["name"] not in selected_tools:
53
50
  continue
51
+ description = tool["description"]
52
+ if toolkit_name:
53
+ description = f"Toolkit: {toolkit_name}\n{description}"
54
+ description = description[:1000]
54
55
  tools.append(BaseAction(
55
56
  api_wrapper=zephyr_api_wrapper,
56
- name=prefix + tool["name"],
57
- description=tool["description"],
58
- args_schema=tool["args_schema"]
57
+ name=tool["name"],
58
+ description=description,
59
+ args_schema=tool["args_schema"],
60
+ metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
59
61
  ))
60
62
  return cls(tools=tools)
61
63
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alita_sdk
3
- Version: 0.3.462
3
+ Version: 0.3.627
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
@@ -31,7 +31,7 @@ Requires-Dist: langchain_core<0.4.0,>=0.3.76; extra == "runtime"
31
31
  Requires-Dist: langchain<0.4.0,>=0.3.22; extra == "runtime"
32
32
  Requires-Dist: langchain_community<0.4.0,>=0.3.7; extra == "runtime"
33
33
  Requires-Dist: langchain-openai<0.4.0,>=0.3.0; extra == "runtime"
34
- Requires-Dist: langchain-anthropic<0.4.0,>=0.3.10; extra == "runtime"
34
+ Requires-Dist: langchain-anthropic<0.4.0,>=0.3.20; extra == "runtime"
35
35
  Requires-Dist: anthropic>=0.57.0; extra == "runtime"
36
36
  Requires-Dist: langgraph<0.5,>=0.4.8; extra == "runtime"
37
37
  Requires-Dist: langgraph-prebuilt==0.5.2; extra == "runtime"
@@ -68,12 +68,13 @@ Requires-Dist: pytesseract==0.3.13; extra == "runtime"
68
68
  Requires-Dist: markdown==3.5.1; extra == "runtime"
69
69
  Requires-Dist: beautifulsoup4==4.12.2; extra == "runtime"
70
70
  Requires-Dist: charset_normalizer==3.3.2; extra == "runtime"
71
- Requires-Dist: opentelemetry-exporter-otlp-proto-grpc==1.25.0; extra == "runtime"
72
- Requires-Dist: opentelemetry_api==1.25.0; extra == "runtime"
73
- Requires-Dist: opentelemetry_instrumentation==0.46b0; extra == "runtime"
74
- Requires-Dist: grpcio_status==1.63.0rc1; extra == "runtime"
75
- Requires-Dist: protobuf==4.25.7; extra == "runtime"
71
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0; extra == "runtime"
72
+ Requires-Dist: opentelemetry_api>=1.25.0; extra == "runtime"
73
+ Requires-Dist: opentelemetry_instrumentation>=0.46b0; extra == "runtime"
74
+ Requires-Dist: grpcio_status>=1.63.0rc1; extra == "runtime"
75
+ Requires-Dist: protobuf>=4.25.7; extra == "runtime"
76
76
  Requires-Dist: langchain-sandbox>=0.0.6; extra == "runtime"
77
+ Requires-Dist: langchain-mcp-adapters<0.2.0,>=0.1.14; extra == "runtime"
77
78
  Provides-Extra: tools
78
79
  Requires-Dist: dulwich==0.21.6; extra == "tools"
79
80
  Requires-Dist: paramiko==3.3.1; extra == "tools"
@@ -134,6 +135,7 @@ Provides-Extra: community
134
135
  Requires-Dist: retry-extended==0.2.3; extra == "community"
135
136
  Requires-Dist: pyobjtojson==0.3; extra == "community"
136
137
  Requires-Dist: elitea-analyse==0.1.2; extra == "community"
138
+ Requires-Dist: networkx>=3.0; extra == "community"
137
139
  Provides-Extra: all
138
140
  Requires-Dist: alita-sdk[runtime]; extra == "all"
139
141
  Requires-Dist: alita-sdk[tools]; extra == "all"
@@ -206,6 +208,144 @@ PROJECT_ID=<your_project_id>
206
208
  NOTE: these variables can be grabbed from your Elitea platform configuration page.
207
209
  ![Platform configuration](docs/readme_imgs/platform_config.png "Platform configuration")
208
210
 
211
+ ### Custom .env File Location
212
+
213
+ By default, the CLI looks for `.env` files in the following order:
214
+ 1. `.alita/.env` (recommended)
215
+ 2. `.env` in the current directory
216
+
217
+ You can override this by setting the `ALITA_ENV_FILE` environment variable:
218
+
219
+ ```bash
220
+ export ALITA_ENV_FILE=/path/to/your/.env
221
+ alita-cli agent chat
222
+ ```
223
+
224
+ Using the CLI for Interactive Chat
225
+ ----------------------------------
226
+
227
+ The Alita SDK includes a powerful CLI for interactive agent chat sessions.
228
+
229
+ ### Starting a Chat Session
230
+
231
+ ```bash
232
+ # Interactive selection (shows all available agents + direct chat option)
233
+ alita-cli agent chat
234
+
235
+ # Chat with a specific local agent
236
+ alita-cli agent chat .alita/agents/my-agent.agent.md
237
+
238
+ # Chat with a platform agent
239
+ alita-cli agent chat my-agent-name
240
+ ```
241
+
242
+ ### Direct Chat Mode (No Agent)
243
+
244
+ You can start a chat session directly with the LLM without any agent configuration:
245
+
246
+ ```bash
247
+ alita-cli agent chat
248
+ # Select option 1: "Direct chat with model (no agent)"
249
+ ```
250
+
251
+ This is useful for quick interactions or testing without setting up an agent.
252
+
253
+ ### Chat Commands
254
+
255
+ During a chat session, you can use the following commands:
256
+
257
+ | Command | Description |
258
+ |---------|-------------|
259
+ | `/help` | Show all available commands |
260
+ | `/model` | Switch to a different model (preserves chat history) |
261
+ | `/add_mcp` | Add an MCP server from your local mcp.json (preserves chat history) |
262
+ | `/add_toolkit` | Add a toolkit from $ALITA_DIR/tools (preserves chat history) |
263
+ | `/clear` | Clear conversation history |
264
+ | `/history` | Show conversation history |
265
+ | `/save` | Save conversation to file |
266
+ | `exit` | End conversation |
267
+
268
+ ### Enhanced Input Features
269
+
270
+ The chat interface includes readline-based input enhancements:
271
+
272
+ | Feature | Key/Action |
273
+ |---------|------------|
274
+ | **Tab completion** | Press `Tab` to autocomplete commands (e.g., `/mo` → `/model`) |
275
+ | **Command history** | `↑` / `↓` arrows to navigate through previous messages |
276
+ | **Cursor movement** | `←` / `→` arrows to move within the current line |
277
+ | **Start of line** | `Ctrl+A` jumps to the beginning of the line |
278
+ | **End of line** | `Ctrl+E` jumps to the end of the line |
279
+ | **Delete word** | `Ctrl+W` deletes the word before cursor |
280
+ | **Clear line** | `Ctrl+U` clears from cursor to beginning of line |
281
+
282
+ ### Dynamic Model Switching
283
+
284
+ Use `/model` to switch models on the fly:
285
+
286
+ ```
287
+ > /model
288
+
289
+ 🔧 Select a model:
290
+
291
+ # Model Type
292
+ 1 gpt-4o openai
293
+ 2 gpt-4o-mini openai
294
+ 3 claude-3-sonnet anthropic
295
+
296
+ Select model number: 1
297
+
298
+ ✓ Selected: gpt-4o
299
+ ╭──────────────────────────────────────────────────────────────╮
300
+ │ ℹ Model switched to gpt-4o. Agent state reset, chat history │
301
+ │ preserved. │
302
+ ╰──────────────────────────────────────────────────────────────╯
303
+ ```
304
+
305
+ ### Adding MCP Servers Dynamically
306
+
307
+ Use `/add_mcp` to add MCP servers during a chat session. Servers are loaded from your local `mcp.json` file (typically at `.alita/mcp.json`):
308
+
309
+ ```
310
+ > /add_mcp
311
+
312
+ 🔌 Select an MCP server to add:
313
+
314
+ # Server Type Command/URL
315
+ 1 playwright stdio npx @playwright/mcp@latest
316
+ 2 filesystem stdio npx @anthropic/mcp-fs
317
+
318
+ Select MCP server number: 1
319
+
320
+ ✓ Selected: playwright
321
+ ╭──────────────────────────────────────────────────────────────╮
322
+ │ ℹ Added MCP: playwright. Agent state reset, chat history │
323
+ │ preserved. │
324
+ ╰──────────────────────────────────────────────────────────────╯
325
+ ```
326
+
327
+ ### Adding Toolkits Dynamically
328
+
329
+ Use `/add_toolkit` to add toolkits from your `$ALITA_DIR/tools` directory (default: `.alita/tools`):
330
+
331
+ ```
332
+ > /add_toolkit
333
+
334
+ 🧰 Select a toolkit to add:
335
+
336
+ # Toolkit Type File
337
+ 1 jira jira jira-config.json
338
+ 2 github github github-config.json
339
+
340
+ Select toolkit number: 1
341
+
342
+ ✓ Selected: jira
343
+ ╭──────────────────────────────────────────────────────────────╮
344
+ │ ℹ Added toolkit: jira. Agent state reset, chat history │
345
+ │ preserved. │
346
+ ╰──────────────────────────────────────────────────────────────╯
347
+ ```
348
+
209
349
 
210
350
 
211
351
  Using SDK with Streamlit for Local Development