alita-sdk 0.3.257__py3-none-any.whl → 0.3.562__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.
- alita_sdk/cli/__init__.py +10 -0
- alita_sdk/cli/__main__.py +17 -0
- alita_sdk/cli/agent/__init__.py +5 -0
- alita_sdk/cli/agent/default.py +258 -0
- alita_sdk/cli/agent_executor.py +155 -0
- alita_sdk/cli/agent_loader.py +215 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3601 -0
- alita_sdk/cli/callbacks.py +647 -0
- alita_sdk/cli/cli.py +168 -0
- alita_sdk/cli/config.py +306 -0
- alita_sdk/cli/context/__init__.py +30 -0
- alita_sdk/cli/context/cleanup.py +198 -0
- alita_sdk/cli/context/manager.py +731 -0
- alita_sdk/cli/context/message.py +285 -0
- alita_sdk/cli/context/strategies.py +289 -0
- alita_sdk/cli/context/token_estimation.py +127 -0
- alita_sdk/cli/formatting.py +182 -0
- alita_sdk/cli/input_handler.py +419 -0
- alita_sdk/cli/inventory.py +1073 -0
- alita_sdk/cli/mcp_loader.py +315 -0
- alita_sdk/cli/toolkit.py +327 -0
- alita_sdk/cli/toolkit_loader.py +85 -0
- alita_sdk/cli/tools/__init__.py +43 -0
- alita_sdk/cli/tools/approval.py +224 -0
- alita_sdk/cli/tools/filesystem.py +1751 -0
- alita_sdk/cli/tools/planning.py +389 -0
- alita_sdk/cli/tools/terminal.py +414 -0
- alita_sdk/community/__init__.py +72 -12
- alita_sdk/community/inventory/__init__.py +236 -0
- alita_sdk/community/inventory/config.py +257 -0
- alita_sdk/community/inventory/enrichment.py +2137 -0
- alita_sdk/community/inventory/extractors.py +1469 -0
- alita_sdk/community/inventory/ingestion.py +3172 -0
- alita_sdk/community/inventory/knowledge_graph.py +1457 -0
- alita_sdk/community/inventory/parsers/__init__.py +218 -0
- alita_sdk/community/inventory/parsers/base.py +295 -0
- alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
- alita_sdk/community/inventory/parsers/go_parser.py +851 -0
- alita_sdk/community/inventory/parsers/html_parser.py +389 -0
- alita_sdk/community/inventory/parsers/java_parser.py +593 -0
- alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
- alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
- alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
- alita_sdk/community/inventory/parsers/python_parser.py +604 -0
- alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
- alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
- alita_sdk/community/inventory/parsers/text_parser.py +322 -0
- alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
- alita_sdk/community/inventory/patterns/__init__.py +61 -0
- alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
- alita_sdk/community/inventory/patterns/loader.py +348 -0
- alita_sdk/community/inventory/patterns/registry.py +198 -0
- alita_sdk/community/inventory/presets.py +535 -0
- alita_sdk/community/inventory/retrieval.py +1403 -0
- alita_sdk/community/inventory/toolkit.py +173 -0
- alita_sdk/community/inventory/toolkit_utils.py +176 -0
- alita_sdk/community/inventory/visualize.py +1370 -0
- alita_sdk/configurations/__init__.py +11 -0
- alita_sdk/configurations/ado.py +148 -2
- alita_sdk/configurations/azure_search.py +1 -1
- alita_sdk/configurations/bigquery.py +1 -1
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/browser.py +18 -0
- alita_sdk/configurations/carrier.py +19 -0
- alita_sdk/configurations/confluence.py +130 -1
- alita_sdk/configurations/delta_lake.py +1 -1
- alita_sdk/configurations/figma.py +76 -5
- alita_sdk/configurations/github.py +65 -1
- alita_sdk/configurations/gitlab.py +81 -0
- alita_sdk/configurations/google_places.py +17 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/openapi.py +111 -0
- alita_sdk/configurations/postman.py +1 -1
- alita_sdk/configurations/qtest.py +72 -3
- alita_sdk/configurations/report_portal.py +115 -0
- alita_sdk/configurations/salesforce.py +19 -0
- alita_sdk/configurations/service_now.py +1 -12
- alita_sdk/configurations/sharepoint.py +167 -0
- alita_sdk/configurations/sonar.py +18 -0
- alita_sdk/configurations/sql.py +20 -0
- alita_sdk/configurations/testio.py +101 -0
- alita_sdk/configurations/testrail.py +88 -0
- alita_sdk/configurations/xray.py +94 -1
- alita_sdk/configurations/zephyr_enterprise.py +94 -1
- alita_sdk/configurations/zephyr_essential.py +95 -0
- alita_sdk/runtime/clients/artifact.py +21 -4
- alita_sdk/runtime/clients/client.py +458 -67
- alita_sdk/runtime/clients/mcp_discovery.py +342 -0
- alita_sdk/runtime/clients/mcp_manager.py +262 -0
- alita_sdk/runtime/clients/sandbox_client.py +352 -0
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +183 -43
- alita_sdk/runtime/langchain/constants.py +647 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
- alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
- alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
- alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
- alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
- alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
- alita_sdk/runtime/langchain/langraph_agent.py +407 -92
- alita_sdk/runtime/langchain/utils.py +102 -8
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/models/mcp_models.py +61 -0
- alita_sdk/runtime/skills/__init__.py +91 -0
- alita_sdk/runtime/skills/callbacks.py +498 -0
- alita_sdk/runtime/skills/discovery.py +540 -0
- alita_sdk/runtime/skills/executor.py +610 -0
- alita_sdk/runtime/skills/input_builder.py +371 -0
- alita_sdk/runtime/skills/models.py +330 -0
- alita_sdk/runtime/skills/registry.py +355 -0
- alita_sdk/runtime/skills/skill_runner.py +330 -0
- alita_sdk/runtime/toolkits/__init__.py +28 -0
- alita_sdk/runtime/toolkits/application.py +14 -4
- alita_sdk/runtime/toolkits/artifact.py +24 -9
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +780 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +11 -6
- alita_sdk/runtime/toolkits/tools.py +314 -70
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +24 -0
- alita_sdk/runtime/tools/application.py +16 -4
- alita_sdk/runtime/tools/artifact.py +367 -33
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +100 -4
- alita_sdk/runtime/tools/graph.py +81 -0
- alita_sdk/runtime/tools/image_generation.py +218 -0
- alita_sdk/runtime/tools/llm.py +1013 -177
- alita_sdk/runtime/tools/loop.py +3 -1
- alita_sdk/runtime/tools/loop_output.py +3 -1
- alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
- alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
- alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
- alita_sdk/runtime/tools/planning/__init__.py +36 -0
- alita_sdk/runtime/tools/planning/models.py +246 -0
- alita_sdk/runtime/tools/planning/wrapper.py +607 -0
- alita_sdk/runtime/tools/router.py +2 -1
- alita_sdk/runtime/tools/sandbox.py +375 -0
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +69 -65
- alita_sdk/runtime/tools/vectorstore_base.py +163 -90
- alita_sdk/runtime/utils/AlitaCallback.py +137 -21
- alita_sdk/runtime/utils/mcp_client.py +492 -0
- alita_sdk/runtime/utils/mcp_oauth.py +361 -0
- alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/streamlit.py +41 -14
- alita_sdk/runtime/utils/toolkit_utils.py +28 -9
- alita_sdk/runtime/utils/utils.py +48 -0
- alita_sdk/tools/__init__.py +135 -37
- alita_sdk/tools/ado/__init__.py +2 -2
- alita_sdk/tools/ado/repos/__init__.py +15 -19
- alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
- alita_sdk/tools/ado/test_plan/__init__.py +26 -8
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
- alita_sdk/tools/ado/wiki/__init__.py +27 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
- alita_sdk/tools/ado/work_item/__init__.py +27 -12
- alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +12 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +14 -11
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +13 -8
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +454 -110
- alita_sdk/tools/bitbucket/__init__.py +27 -19
- alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
- alita_sdk/tools/browser/__init__.py +41 -16
- alita_sdk/tools/browser/crawler.py +3 -1
- alita_sdk/tools/browser/utils.py +15 -6
- alita_sdk/tools/carrier/__init__.py +18 -17
- alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
- alita_sdk/tools/carrier/excel_reporter.py +8 -4
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/codeparser.py +1 -1
- alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
- alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
- alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
- alita_sdk/tools/chunkers/universal_chunker.py +270 -0
- alita_sdk/tools/cloud/aws/__init__.py +11 -7
- alita_sdk/tools/cloud/azure/__init__.py +11 -7
- alita_sdk/tools/cloud/gcp/__init__.py +11 -7
- alita_sdk/tools/cloud/k8s/__init__.py +11 -7
- alita_sdk/tools/code/linter/__init__.py +9 -8
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +20 -13
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +21 -14
- alita_sdk/tools/confluence/api_wrapper.py +197 -58
- alita_sdk/tools/confluence/loader.py +14 -2
- alita_sdk/tools/custom_open_api/__init__.py +11 -5
- alita_sdk/tools/elastic/__init__.py +10 -8
- alita_sdk/tools/elitea_base.py +546 -64
- alita_sdk/tools/figma/__init__.py +11 -8
- alita_sdk/tools/figma/api_wrapper.py +352 -153
- alita_sdk/tools/github/__init__.py +17 -17
- alita_sdk/tools/github/api_wrapper.py +9 -26
- alita_sdk/tools/github/github_client.py +81 -12
- alita_sdk/tools/github/schemas.py +2 -1
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/gitlab/__init__.py +18 -13
- alita_sdk/tools/gitlab/api_wrapper.py +224 -80
- alita_sdk/tools/gitlab_org/__init__.py +13 -10
- alita_sdk/tools/google/bigquery/__init__.py +13 -13
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +20 -11
- alita_sdk/tools/jira/__init__.py +21 -11
- alita_sdk/tools/jira/api_wrapper.py +315 -168
- alita_sdk/tools/keycloak/__init__.py +10 -8
- alita_sdk/tools/localgit/__init__.py +8 -3
- alita_sdk/tools/localgit/local_git.py +62 -54
- alita_sdk/tools/localgit/tool.py +5 -1
- alita_sdk/tools/memory/__init__.py +38 -14
- alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
- alita_sdk/tools/ocr/__init__.py +10 -8
- alita_sdk/tools/openapi/__init__.py +281 -108
- alita_sdk/tools/openapi/api_wrapper.py +883 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +18 -11
- alita_sdk/tools/pandas/api_wrapper.py +40 -45
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +10 -11
- alita_sdk/tools/postman/api_wrapper.py +19 -8
- alita_sdk/tools/postman/postman_analysis.py +8 -1
- alita_sdk/tools/pptx/__init__.py +10 -10
- alita_sdk/tools/qtest/__init__.py +21 -14
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +12 -10
- alita_sdk/tools/report_portal/__init__.py +22 -16
- alita_sdk/tools/salesforce/__init__.py +21 -16
- alita_sdk/tools/servicenow/__init__.py +20 -16
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +16 -14
- alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +11 -7
- alita_sdk/tools/sql/__init__.py +21 -19
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +20 -13
- alita_sdk/tools/testrail/__init__.py +12 -11
- alita_sdk/tools/testrail/api_wrapper.py +214 -46
- alita_sdk/tools/utils/__init__.py +28 -4
- alita_sdk/tools/utils/content_parser.py +182 -62
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
- alita_sdk/tools/xray/__init__.py +17 -14
- alita_sdk/tools/xray/api_wrapper.py +58 -113
- alita_sdk/tools/yagmail/__init__.py +8 -3
- alita_sdk/tools/zephyr/__init__.py +11 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +15 -9
- alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
- alita_sdk/tools/zephyr_essential/__init__.py +15 -10
- alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
- alita_sdk/tools/zephyr_essential/client.py +6 -4
- alita_sdk/tools/zephyr_scale/__init__.py +12 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
- alita_sdk/tools/zephyr_squad/__init__.py +11 -7
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/METADATA +184 -37
- alita_sdk-0.3.562.dist-info/RECORD +450 -0
- alita_sdk-0.3.562.dist-info/entry_points.txt +2 -0
- alita_sdk/tools/bitbucket/tools.py +0 -304
- alita_sdk-0.3.257.dist-info/RECORD +0 -343
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.562.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import re
|
|
3
4
|
import urllib.parse
|
|
4
5
|
from typing import Dict, List, Generator, Optional
|
|
5
6
|
|
|
@@ -7,6 +8,7 @@ from azure.devops.connection import Connection
|
|
|
7
8
|
from azure.devops.v7_1.core import CoreClient
|
|
8
9
|
from azure.devops.v7_1.wiki import WikiClient
|
|
9
10
|
from azure.devops.v7_1.work_item_tracking import TeamContext, Wiql, WorkItemTrackingClient
|
|
11
|
+
from bs4 import BeautifulSoup
|
|
10
12
|
from langchain_core.documents import Document
|
|
11
13
|
from langchain_core.tools import ToolException
|
|
12
14
|
from msrest.authentication import BasicAuthentication
|
|
@@ -15,6 +17,8 @@ from pydantic import model_validator
|
|
|
15
17
|
from pydantic.fields import Field
|
|
16
18
|
|
|
17
19
|
from alita_sdk.tools.non_code_indexer_toolkit import NonCodeIndexerToolkit
|
|
20
|
+
from ...utils.content_parser import parse_file_content
|
|
21
|
+
from ....runtime.utils.utils import IndexerKeywords
|
|
18
22
|
|
|
19
23
|
logger = logging.getLogger(__name__)
|
|
20
24
|
|
|
@@ -52,7 +56,11 @@ ADOGetWorkItem = create_model(
|
|
|
52
56
|
id=(int, Field(description="The work item id")),
|
|
53
57
|
fields=(Optional[list[str]], Field(description="Comma-separated list of requested fields", default=None)),
|
|
54
58
|
as_of=(Optional[str], Field(description="AsOf UTC date time string", default=None)),
|
|
55
|
-
expand=(Optional[str], Field(description="The expand parameters for work item attributes. Possible options are { None, Relations, Fields, Links, All }.", default=None))
|
|
59
|
+
expand=(Optional[str], Field(description="The expand parameters for work item attributes. Possible options are { None, Relations, Fields, Links, All }.", default=None)),
|
|
60
|
+
parse_attachments=(Optional[bool], Field(description="Value that defines is attachment should be parsed.", default=False)),
|
|
61
|
+
image_description_prompt=(Optional[str],
|
|
62
|
+
Field(description="Prompt which is used for image description", default=None)),
|
|
63
|
+
|
|
56
64
|
)
|
|
57
65
|
|
|
58
66
|
ADOLinkWorkItem = create_model(
|
|
@@ -283,8 +291,23 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
283
291
|
logger.error(f"Error searching work items: {e}")
|
|
284
292
|
return ToolException(f"Error searching work items: {e}")
|
|
285
293
|
|
|
286
|
-
|
|
287
|
-
|
|
294
|
+
def parse_attachment_by_url(self, attachment_url, file_name=None, image_description_prompt=None):
|
|
295
|
+
match = re.search(r'attachments/([\w-]+)(?:\?fileName=([^&]+))?', attachment_url)
|
|
296
|
+
if match:
|
|
297
|
+
attachment_id = match.group(1)
|
|
298
|
+
if not file_name:
|
|
299
|
+
file_name = match.group(2)
|
|
300
|
+
if not file_name:
|
|
301
|
+
raise ToolException("File name must be provided either in the URL or as a parameter.")
|
|
302
|
+
return self.parse_attachment_by_id(attachment_id, file_name, image_description_prompt)
|
|
303
|
+
raise ToolException(f"Attachment '{attachment_url}' was not found.")
|
|
304
|
+
|
|
305
|
+
def parse_attachment_by_id(self, attachment_id, file_name, image_description_prompt):
|
|
306
|
+
file_content = self.get_attachment_content(attachment_id)
|
|
307
|
+
return parse_file_content(file_content=file_content, file_name=file_name,
|
|
308
|
+
llm=self.llm, prompt=image_description_prompt)
|
|
309
|
+
|
|
310
|
+
def get_work_item(self, id: int, fields: Optional[list[str]] = None, as_of: Optional[str] = None, expand: Optional[str] = None, parse_attachments=False, image_description_prompt=None):
|
|
288
311
|
"""Get a single work item by ID."""
|
|
289
312
|
try:
|
|
290
313
|
# Validate that the Azure DevOps client is initialized
|
|
@@ -306,11 +329,38 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
306
329
|
parsed_item.update(fields_data)
|
|
307
330
|
|
|
308
331
|
# extract relations if any
|
|
309
|
-
relations_data =
|
|
332
|
+
relations_data = None
|
|
333
|
+
if expand and str(expand).lower() in ("relations", "all"):
|
|
334
|
+
try:
|
|
335
|
+
relations_data = getattr(work_item, 'relations', None)
|
|
336
|
+
except KeyError:
|
|
337
|
+
relations_data = None
|
|
310
338
|
if relations_data:
|
|
311
|
-
parsed_item['relations'] = []
|
|
312
|
-
|
|
313
|
-
|
|
339
|
+
parsed_item['relations'] = [relation.as_dict() for relation in relations_data]
|
|
340
|
+
|
|
341
|
+
if parse_attachments:
|
|
342
|
+
# describe images in work item fields if present
|
|
343
|
+
for field_name, field_value in fields_data.items():
|
|
344
|
+
if isinstance(field_value, str):
|
|
345
|
+
soup = BeautifulSoup(field_value, 'html.parser')
|
|
346
|
+
images = soup.find_all('img')
|
|
347
|
+
for img in images:
|
|
348
|
+
src = img.get('src')
|
|
349
|
+
if src:
|
|
350
|
+
description = self.parse_attachment_by_url(src, image_description_prompt=image_description_prompt)
|
|
351
|
+
img['image-description'] = description
|
|
352
|
+
parsed_item[field_name] = str(soup)
|
|
353
|
+
# parse attached documents if present
|
|
354
|
+
for relation in parsed_item.get('relations', []):
|
|
355
|
+
# Only process actual file attachments
|
|
356
|
+
if relation.get('rel') == 'AttachedFile':
|
|
357
|
+
file_name = relation.get('attributes', {}).get('name')
|
|
358
|
+
if file_name:
|
|
359
|
+
try:
|
|
360
|
+
relation['content'] = self.parse_attachment_by_url(relation['url'], file_name, image_description_prompt=image_description_prompt)
|
|
361
|
+
except Exception as att_e:
|
|
362
|
+
logger.warning(f"Failed to parse attachment {file_name}: {att_e}")
|
|
363
|
+
|
|
314
364
|
|
|
315
365
|
return parsed_item
|
|
316
366
|
except Exception as e:
|
|
@@ -521,11 +571,45 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
521
571
|
'attachment_ids': {rel.url.split('/')[-1]:rel.attributes.get('name', '') for rel in wi.relations or [] if rel.rel == 'AttachedFile'}
|
|
522
572
|
})
|
|
523
573
|
|
|
574
|
+
def get_attachment_content(self, attachment_id):
|
|
575
|
+
content_generator = self._client.get_attachment_content(id=attachment_id, download=True)
|
|
576
|
+
return b"".join(content_generator)
|
|
577
|
+
|
|
524
578
|
def _process_document(self, document: Document) -> Generator[Document, None, None]:
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
579
|
+
raw_attachment_ids = document.metadata.get('attachment_ids', {})
|
|
580
|
+
|
|
581
|
+
# Normalize attachment_ids: accept dict or JSON string, raise otherwise
|
|
582
|
+
if isinstance(raw_attachment_ids, str):
|
|
583
|
+
try:
|
|
584
|
+
loaded = json.loads(raw_attachment_ids)
|
|
585
|
+
except json.JSONDecodeError:
|
|
586
|
+
raise TypeError(
|
|
587
|
+
f"Expected dict or JSON string for 'attachment_ids', got non-JSON string for id="
|
|
588
|
+
f"{document.metadata.get('id')}: {raw_attachment_ids!r}"
|
|
589
|
+
)
|
|
590
|
+
if not isinstance(loaded, dict):
|
|
591
|
+
raise TypeError(
|
|
592
|
+
f"'attachment_ids' JSON did not decode to dict for id={document.metadata.get('id')}: {loaded!r}"
|
|
593
|
+
)
|
|
594
|
+
attachment_ids = loaded
|
|
595
|
+
elif isinstance(raw_attachment_ids, dict):
|
|
596
|
+
attachment_ids = raw_attachment_ids
|
|
597
|
+
else:
|
|
598
|
+
raise TypeError(
|
|
599
|
+
f"Expected 'attachment_ids' to be dict or JSON string, got {type(raw_attachment_ids)} "
|
|
600
|
+
f"for id={document.metadata.get('id')}: {raw_attachment_ids!r}"
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
for attachment_id, file_name in attachment_ids.items():
|
|
604
|
+
content = self.get_attachment_content(attachment_id=attachment_id)
|
|
605
|
+
yield Document(
|
|
606
|
+
page_content="",
|
|
607
|
+
metadata={
|
|
608
|
+
'id': attachment_id,
|
|
609
|
+
IndexerKeywords.CONTENT_FILE_NAME.value: file_name,
|
|
610
|
+
IndexerKeywords.CONTENT_IN_BYTES.value: content,
|
|
611
|
+
},
|
|
612
|
+
)
|
|
529
613
|
|
|
530
614
|
def _index_tool_params(self):
|
|
531
615
|
"""Return the parameters for indexing data."""
|
|
@@ -5,7 +5,8 @@ from pydantic import create_model, BaseModel, Field, SecretStr
|
|
|
5
5
|
|
|
6
6
|
from .data_mining_wrapper import AdvancedJiraMiningWrapper
|
|
7
7
|
from ..base.tool import BaseAction
|
|
8
|
-
from ..
|
|
8
|
+
from ..elitea_base import filter_missconfigured_index_tools
|
|
9
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
9
10
|
|
|
10
11
|
name = "advanced_jira_mining"
|
|
11
12
|
|
|
@@ -27,15 +28,13 @@ def get_tools(tool):
|
|
|
27
28
|
|
|
28
29
|
class AdvancedJiraMiningToolkit(BaseToolkit):
|
|
29
30
|
tools: List[BaseTool] = []
|
|
30
|
-
toolkit_max_length: int = 0
|
|
31
31
|
|
|
32
32
|
@staticmethod
|
|
33
33
|
def toolkit_config_schema() -> BaseModel:
|
|
34
34
|
selected_tools = {x['name']: x['args_schema'].schema() for x in AdvancedJiraMiningWrapper.model_construct().get_available_tools()}
|
|
35
|
-
AdvancedJiraMiningToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
36
35
|
return create_model(
|
|
37
36
|
name,
|
|
38
|
-
jira_base_url=(str, Field(default="", title="Jira URL", description="Jira URL", json_schema_extra={'toolkit_name': True
|
|
37
|
+
jira_base_url=(str, Field(default="", title="Jira URL", description="Jira URL", json_schema_extra={'toolkit_name': True})),
|
|
39
38
|
confluence_base_url=(str, Field(default="", title="Confluence URL", description="Confluence URL")),
|
|
40
39
|
model_type=(str, Field(default="", title="Model type", description="Model type")),
|
|
41
40
|
summarization_prompt=(Optional[str], Field(default=None, title="Summarization prompt", description="Summarization prompt")),
|
|
@@ -59,22 +58,27 @@ class AdvancedJiraMiningToolkit(BaseToolkit):
|
|
|
59
58
|
)
|
|
60
59
|
|
|
61
60
|
@classmethod
|
|
61
|
+
@filter_missconfigured_index_tools
|
|
62
62
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
63
63
|
if selected_tools is None:
|
|
64
64
|
selected_tools = []
|
|
65
65
|
jira_mining_wrapper = AdvancedJiraMiningWrapper(**kwargs)
|
|
66
66
|
available_tools = jira_mining_wrapper.get_available_tools()
|
|
67
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
68
67
|
tools = []
|
|
69
68
|
for tool in available_tools:
|
|
70
69
|
if selected_tools:
|
|
71
70
|
if tool["name"] not in selected_tools:
|
|
72
71
|
continue
|
|
72
|
+
description = tool["description"]
|
|
73
|
+
if toolkit_name:
|
|
74
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
75
|
+
description = description[:1000]
|
|
73
76
|
tools.append(BaseAction(
|
|
74
77
|
api_wrapper=jira_mining_wrapper,
|
|
75
|
-
name=
|
|
76
|
-
description=
|
|
77
|
-
args_schema=tool["args_schema"]
|
|
78
|
+
name=tool["name"],
|
|
79
|
+
description=description,
|
|
80
|
+
args_schema=tool["args_schema"],
|
|
81
|
+
metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
|
|
78
82
|
))
|
|
79
83
|
return cls(tools=tools)
|
|
80
84
|
|
|
@@ -3,10 +3,10 @@ from functools import lru_cache
|
|
|
3
3
|
from typing import List, Optional, Type
|
|
4
4
|
|
|
5
5
|
from langchain_core.tools import BaseTool, BaseToolkit
|
|
6
|
-
from pydantic import BaseModel, Field,
|
|
6
|
+
from pydantic import BaseModel, Field, computed_field, field_validator
|
|
7
7
|
|
|
8
8
|
from alita_sdk.configurations.delta_lake import DeltaLakeConfiguration
|
|
9
|
-
from ...utils import
|
|
9
|
+
from ...utils import clean_string, get_max_toolkit_length
|
|
10
10
|
from .api_wrapper import DeltaLakeApiWrapper
|
|
11
11
|
from .tool import DeltaLakeAction
|
|
12
12
|
|
|
@@ -21,10 +21,6 @@ def get_available_tools() -> dict[str, dict]:
|
|
|
21
21
|
}
|
|
22
22
|
return available_tools
|
|
23
23
|
|
|
24
|
-
toolkit_max_length = lru_cache(maxsize=1)(
|
|
25
|
-
lambda: get_max_toolkit_length(get_available_tools())
|
|
26
|
-
)
|
|
27
|
-
|
|
28
24
|
class DeltaLakeToolkitConfig(BaseModel):
|
|
29
25
|
class Config:
|
|
30
26
|
title = name
|
|
@@ -54,7 +50,7 @@ class DeltaLakeToolkitConfig(BaseModel):
|
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
delta_lake_configuration:
|
|
53
|
+
delta_lake_configuration: DeltaLakeConfiguration = Field(description="Delta Lake Configuration", json_schema_extra={"configuration_types": ["delta_lake"]})
|
|
58
54
|
selected_tools: List[str] = Field(default=[], description="Selected tools", json_schema_extra={"args_schemas": get_available_tools()})
|
|
59
55
|
|
|
60
56
|
@field_validator("selected_tools", mode="before", check_fields=False)
|
|
@@ -87,9 +83,10 @@ class DeltaLakeToolkit(BaseToolkit):
|
|
|
87
83
|
|
|
88
84
|
@computed_field
|
|
89
85
|
@property
|
|
90
|
-
def
|
|
86
|
+
def toolkit_context(self) -> str:
|
|
87
|
+
"""Returns toolkit context for descriptions (max 1000 chars)."""
|
|
91
88
|
return (
|
|
92
|
-
clean_string(self.toolkit_name,
|
|
89
|
+
f" [Toolkit: {clean_string(self.toolkit_name, 0)}]"
|
|
93
90
|
if self.toolkit_name
|
|
94
91
|
else ""
|
|
95
92
|
)
|
|
@@ -118,12 +115,18 @@ class DeltaLakeToolkit(BaseToolkit):
|
|
|
118
115
|
selected_tools = set(selected_tools)
|
|
119
116
|
for t in instance.available_tools:
|
|
120
117
|
if t["name"] in selected_tools:
|
|
118
|
+
description = t["description"]
|
|
119
|
+
if toolkit_name:
|
|
120
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
121
|
+
description = f"S3 Path: {getattr(instance.api_wrapper, 's3_path', '')} Table Path: {getattr(instance.api_wrapper, 'table_path', '')}\n{description}"
|
|
122
|
+
description = description[:1000]
|
|
121
123
|
instance.tools.append(
|
|
122
124
|
DeltaLakeAction(
|
|
123
125
|
api_wrapper=instance.api_wrapper,
|
|
124
|
-
name=
|
|
125
|
-
description=
|
|
126
|
+
name=t["name"],
|
|
127
|
+
description=description,
|
|
126
128
|
args_schema=t["args_schema"],
|
|
129
|
+
metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
|
|
127
130
|
)
|
|
128
131
|
)
|
|
129
132
|
return instance
|
|
@@ -29,7 +29,11 @@ class DeltaLakeAction(BaseTool):
|
|
|
29
29
|
) -> str:
|
|
30
30
|
"""Use the Delta Lake API to run an operation."""
|
|
31
31
|
try:
|
|
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
|
+
tool_name = re.sub(r'_\d+$', '', self.name)
|
|
32
36
|
# Use the tool name to dispatch to the correct API wrapper method
|
|
33
|
-
return self.api_wrapper.run(
|
|
37
|
+
return self.api_wrapper.run(tool_name, *args, **kwargs)
|
|
34
38
|
except Exception as e:
|
|
35
39
|
return f"Error: {format_exc()}"
|
|
@@ -4,7 +4,9 @@ from .api_wrapper import AzureSearchApiWrapper
|
|
|
4
4
|
from ...base.tool import BaseAction
|
|
5
5
|
from langchain_core.tools import BaseToolkit, BaseTool
|
|
6
6
|
from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
from ...elitea_base import filter_missconfigured_index_tools
|
|
9
|
+
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
8
10
|
from ....configurations.azure_search import AzureSearchConfiguration
|
|
9
11
|
import requests
|
|
10
12
|
|
|
@@ -29,17 +31,15 @@ def get_toolkit():
|
|
|
29
31
|
|
|
30
32
|
class AzureSearchToolkit(BaseToolkit):
|
|
31
33
|
tools: List[BaseTool] = []
|
|
32
|
-
toolkit_max_length: int = 0
|
|
33
34
|
|
|
34
35
|
@staticmethod
|
|
35
36
|
def toolkit_config_schema() -> BaseModel:
|
|
36
37
|
selected_tools = {x['name']: x['args_schema'].schema() for x in AzureSearchApiWrapper.model_construct().get_available_tools()}
|
|
37
|
-
AzureSearchToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
38
38
|
m = create_model(
|
|
39
39
|
name,
|
|
40
40
|
index_name=(str, Field(description="Azure Search index name")),
|
|
41
41
|
azure_search_configuration=(
|
|
42
|
-
|
|
42
|
+
AzureSearchConfiguration,
|
|
43
43
|
Field(description="Azure Search Configuration", json_schema_extra={'configuration_types': ['azure_search']})
|
|
44
44
|
),
|
|
45
45
|
api_version=(Optional[str], Field(description="API version", default=None)),
|
|
@@ -66,6 +66,7 @@ class AzureSearchToolkit(BaseToolkit):
|
|
|
66
66
|
return m
|
|
67
67
|
|
|
68
68
|
@classmethod
|
|
69
|
+
@filter_missconfigured_index_tools
|
|
69
70
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
70
71
|
if selected_tools is None:
|
|
71
72
|
selected_tools = []
|
|
@@ -76,17 +77,21 @@ class AzureSearchToolkit(BaseToolkit):
|
|
|
76
77
|
}
|
|
77
78
|
azure_search_api_wrapper = AzureSearchApiWrapper(**wrapper_payload)
|
|
78
79
|
available_tools = azure_search_api_wrapper.get_available_tools()
|
|
79
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
80
80
|
tools = []
|
|
81
81
|
for tool in available_tools:
|
|
82
82
|
if selected_tools:
|
|
83
83
|
if tool["name"] not in selected_tools:
|
|
84
84
|
continue
|
|
85
|
+
description = tool["description"]
|
|
86
|
+
if toolkit_name:
|
|
87
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
88
|
+
description = description[:1000]
|
|
85
89
|
tools.append(BaseAction(
|
|
86
90
|
api_wrapper=azure_search_api_wrapper,
|
|
87
|
-
name=
|
|
88
|
-
description=
|
|
89
|
-
args_schema=tool["args_schema"]
|
|
91
|
+
name=tool["name"],
|
|
92
|
+
description=description,
|
|
93
|
+
args_schema=tool["args_schema"],
|
|
94
|
+
metadata={"toolkit_name": toolkit_name} if toolkit_name else {}
|
|
90
95
|
))
|
|
91
96
|
return cls(tools=tools)
|
|
92
97
|
|
alita_sdk/tools/base/tool.py
CHANGED
|
@@ -23,6 +23,10 @@ class BaseAction(BaseTool):
|
|
|
23
23
|
) -> ToolException | str:
|
|
24
24
|
"""Use the Confluence API to run an operation."""
|
|
25
25
|
try:
|
|
26
|
-
|
|
26
|
+
# Strip numeric suffix added for deduplication (_2, _3, etc.)
|
|
27
|
+
# to get the original tool name that exists in the wrapper
|
|
28
|
+
import re
|
|
29
|
+
tool_name = re.sub(r'_\d+$', '', self.name)
|
|
30
|
+
return self.api_wrapper.run(tool_name, *args, **kwargs)
|
|
27
31
|
except Exception as e:
|
|
28
32
|
return ToolException(f"An exception occurred: {e}")
|