alita-sdk 0.3.351__py3-none-any.whl → 0.3.499__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 (206) 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 +3601 -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 +1256 -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 +64 -8
  30. alita_sdk/community/inventory/__init__.py +224 -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/visualize.py +1370 -0
  58. alita_sdk/configurations/bitbucket.py +94 -2
  59. alita_sdk/configurations/confluence.py +96 -1
  60. alita_sdk/configurations/gitlab.py +79 -0
  61. alita_sdk/configurations/jira.py +103 -0
  62. alita_sdk/configurations/testrail.py +88 -0
  63. alita_sdk/configurations/xray.py +93 -0
  64. alita_sdk/configurations/zephyr_enterprise.py +93 -0
  65. alita_sdk/configurations/zephyr_essential.py +75 -0
  66. alita_sdk/runtime/clients/artifact.py +1 -1
  67. alita_sdk/runtime/clients/client.py +214 -42
  68. alita_sdk/runtime/clients/mcp_discovery.py +342 -0
  69. alita_sdk/runtime/clients/mcp_manager.py +262 -0
  70. alita_sdk/runtime/clients/sandbox_client.py +373 -0
  71. alita_sdk/runtime/langchain/assistant.py +118 -30
  72. alita_sdk/runtime/langchain/constants.py +8 -1
  73. alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
  74. alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
  75. alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +4 -1
  76. alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +41 -12
  77. alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -1
  78. alita_sdk/runtime/langchain/document_loaders/constants.py +116 -99
  79. alita_sdk/runtime/langchain/interfaces/llm_processor.py +2 -2
  80. alita_sdk/runtime/langchain/langraph_agent.py +307 -71
  81. alita_sdk/runtime/langchain/utils.py +48 -8
  82. alita_sdk/runtime/llms/preloaded.py +2 -6
  83. alita_sdk/runtime/models/mcp_models.py +61 -0
  84. alita_sdk/runtime/toolkits/__init__.py +26 -0
  85. alita_sdk/runtime/toolkits/application.py +9 -2
  86. alita_sdk/runtime/toolkits/artifact.py +18 -6
  87. alita_sdk/runtime/toolkits/datasource.py +13 -6
  88. alita_sdk/runtime/toolkits/mcp.py +780 -0
  89. alita_sdk/runtime/toolkits/planning.py +178 -0
  90. alita_sdk/runtime/toolkits/tools.py +205 -55
  91. alita_sdk/runtime/toolkits/vectorstore.py +9 -4
  92. alita_sdk/runtime/tools/__init__.py +11 -3
  93. alita_sdk/runtime/tools/application.py +7 -0
  94. alita_sdk/runtime/tools/artifact.py +225 -12
  95. alita_sdk/runtime/tools/function.py +95 -5
  96. alita_sdk/runtime/tools/graph.py +10 -4
  97. alita_sdk/runtime/tools/image_generation.py +212 -0
  98. alita_sdk/runtime/tools/llm.py +494 -102
  99. alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
  100. alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
  101. alita_sdk/runtime/tools/mcp_server_tool.py +4 -4
  102. alita_sdk/runtime/tools/planning/__init__.py +36 -0
  103. alita_sdk/runtime/tools/planning/models.py +246 -0
  104. alita_sdk/runtime/tools/planning/wrapper.py +607 -0
  105. alita_sdk/runtime/tools/router.py +2 -1
  106. alita_sdk/runtime/tools/sandbox.py +180 -79
  107. alita_sdk/runtime/tools/vectorstore.py +22 -21
  108. alita_sdk/runtime/tools/vectorstore_base.py +125 -52
  109. alita_sdk/runtime/utils/AlitaCallback.py +106 -20
  110. alita_sdk/runtime/utils/mcp_client.py +465 -0
  111. alita_sdk/runtime/utils/mcp_oauth.py +244 -0
  112. alita_sdk/runtime/utils/mcp_sse_client.py +405 -0
  113. alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
  114. alita_sdk/runtime/utils/streamlit.py +40 -13
  115. alita_sdk/runtime/utils/toolkit_utils.py +28 -9
  116. alita_sdk/runtime/utils/utils.py +12 -0
  117. alita_sdk/tools/__init__.py +77 -33
  118. alita_sdk/tools/ado/repos/__init__.py +7 -6
  119. alita_sdk/tools/ado/repos/repos_wrapper.py +11 -11
  120. alita_sdk/tools/ado/test_plan/__init__.py +7 -7
  121. alita_sdk/tools/ado/wiki/__init__.py +7 -11
  122. alita_sdk/tools/ado/wiki/ado_wrapper.py +89 -15
  123. alita_sdk/tools/ado/work_item/__init__.py +7 -11
  124. alita_sdk/tools/ado/work_item/ado_wrapper.py +17 -8
  125. alita_sdk/tools/advanced_jira_mining/__init__.py +8 -7
  126. alita_sdk/tools/aws/delta_lake/__init__.py +11 -9
  127. alita_sdk/tools/azure_ai/search/__init__.py +7 -6
  128. alita_sdk/tools/base_indexer_toolkit.py +345 -70
  129. alita_sdk/tools/bitbucket/__init__.py +9 -8
  130. alita_sdk/tools/bitbucket/api_wrapper.py +50 -6
  131. alita_sdk/tools/browser/__init__.py +4 -4
  132. alita_sdk/tools/carrier/__init__.py +4 -6
  133. alita_sdk/tools/chunkers/__init__.py +3 -1
  134. alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
  135. alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
  136. alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
  137. alita_sdk/tools/chunkers/universal_chunker.py +270 -0
  138. alita_sdk/tools/cloud/aws/__init__.py +7 -6
  139. alita_sdk/tools/cloud/azure/__init__.py +7 -6
  140. alita_sdk/tools/cloud/gcp/__init__.py +7 -6
  141. alita_sdk/tools/cloud/k8s/__init__.py +7 -6
  142. alita_sdk/tools/code/linter/__init__.py +7 -7
  143. alita_sdk/tools/code/loaders/codesearcher.py +3 -2
  144. alita_sdk/tools/code/sonar/__init__.py +8 -7
  145. alita_sdk/tools/code_indexer_toolkit.py +199 -0
  146. alita_sdk/tools/confluence/__init__.py +9 -8
  147. alita_sdk/tools/confluence/api_wrapper.py +171 -75
  148. alita_sdk/tools/confluence/loader.py +10 -0
  149. alita_sdk/tools/custom_open_api/__init__.py +9 -4
  150. alita_sdk/tools/elastic/__init__.py +8 -7
  151. alita_sdk/tools/elitea_base.py +492 -52
  152. alita_sdk/tools/figma/__init__.py +7 -7
  153. alita_sdk/tools/figma/api_wrapper.py +2 -1
  154. alita_sdk/tools/github/__init__.py +9 -9
  155. alita_sdk/tools/github/api_wrapper.py +9 -26
  156. alita_sdk/tools/github/github_client.py +62 -2
  157. alita_sdk/tools/gitlab/__init__.py +8 -8
  158. alita_sdk/tools/gitlab/api_wrapper.py +135 -33
  159. alita_sdk/tools/gitlab_org/__init__.py +7 -8
  160. alita_sdk/tools/google/bigquery/__init__.py +11 -12
  161. alita_sdk/tools/google_places/__init__.py +8 -7
  162. alita_sdk/tools/jira/__init__.py +9 -7
  163. alita_sdk/tools/jira/api_wrapper.py +100 -52
  164. alita_sdk/tools/keycloak/__init__.py +8 -7
  165. alita_sdk/tools/localgit/local_git.py +56 -54
  166. alita_sdk/tools/memory/__init__.py +1 -1
  167. alita_sdk/tools/non_code_indexer_toolkit.py +3 -2
  168. alita_sdk/tools/ocr/__init__.py +8 -7
  169. alita_sdk/tools/openapi/__init__.py +10 -1
  170. alita_sdk/tools/pandas/__init__.py +8 -7
  171. alita_sdk/tools/postman/__init__.py +7 -8
  172. alita_sdk/tools/postman/api_wrapper.py +19 -8
  173. alita_sdk/tools/postman/postman_analysis.py +8 -1
  174. alita_sdk/tools/pptx/__init__.py +8 -9
  175. alita_sdk/tools/qtest/__init__.py +16 -11
  176. alita_sdk/tools/qtest/api_wrapper.py +1784 -88
  177. alita_sdk/tools/rally/__init__.py +7 -8
  178. alita_sdk/tools/report_portal/__init__.py +9 -7
  179. alita_sdk/tools/salesforce/__init__.py +7 -7
  180. alita_sdk/tools/servicenow/__init__.py +10 -10
  181. alita_sdk/tools/sharepoint/__init__.py +7 -6
  182. alita_sdk/tools/sharepoint/api_wrapper.py +127 -36
  183. alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
  184. alita_sdk/tools/sharepoint/utils.py +8 -2
  185. alita_sdk/tools/slack/__init__.py +7 -6
  186. alita_sdk/tools/sql/__init__.py +8 -7
  187. alita_sdk/tools/sql/api_wrapper.py +71 -23
  188. alita_sdk/tools/testio/__init__.py +7 -6
  189. alita_sdk/tools/testrail/__init__.py +8 -9
  190. alita_sdk/tools/utils/__init__.py +26 -4
  191. alita_sdk/tools/utils/content_parser.py +88 -60
  192. alita_sdk/tools/utils/text_operations.py +254 -0
  193. alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +76 -26
  194. alita_sdk/tools/xray/__init__.py +9 -7
  195. alita_sdk/tools/zephyr/__init__.py +7 -6
  196. alita_sdk/tools/zephyr_enterprise/__init__.py +8 -6
  197. alita_sdk/tools/zephyr_essential/__init__.py +7 -6
  198. alita_sdk/tools/zephyr_essential/api_wrapper.py +12 -13
  199. alita_sdk/tools/zephyr_scale/__init__.py +7 -6
  200. alita_sdk/tools/zephyr_squad/__init__.py +7 -6
  201. {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/METADATA +147 -2
  202. {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/RECORD +206 -130
  203. alita_sdk-0.3.499.dist-info/entry_points.txt +2 -0
  204. {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/WHEEL +0 -0
  205. {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/licenses/LICENSE +0 -0
  206. {alita_sdk-0.3.351.dist-info → alita_sdk-0.3.499.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,8 @@ from abc import ABC, abstractmethod
2
2
  from typing import Any, Dict, Optional, List
3
3
  from logging import getLogger
4
4
 
5
+ from ...runtime.utils.utils import IndexerKeywords
6
+
5
7
  logger = getLogger(__name__)
6
8
 
7
9
 
@@ -24,13 +26,13 @@ class VectorStoreAdapter(ABC):
24
26
  pass
25
27
 
26
28
  @abstractmethod
27
- def get_indexed_ids(self, vectorstore_wrapper, collection_suffix: Optional[str] = '') -> List[str]:
29
+ def get_indexed_ids(self, vectorstore_wrapper, index_name: Optional[str] = '') -> List[str]:
28
30
  """Get all indexed document IDs from vectorstore"""
29
31
  pass
30
32
 
31
33
  @abstractmethod
32
- def clean_collection(self, vectorstore_wrapper, collection_suffix: str = ''):
33
- """Clean the vectorstore collection by deleting all indexed data."""
34
+ def clean_collection(self, vectorstore_wrapper, index_name: str = '', including_index_meta: bool = False):
35
+ """Clean the vectorstore collection by deleting all indexed data. If including_index_meta is True, skip the index_meta records."""
34
36
  pass
35
37
 
36
38
  @abstractmethod
@@ -39,7 +41,7 @@ class VectorStoreAdapter(ABC):
39
41
  pass
40
42
 
41
43
  @abstractmethod
42
- def get_code_indexed_data(self, vectorstore_wrapper, collection_suffix) -> Dict[str, Dict[str, Any]]:
44
+ def get_code_indexed_data(self, vectorstore_wrapper, index_name) -> Dict[str, Dict[str, Any]]:
43
45
  """Get all indexed data from vectorstore for code content"""
44
46
  pass
45
47
 
@@ -48,6 +50,11 @@ class VectorStoreAdapter(ABC):
48
50
  """Add a new collection name to the metadata"""
49
51
  pass
50
52
 
53
+ @abstractmethod
54
+ def get_index_meta(self, vectorstore_wrapper, index_name: str) -> List[Dict[str, Any]]:
55
+ """Get all index_meta entries from the vector store."""
56
+ pass
57
+
51
58
 
52
59
  class PGVectorAdapter(VectorStoreAdapter):
53
60
  """Adapter for PGVector database operations."""
@@ -99,20 +106,25 @@ class PGVectorAdapter(VectorStoreAdapter):
99
106
  session.commit()
100
107
  logger.info(f"Schema '{schema_name}' has been dropped.")
101
108
 
102
- def get_indexed_ids(self, vectorstore_wrapper, collection_suffix: Optional[str] = '') -> List[str]:
109
+ def get_indexed_ids(self, vectorstore_wrapper, index_name: Optional[str] = '') -> List[str]:
103
110
  """Get all indexed document IDs from PGVector"""
104
111
  from sqlalchemy.orm import Session
105
- from sqlalchemy import func
112
+ from sqlalchemy import func, or_
106
113
 
107
114
  store = vectorstore_wrapper.vectorstore
108
115
  try:
109
116
  with Session(store.session_maker.bind) as session:
110
117
  # Start building the query
111
118
  query = session.query(store.EmbeddingStore.id)
112
- # Apply filter only if collection_suffix is provided
113
- if collection_suffix:
119
+ # Apply filter only if index_name is provided
120
+ if index_name:
114
121
  query = query.filter(
115
- func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == collection_suffix
122
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name,
123
+ or_(
124
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'type').is_(None),
125
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata,
126
+ 'type') != IndexerKeywords.INDEX_META_TYPE.value
127
+ )
116
128
  )
117
129
  ids = query.all()
118
130
  return [str(id_tuple[0]) for id_tuple in ids]
@@ -120,25 +132,37 @@ class PGVectorAdapter(VectorStoreAdapter):
120
132
  logger.error(f"Failed to get indexed IDs from PGVector: {str(e)}")
121
133
  return []
122
134
 
123
- def clean_collection(self, vectorstore_wrapper, collection_suffix: str = ''):
124
- """Clean the vectorstore collection by deleting all indexed data."""
125
- # This logic deletes all data from the vectorstore collection without removal of collection.
126
- # Collection itself remains available for future indexing.
127
- vectorstore_wrapper.vectorstore.delete(ids=self.get_indexed_ids(vectorstore_wrapper, collection_suffix))
135
+ def clean_collection(self, vectorstore_wrapper, index_name: str = '', including_index_meta: bool = False):
136
+ """Clean the vectorstore collection by deleting all indexed data. If including_index_meta is True, skip the index_meta records."""
137
+ from sqlalchemy.orm import Session
138
+ from sqlalchemy import func, or_
139
+ store = vectorstore_wrapper.vectorstore
140
+ with Session(store.session_maker.bind) as session:
141
+ if including_index_meta:
142
+ session.query(store.EmbeddingStore).filter(
143
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name
144
+ ).delete(synchronize_session=False)
145
+ else:
146
+ session.query(store.EmbeddingStore).filter(
147
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name,
148
+ or_(func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'type').is_(None),
149
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'type') != IndexerKeywords.INDEX_META_TYPE.value)
150
+ ).delete(synchronize_session=False)
151
+ session.commit()
128
152
 
129
153
  def is_vectorstore_type(self, vectorstore) -> bool:
130
154
  """Check if the vectorstore is a PGVector store."""
131
155
  return hasattr(vectorstore, 'session_maker') and hasattr(vectorstore, 'EmbeddingStore')
132
156
 
133
- def get_indexed_data(self, vectorstore_wrapper, collection_suffix: str)-> Dict[str, Dict[str, Any]]:
134
- """Get all indexed data from PGVector for non-code content per collection_suffix."""
157
+ def get_indexed_data(self, vectorstore_wrapper, index_name: str)-> Dict[str, Dict[str, Any]]:
158
+ """Get all indexed data from PGVector for non-code content per index_name."""
135
159
  from sqlalchemy.orm import Session
136
160
  from sqlalchemy import func
137
161
  from ...runtime.utils.utils import IndexerKeywords
138
162
 
139
163
  result = {}
140
164
  try:
141
- vectorstore_wrapper._log_data("Retrieving already indexed data from PGVector vectorstore",
165
+ vectorstore_wrapper._log_tool_event("Retrieving already indexed data from PGVector vectorstore",
142
166
  tool_name="get_indexed_data")
143
167
  store = vectorstore_wrapper.vectorstore
144
168
  with Session(store.session_maker.bind) as session:
@@ -147,7 +171,7 @@ class PGVectorAdapter(VectorStoreAdapter):
147
171
  store.EmbeddingStore.document,
148
172
  store.EmbeddingStore.cmetadata
149
173
  ).filter(
150
- func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == collection_suffix
174
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name
151
175
  ).all()
152
176
 
153
177
  # Process the retrieved data
@@ -180,14 +204,14 @@ class PGVectorAdapter(VectorStoreAdapter):
180
204
 
181
205
  return result
182
206
 
183
- def get_code_indexed_data(self, vectorstore_wrapper, collection_suffix: str) -> Dict[str, Dict[str, Any]]:
207
+ def get_code_indexed_data(self, vectorstore_wrapper, index_name: str) -> Dict[str, Dict[str, Any]]:
184
208
  """Get all indexed code data from PGVector per collection suffix."""
185
209
  from sqlalchemy.orm import Session
186
210
  from sqlalchemy import func
187
211
 
188
212
  result = {}
189
213
  try:
190
- vectorstore_wrapper._log_data("Retrieving already indexed code data from PGVector vectorstore",
214
+ vectorstore_wrapper._log_tool_event(message="Retrieving already indexed code data from PGVector vectorstore",
191
215
  tool_name="index_code_data")
192
216
  store = vectorstore_wrapper.vectorstore
193
217
  with (Session(store.session_maker.bind) as session):
@@ -195,7 +219,7 @@ class PGVectorAdapter(VectorStoreAdapter):
195
219
  store.EmbeddingStore.id,
196
220
  store.EmbeddingStore.cmetadata
197
221
  ).filter(
198
- func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == collection_suffix
222
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name
199
223
  ).all()
200
224
 
201
225
  for db_id, meta in docs:
@@ -265,6 +289,29 @@ class PGVectorAdapter(VectorStoreAdapter):
265
289
  except Exception as e:
266
290
  logger.error(f"Failed to update collection for entry ID {entry_id}: {str(e)}")
267
291
 
292
+ def get_index_meta(self, vectorstore_wrapper, index_name: str) -> List[Dict[str, Any]]:
293
+ from sqlalchemy.orm import Session
294
+ from sqlalchemy import func
295
+
296
+ store = vectorstore_wrapper.vectorstore
297
+ try:
298
+ with Session(store.session_maker.bind) as session:
299
+ meta = session.query(
300
+ store.EmbeddingStore.id,
301
+ store.EmbeddingStore.document,
302
+ store.EmbeddingStore.cmetadata
303
+ ).filter(
304
+ store.EmbeddingStore.cmetadata['type'].astext == IndexerKeywords.INDEX_META_TYPE.value,
305
+ func.jsonb_extract_path_text(store.EmbeddingStore.cmetadata, 'collection') == index_name
306
+ ).all()
307
+ result = []
308
+ for id, document, cmetadata in meta:
309
+ result.append({"id": id, "content": document, "metadata": cmetadata})
310
+ return result
311
+ except Exception as e:
312
+ logger.error(f"Failed to get index_meta from PGVector: {str(e)}")
313
+ raise e
314
+
268
315
 
269
316
  class ChromaAdapter(VectorStoreAdapter):
270
317
  """Adapter for Chroma database operations."""
@@ -282,7 +329,7 @@ class ChromaAdapter(VectorStoreAdapter):
282
329
  def remove_collection(self, vectorstore_wrapper, collection_name: str):
283
330
  vectorstore_wrapper.vectorstore.delete_collection()
284
331
 
285
- def get_indexed_ids(self, vectorstore_wrapper, collection_suffix: Optional[str] = '') -> List[str]:
332
+ def get_indexed_ids(self, vectorstore_wrapper, index_name: Optional[str] = '') -> List[str]:
286
333
  """Get all indexed document IDs from Chroma"""
287
334
  try:
288
335
  data = vectorstore_wrapper.vectorstore.get(include=[]) # Only get IDs, no metadata
@@ -291,9 +338,9 @@ class ChromaAdapter(VectorStoreAdapter):
291
338
  logger.error(f"Failed to get indexed IDs from Chroma: {str(e)}")
292
339
  return []
293
340
 
294
- def clean_collection(self, vectorstore_wrapper, collection_suffix: str = ''):
295
- """Clean the vectorstore collection by deleting all indexed data."""
296
- vectorstore_wrapper.vectorstore.delete(ids=self.get_indexed_ids(vectorstore_wrapper, collection_suffix))
341
+ def clean_collection(self, vectorstore_wrapper, index_name: str = '', including_index_meta: bool = False):
342
+ """Clean the vectorstore collection by deleting all indexed data. including_index_meta is ignored."""
343
+ vectorstore_wrapper.vectorstore.delete(ids=self.get_indexed_ids(vectorstore_wrapper, index_name))
297
344
 
298
345
  def get_indexed_data(self, vectorstore_wrapper):
299
346
  """Get all indexed data from Chroma for non-code content"""
@@ -331,7 +378,7 @@ class ChromaAdapter(VectorStoreAdapter):
331
378
 
332
379
  return result
333
380
 
334
- def get_code_indexed_data(self, vectorstore_wrapper, collection_suffix) -> Dict[str, Dict[str, Any]]:
381
+ def get_code_indexed_data(self, vectorstore_wrapper, index_name) -> Dict[str, Dict[str, Any]]:
335
382
  """Get all indexed code data from Chroma."""
336
383
  result = {}
337
384
  try:
@@ -361,6 +408,9 @@ class ChromaAdapter(VectorStoreAdapter):
361
408
  # This is a simplified implementation - in practice, you might need more complex logic
362
409
  logger.warning("add_to_collection for Chroma is not fully implemented yet")
363
410
 
411
+ def get_index_meta(self, vectorstore_wrapper, index_name: str) -> List[Dict[str, Any]]:
412
+ logger.warning("get_index_meta for Chroma is not implemented yet")
413
+
364
414
 
365
415
  class VectorStoreAdapterFactory:
366
416
  """Factory for creating vector store adapters."""
@@ -8,7 +8,7 @@ from pydantic import create_model, BaseModel, Field
8
8
  from .api_wrapper import XrayApiWrapper
9
9
  from ..base.tool import BaseAction
10
10
  from ..elitea_base import filter_missconfigured_index_tools
11
- from ..utils import clean_string, get_max_toolkit_length, TOOLKIT_SPLITTER
11
+ from ..utils import clean_string, get_max_toolkit_length
12
12
  from ...configurations.pgvector import PgVectorConfiguration
13
13
  from ...configurations.xray import XrayConfiguration
14
14
 
@@ -34,12 +34,10 @@ def get_tools(tool):
34
34
 
35
35
  class XrayToolkit(BaseToolkit):
36
36
  tools: List[BaseTool] = []
37
- toolkit_max_length: int = 0
38
37
 
39
38
  @staticmethod
40
39
  def toolkit_config_schema() -> BaseModel:
41
40
  selected_tools = {x['name']: x['args_schema'].schema() for x in XrayApiWrapper.model_construct().get_available_tools()}
42
- XrayToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
43
41
  return create_model(
44
42
  name,
45
43
  limit=(Optional[int], Field(description="Limit", default=100)),
@@ -56,7 +54,7 @@ class XrayToolkit(BaseToolkit):
56
54
  {
57
55
  'metadata': {
58
56
  "label": "XRAY cloud", "icon_url": "xray.svg",
59
- "categories": ["test management"],
57
+ "categories": ["test management"],
60
58
  "extra_categories": ["test automation", "test case management", "test planning"]
61
59
  }
62
60
  }
@@ -75,17 +73,21 @@ class XrayToolkit(BaseToolkit):
75
73
  **(kwargs.get('pgvector_configuration') or {}),
76
74
  }
77
75
  xray_api_wrapper = XrayApiWrapper(**wrapper_payload)
78
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
79
76
  available_tools = xray_api_wrapper.get_available_tools()
80
77
  tools = []
81
78
  for tool in available_tools:
82
79
  if selected_tools:
83
80
  if tool["name"] not in selected_tools:
84
81
  continue
82
+ description = tool["description"]
83
+ if toolkit_name:
84
+ description = f"Toolkit: {toolkit_name}\n{description}"
85
+ description = description + "\nXray instance: " + xray_api_wrapper.base_url
86
+ description = description[:1000]
85
87
  tools.append(BaseAction(
86
88
  api_wrapper=xray_api_wrapper,
87
- name=prefix + tool["name"],
88
- description=tool["description"] + "\nXray instance: " + xray_api_wrapper.base_url,
89
+ name=tool["name"],
90
+ description=description,
89
91
  args_schema=tool["args_schema"]
90
92
  ))
91
93
  return cls(tools=tools)
@@ -8,7 +8,7 @@ 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
12
 
13
13
  name = "zephyr"
14
14
 
@@ -23,15 +23,13 @@ def get_tools(tool):
23
23
 
24
24
  class ZephyrToolkit(BaseToolkit):
25
25
  tools: List[BaseTool] = []
26
- toolkit_max_length: int = 0
27
26
 
28
27
  @staticmethod
29
28
  def toolkit_config_schema() -> BaseModel:
30
29
  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
30
  return create_model(
33
31
  name,
34
- base_url=(str, Field(description="Base URL", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': ZephyrToolkit.toolkit_max_length})),
32
+ base_url=(str, Field(description="Base URL")),
35
33
  username=(str, Field(description="Username")),
36
34
  password=(SecretStr, Field(description="Password", json_schema_extra={'secret': True})),
37
35
  selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
@@ -49,17 +47,20 @@ class ZephyrToolkit(BaseToolkit):
49
47
  @filter_missconfigured_index_tools
50
48
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
51
49
  zephyr_api_wrapper = ZephyrV1ApiWrapper(**kwargs)
52
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
53
50
  available_tools = zephyr_api_wrapper.get_available_tools()
54
51
  tools = []
55
52
  for tool in available_tools:
56
53
  if selected_tools:
57
54
  if tool["name"] not in selected_tools:
58
55
  continue
56
+ description = tool["description"]
57
+ if toolkit_name:
58
+ description = f"Toolkit: {toolkit_name}\n{description}"
59
+ description = description[:1000]
59
60
  tools.append(BaseAction(
60
61
  api_wrapper=zephyr_api_wrapper,
61
62
  name=tool["name"],
62
- description=tool["description"],
63
+ description=description,
63
64
  args_schema=tool["args_schema"]
64
65
  ))
65
66
  return cls(tools=tools)
@@ -5,7 +5,7 @@ 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
11
 
@@ -28,13 +28,11 @@ def get_tools(tool):
28
28
 
29
29
  class ZephyrEnterpriseToolkit(BaseToolkit):
30
30
  tools: List[BaseTool] = []
31
- toolkit_max_length: int = 0
32
31
 
33
32
  @staticmethod
34
33
  def toolkit_config_schema() -> BaseModel:
35
34
  selected_tools = {x['name']: x['args_schema'].schema() for x in
36
35
  ZephyrApiWrapper.model_construct().get_available_tools()}
37
- ZephyrEnterpriseToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
38
36
  return create_model(
39
37
  name,
40
38
  zephyr_configuration=(ZephyrEnterpriseConfiguration, Field(description="Zephyr Configuration", json_schema_extra={'configuration_types': ['zephyr_enterprise']})),
@@ -67,16 +65,20 @@ class ZephyrEnterpriseToolkit(BaseToolkit):
67
65
  **(kwargs.get('embedding_configuration') or {}),
68
66
  }
69
67
  zephyr_api_wrapper = ZephyrApiWrapper(**wrapper_payload)
70
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
71
68
  available_tools = zephyr_api_wrapper.get_available_tools()
72
69
  tools = []
73
70
  for tool in available_tools:
74
71
  if selected_tools and tool["name"] not in selected_tools:
75
72
  continue
73
+ description = tool["description"]
74
+ if toolkit_name:
75
+ description = f"Toolkit: {toolkit_name}\n{description}"
76
+ description = description + "\nZephyr Enterprise instance: " + zephyr_api_wrapper.base_url
77
+ description = description[:1000]
76
78
  tools.append(BaseAction(
77
79
  api_wrapper=zephyr_api_wrapper,
78
- name=prefix + tool["name"],
79
- description=tool["description"] + "\nZephyr Enterprise instance: " + zephyr_api_wrapper.base_url,
80
+ name=tool["name"],
81
+ description=description,
80
82
  args_schema=tool["args_schema"]
81
83
  ))
82
84
  return cls(tools=tools)
@@ -6,7 +6,7 @@ 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
12
 
@@ -29,12 +29,10 @@ def get_tools(tool):
29
29
 
30
30
  class ZephyrEssentialToolkit(BaseToolkit):
31
31
  tools: List[BaseTool] = []
32
- toolkit_max_length: int = 0
33
32
 
34
33
  @staticmethod
35
34
  def toolkit_config_schema() -> BaseModel:
36
35
  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
36
  return create_model(
39
37
  name,
40
38
  zephyr_essential_configuration=(ZephyrEssentialConfiguration, Field(description="Zephyr Essential Configuration", json_schema_extra={'configuration_types': ['zephyr_essential']})),
@@ -62,17 +60,20 @@ class ZephyrEssentialToolkit(BaseToolkit):
62
60
  **(kwargs.get('pgvector_configuration') or {}),
63
61
  }
64
62
  zephyr_api_wrapper = ZephyrEssentialApiWrapper(**wrapper_payload)
65
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
66
63
  available_tools = zephyr_api_wrapper.get_available_tools()
67
64
  tools = []
68
65
  for tool in available_tools:
69
66
  if selected_tools:
70
67
  if tool["name"] not in selected_tools:
71
68
  continue
69
+ description = tool["description"]
70
+ if toolkit_name:
71
+ description = f"Toolkit: {toolkit_name}\n{description}"
72
+ description = description[:1000]
72
73
  tools.append(BaseAction(
73
74
  api_wrapper=zephyr_api_wrapper,
74
- name=prefix + tool["name"],
75
- description=tool["description"],
75
+ name=tool["name"],
76
+ description=description,
76
77
  args_schema=tool["args_schema"]
77
78
  ))
78
79
  return cls(tools=tools)
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import json
2
3
  import logging
3
4
  from typing import Optional, Generator, Literal
@@ -284,22 +285,20 @@ class ZephyrEssentialApiWrapper(NonCodeIndexerToolkit):
284
285
  if isinstance(v, (str, int, float, bool, list, dict))
285
286
  }
286
287
  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:
288
+ #
292
289
  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
290
+ additional_content = self._process_test_case(metadata['key'])
291
+ for steps_type, content in additional_content.items():
292
+ if content:
293
+ page_content = json.dumps(content)
294
+ content_hash = hashlib.sha256(page_content.encode('utf-8')).hexdigest()
295
+ metadata[IndexerKeywords.UPDATED_ON.value] = content_hash
296
+ metadata[IndexerKeywords.CONTENT_IN_BYTES.value] = page_content.encode('utf-8')
297
+ metadata["steps_type"] = steps_type
300
298
  except Exception as e:
301
299
  logging.error(f"Failed to process document: {e}")
302
- yield document
300
+ #
301
+ yield Document(page_content="", metadata=metadata)
303
302
 
304
303
  def _process_test_case(self, key) -> dict:
305
304
  steps = self.get_test_case_test_steps(key)
@@ -7,7 +7,7 @@ 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
13
 
@@ -32,12 +32,10 @@ def get_tools(tool):
32
32
 
33
33
  class ZephyrScaleToolkit(BaseToolkit):
34
34
  tools: List[BaseTool] = []
35
- toolkit_max_length: int = 0
36
35
 
37
36
  @staticmethod
38
37
  def toolkit_config_schema() -> BaseModel:
39
38
  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
39
  return create_model(
42
40
  name,
43
41
  max_results=(int, Field(default=100, description="Results count to show")),
@@ -75,17 +73,20 @@ class ZephyrScaleToolkit(BaseToolkit):
75
73
  **(kwargs.get('pgvector_configuration') or {}),
76
74
  }
77
75
  zephyr_wrapper = ZephyrScaleApiWrapper(**wrapper_payload)
78
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
79
76
  available_tools = zephyr_wrapper.get_available_tools()
80
77
  tools = []
81
78
  for tool in available_tools:
82
79
  if selected_tools:
83
80
  if tool["name"] not in selected_tools:
84
81
  continue
82
+ description = tool["description"]
83
+ if toolkit_name:
84
+ description = f"Toolkit: {toolkit_name}\n{description}"
85
+ description = description[:1000]
85
86
  tools.append(BaseAction(
86
87
  api_wrapper=zephyr_wrapper,
87
- name=prefix + tool["name"],
88
- description=tool["description"],
88
+ name=tool["name"],
89
+ description=description,
89
90
  args_schema=tool["args_schema"]
90
91
  ))
91
92
  return cls(tools=tools)
@@ -6,7 +6,7 @@ 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
10
 
11
11
  name = "zephyr_squad"
12
12
 
@@ -21,12 +21,10 @@ def get_tools(tool):
21
21
 
22
22
  class ZephyrSquadToolkit(BaseToolkit):
23
23
  tools: List[BaseTool] = []
24
- toolkit_max_length: int = 0
25
24
 
26
25
  @staticmethod
27
26
  def toolkit_config_schema() -> BaseModel:
28
27
  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
28
  return create_model(
31
29
  name,
32
30
  account_id=(str, Field(description="AccountID for the user that is going to be authenticating")),
@@ -43,17 +41,20 @@ class ZephyrSquadToolkit(BaseToolkit):
43
41
  @filter_missconfigured_index_tools
44
42
  def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
45
43
  zephyr_api_wrapper = ZephyrSquadApiWrapper(**kwargs)
46
- prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
47
44
  available_tools = zephyr_api_wrapper.get_available_tools()
48
45
  tools = []
49
46
  for tool in available_tools:
50
47
  if selected_tools:
51
48
  if tool["name"] not in selected_tools:
52
49
  continue
50
+ description = tool["description"]
51
+ if toolkit_name:
52
+ description = f"Toolkit: {toolkit_name}\n{description}"
53
+ description = description[:1000]
53
54
  tools.append(BaseAction(
54
55
  api_wrapper=zephyr_api_wrapper,
55
- name=prefix + tool["name"],
56
- description=tool["description"],
56
+ name=tool["name"],
57
+ description=description,
57
58
  args_schema=tool["args_schema"]
58
59
  ))
59
60
  return cls(tools=tools)