alita-sdk 0.3.257__py3-none-any.whl → 0.3.584__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of alita-sdk might be problematic. Click here for more details.
- 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 +3794 -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 +323 -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 +493 -105
- alita_sdk/runtime/langchain/utils.py +118 -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 +25 -9
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +782 -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 +1032 -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/constants.py +5 -1
- 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 +16 -19
- alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
- alita_sdk/tools/ado/test_plan/__init__.py +27 -8
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
- alita_sdk/tools/ado/wiki/__init__.py +28 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
- alita_sdk/tools/ado/work_item/__init__.py +28 -12
- alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +13 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +15 -11
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +14 -8
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +454 -110
- alita_sdk/tools/bitbucket/__init__.py +28 -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 +12 -7
- alita_sdk/tools/cloud/azure/__init__.py +12 -7
- alita_sdk/tools/cloud/gcp/__init__.py +12 -7
- alita_sdk/tools/cloud/k8s/__init__.py +12 -7
- alita_sdk/tools/code/linter/__init__.py +10 -8
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +21 -13
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +22 -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 +12 -5
- alita_sdk/tools/elastic/__init__.py +11 -8
- alita_sdk/tools/elitea_base.py +546 -64
- alita_sdk/tools/figma/__init__.py +60 -11
- alita_sdk/tools/figma/api_wrapper.py +1400 -167
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +18 -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 +19 -13
- alita_sdk/tools/gitlab/api_wrapper.py +256 -80
- alita_sdk/tools/gitlab_org/__init__.py +14 -10
- alita_sdk/tools/google/bigquery/__init__.py +14 -13
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +21 -11
- alita_sdk/tools/jira/__init__.py +22 -11
- alita_sdk/tools/jira/api_wrapper.py +315 -168
- alita_sdk/tools/keycloak/__init__.py +11 -8
- alita_sdk/tools/localgit/__init__.py +9 -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 +11 -8
- alita_sdk/tools/openapi/__init__.py +491 -106
- alita_sdk/tools/openapi/api_wrapper.py +1357 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- 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 +11 -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 +11 -10
- alita_sdk/tools/qtest/__init__.py +22 -14
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +13 -10
- alita_sdk/tools/report_portal/__init__.py +23 -16
- alita_sdk/tools/salesforce/__init__.py +22 -16
- alita_sdk/tools/servicenow/__init__.py +21 -16
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +17 -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 +13 -8
- alita_sdk/tools/sql/__init__.py +22 -19
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +21 -13
- alita_sdk/tools/testrail/__init__.py +13 -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 +241 -55
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
- alita_sdk/tools/xray/__init__.py +18 -14
- alita_sdk/tools/xray/api_wrapper.py +58 -113
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +12 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +16 -9
- alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
- alita_sdk/tools/zephyr_essential/__init__.py +16 -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 +13 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
- alita_sdk/tools/zephyr_squad/__init__.py +12 -7
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/METADATA +184 -37
- alita_sdk-0.3.584.dist-info/RECORD +452 -0
- alita_sdk-0.3.584.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.584.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/top_level.txt +0 -0
alita_sdk/tools/sql/__init__.py
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
from typing import List, Literal, Optional
|
|
2
2
|
|
|
3
3
|
from langchain_core.tools import BaseToolkit, BaseTool
|
|
4
|
-
from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
4
|
+
from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
5
5
|
|
|
6
6
|
from .api_wrapper import SQLApiWrapper
|
|
7
7
|
from ..base.tool import BaseAction
|
|
8
8
|
from .models import SQLDialect
|
|
9
|
-
from ..
|
|
9
|
+
from ..elitea_base import filter_missconfigured_index_tools
|
|
10
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
11
|
+
from ...configurations.sql import SqlConfiguration
|
|
12
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
10
13
|
|
|
11
14
|
name = "sql"
|
|
12
15
|
|
|
@@ -14,32 +17,24 @@ def get_tools(tool):
|
|
|
14
17
|
return SQLToolkit().get_toolkit(
|
|
15
18
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
16
19
|
dialect=tool['settings']['dialect'],
|
|
17
|
-
host=tool['settings']['host'],
|
|
18
|
-
port=tool['settings']['port'],
|
|
19
|
-
username=tool['settings']['username'],
|
|
20
|
-
password=tool['settings']['password'],
|
|
21
20
|
database_name=tool['settings']['database_name'],
|
|
21
|
+
sql_configuration=tool['settings']['sql_configuration'],
|
|
22
22
|
toolkit_name=tool.get('toolkit_name')
|
|
23
23
|
).get_tools()
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class SQLToolkit(BaseToolkit):
|
|
27
27
|
tools: list[BaseTool] = []
|
|
28
|
-
toolkit_max_length: int = 0
|
|
29
28
|
|
|
30
29
|
@staticmethod
|
|
31
30
|
def toolkit_config_schema() -> BaseModel:
|
|
32
31
|
selected_tools = {x['name']: x['args_schema'].schema() for x in SQLApiWrapper.model_construct().get_available_tools()}
|
|
33
|
-
SQLToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
34
32
|
supported_dialects = (d.value for d in SQLDialect)
|
|
35
33
|
return create_model(
|
|
36
34
|
name,
|
|
37
35
|
dialect=(Literal[tuple(supported_dialects)], Field(description="Database dialect (mysql or postgres)")),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
username=(str, Field(description="Database username")),
|
|
41
|
-
password=(SecretStr, Field(description="Database password", json_schema_extra={'secret': True})),
|
|
42
|
-
database_name=(str, Field(description="Database name", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': SQLToolkit.toolkit_max_length})),
|
|
36
|
+
database_name=(str, Field(description="Database name")),
|
|
37
|
+
sql_configuration=(SqlConfiguration, Field(description="SQL Configuration", json_schema_extra={'configuration_types': ['sql']})),
|
|
43
38
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
44
39
|
__config__=ConfigDict(json_schema_extra=
|
|
45
40
|
{
|
|
@@ -51,24 +46,32 @@ class SQLToolkit(BaseToolkit):
|
|
|
51
46
|
)
|
|
52
47
|
|
|
53
48
|
@classmethod
|
|
49
|
+
@filter_missconfigured_index_tools
|
|
54
50
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
55
51
|
if selected_tools is None:
|
|
56
52
|
selected_tools = []
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
wrapper_payload = {
|
|
54
|
+
**kwargs,
|
|
55
|
+
**kwargs.get('sql_configuration', {}),
|
|
56
|
+
}
|
|
57
|
+
sql_api_wrapper = SQLApiWrapper(**wrapper_payload)
|
|
59
58
|
available_tools = sql_api_wrapper.get_available_tools()
|
|
60
59
|
tools = []
|
|
61
60
|
for tool in available_tools:
|
|
62
61
|
if selected_tools and tool["name"] not in selected_tools:
|
|
63
62
|
continue
|
|
63
|
+
description = f"{tool['description']}\nDatabase: {sql_api_wrapper.database_name}. Host: {sql_api_wrapper.host}"
|
|
64
|
+
if toolkit_name:
|
|
65
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
66
|
+
description = description[:1000]
|
|
64
67
|
tools.append(BaseAction(
|
|
65
68
|
api_wrapper=sql_api_wrapper,
|
|
66
|
-
name=
|
|
67
|
-
description=
|
|
68
|
-
args_schema=tool["args_schema"]
|
|
69
|
+
name=tool["name"],
|
|
70
|
+
description=description,
|
|
71
|
+
args_schema=tool["args_schema"],
|
|
72
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
69
73
|
))
|
|
70
74
|
return cls(tools=tools)
|
|
71
75
|
|
|
72
76
|
def get_tools(self) -> list[BaseTool]:
|
|
73
77
|
return self.tools
|
|
74
|
-
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from pydantic
|
|
4
|
+
from langchain_core.tools import ToolException
|
|
5
|
+
from pydantic import create_model, SecretStr, model_validator
|
|
6
|
+
from pydantic.fields import PrivateAttr, Field
|
|
6
7
|
from sqlalchemy import create_engine, text, inspect, Engine
|
|
7
8
|
from sqlalchemy.orm import sessionmaker
|
|
8
9
|
|
|
@@ -27,7 +28,7 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
27
28
|
username: str
|
|
28
29
|
password: SecretStr
|
|
29
30
|
database_name: str
|
|
30
|
-
_client: Optional[Engine] = PrivateAttr()
|
|
31
|
+
_client: Optional[Engine] = PrivateAttr(default=None)
|
|
31
32
|
|
|
32
33
|
@model_validator(mode='before')
|
|
33
34
|
@classmethod
|
|
@@ -35,27 +36,73 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
35
36
|
for field in SQLConfig.model_fields:
|
|
36
37
|
if field not in values or not values[field]:
|
|
37
38
|
raise ValueError(f"{field} is a required field and must be provided.")
|
|
38
|
-
|
|
39
|
-
dialect = values['dialect']
|
|
40
|
-
host = values['host']
|
|
41
|
-
username = values['username']
|
|
42
|
-
password = values['password']
|
|
43
|
-
database_name = values['database_name']
|
|
44
|
-
port = values['port']
|
|
45
|
-
|
|
46
|
-
if dialect == SQLDialect.POSTGRES:
|
|
47
|
-
connection_string = f'postgresql+psycopg2://{username}:{password}@{host}:{port}/{database_name}'
|
|
48
|
-
elif dialect == SQLDialect.MYSQL:
|
|
49
|
-
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database_name}'
|
|
50
|
-
else:
|
|
51
|
-
raise ValueError(f"Unsupported database type. Supported types are: {[e.value for e in SQLDialect]}")
|
|
52
|
-
|
|
53
|
-
cls._client = create_engine(connection_string)
|
|
54
39
|
return values
|
|
55
40
|
|
|
41
|
+
def _mask_password_in_error(self, error_message: str) -> str:
|
|
42
|
+
"""Mask password in error messages, showing only last 4 characters."""
|
|
43
|
+
password_str = self.password.get_secret_value()
|
|
44
|
+
if len(password_str) <= 4:
|
|
45
|
+
masked_password = "****"
|
|
46
|
+
else:
|
|
47
|
+
masked_password = "****" + password_str[-4:]
|
|
48
|
+
|
|
49
|
+
# Replace all occurrences of the password, and any substring of the password that may appear in the error message
|
|
50
|
+
for part in [password_str, password_str.replace('@', ''), password_str.split('@')[-1]]:
|
|
51
|
+
if part and part in error_message:
|
|
52
|
+
error_message = error_message.replace(part, masked_password)
|
|
53
|
+
return error_message
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def client(self) -> Engine:
|
|
57
|
+
"""Lazy property to create and return database engine with error handling."""
|
|
58
|
+
if self._client is None:
|
|
59
|
+
try:
|
|
60
|
+
dialect = self.dialect
|
|
61
|
+
host = self.host
|
|
62
|
+
username = self.username
|
|
63
|
+
password = self.password.get_secret_value()
|
|
64
|
+
database_name = self.database_name
|
|
65
|
+
port = self.port
|
|
66
|
+
|
|
67
|
+
if dialect == SQLDialect.POSTGRES:
|
|
68
|
+
connection_string = f'postgresql+psycopg2://{username}:{password}@{host}:{port}/{database_name}'
|
|
69
|
+
elif dialect == SQLDialect.MYSQL:
|
|
70
|
+
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database_name}'
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError(f"Unsupported database type. Supported types are: {[e.value for e in SQLDialect]}")
|
|
73
|
+
|
|
74
|
+
self._client = create_engine(connection_string)
|
|
75
|
+
|
|
76
|
+
# Test the connection
|
|
77
|
+
with self._client.connect() as conn:
|
|
78
|
+
conn.execute(text("SELECT 1"))
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
error_message = str(e)
|
|
82
|
+
masked_error = self._mask_password_in_error(error_message)
|
|
83
|
+
logger.error(f"Database connection failed: {masked_error}")
|
|
84
|
+
raise ValueError(f"Database connection failed: {masked_error}")
|
|
85
|
+
|
|
86
|
+
return self._client
|
|
87
|
+
|
|
88
|
+
def _handle_database_errors(func):
|
|
89
|
+
"""Decorator to catch exceptions and mask passwords in error messages."""
|
|
90
|
+
|
|
91
|
+
def wrapper(self, *args, **kwargs):
|
|
92
|
+
try:
|
|
93
|
+
return func(self, *args, **kwargs)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
error_message = str(e)
|
|
96
|
+
masked_error = self._mask_password_in_error(error_message)
|
|
97
|
+
logger.error(f"Database operation failed in {func.__name__}: {masked_error}")
|
|
98
|
+
raise ToolException(masked_error)
|
|
99
|
+
|
|
100
|
+
return wrapper
|
|
101
|
+
|
|
102
|
+
@_handle_database_errors
|
|
56
103
|
def execute_sql(self, sql_query: str):
|
|
57
104
|
"""Executes the provided SQL query on the configured database."""
|
|
58
|
-
engine = self.
|
|
105
|
+
engine = self.client
|
|
59
106
|
maker_session = sessionmaker(bind=engine)
|
|
60
107
|
session = maker_session()
|
|
61
108
|
try:
|
|
@@ -76,9 +123,10 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
76
123
|
finally:
|
|
77
124
|
session.close()
|
|
78
125
|
|
|
126
|
+
@_handle_database_errors
|
|
79
127
|
def list_tables_and_columns(self):
|
|
80
128
|
"""Lists all tables and their columns in the configured database."""
|
|
81
|
-
inspector = inspect(self.
|
|
129
|
+
inspector = inspect(self.client)
|
|
82
130
|
data = {}
|
|
83
131
|
tables = inspector.get_table_names()
|
|
84
132
|
for table in tables:
|
|
@@ -109,4 +157,4 @@ class SQLApiWrapper(BaseToolApiWrapper):
|
|
|
109
157
|
"description": self.list_tables_and_columns.__doc__,
|
|
110
158
|
"args_schema": SQLNoInput,
|
|
111
159
|
}
|
|
112
|
-
]
|
|
160
|
+
]
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
from typing import List, Literal, Optional
|
|
2
2
|
|
|
3
3
|
from langchain_core.tools import BaseToolkit, BaseTool
|
|
4
|
-
from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
4
|
+
from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
5
5
|
|
|
6
6
|
from .api_wrapper import TestIOApiWrapper
|
|
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
|
|
10
|
+
from ...configurations.testio import TestIOConfiguration
|
|
11
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
9
12
|
|
|
10
13
|
name = "testio"
|
|
11
14
|
|
|
12
15
|
def get_tools(tool):
|
|
13
16
|
return TestIOToolkit().get_toolkit(
|
|
14
17
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
15
|
-
|
|
16
|
-
api_key=tool['settings']['api_key'],
|
|
18
|
+
testio_configuration=tool['settings']['testio_configuration'],
|
|
17
19
|
toolkit_name=tool['toolkit_name']
|
|
18
20
|
).get_tools()
|
|
19
21
|
|
|
20
22
|
|
|
21
|
-
TOOLKIT_MAX_LENGTH = 25
|
|
22
|
-
|
|
23
23
|
class TestIOToolkit(BaseToolkit):
|
|
24
24
|
tools: list[BaseTool] = []
|
|
25
25
|
|
|
@@ -29,8 +29,7 @@ class TestIOToolkit(BaseToolkit):
|
|
|
29
29
|
selected_tools = {x['name']: x['args_schema'].schema() for x in TestIOApiWrapper.model_construct().get_available_tools()}
|
|
30
30
|
return create_model(
|
|
31
31
|
name,
|
|
32
|
-
|
|
33
|
-
api_key=(SecretStr, Field(description="API key", json_schema_extra={'secret': True})),
|
|
32
|
+
testio_configuration=(TestIOConfiguration, Field(description="TestIO Configuration", json_schema_extra={'configuration_types': ['testio']})),
|
|
34
33
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
35
34
|
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "TestIO", "icon_url": "testio-icon.svg",
|
|
36
35
|
"categories": ["testing"],
|
|
@@ -38,21 +37,30 @@ class TestIOToolkit(BaseToolkit):
|
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
@classmethod
|
|
40
|
+
@filter_missconfigured_index_tools
|
|
41
41
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
42
42
|
if selected_tools is None:
|
|
43
43
|
selected_tools = []
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
wrapper_payload = {
|
|
45
|
+
**kwargs,
|
|
46
|
+
**kwargs.get('testio_configuration', {}),
|
|
47
|
+
}
|
|
48
|
+
testio_api_wrapper = TestIOApiWrapper(**wrapper_payload)
|
|
46
49
|
available_tools = testio_api_wrapper.get_available_tools()
|
|
47
50
|
tools = []
|
|
48
51
|
for tool in available_tools:
|
|
49
52
|
if selected_tools and tool["name"] not in selected_tools:
|
|
50
53
|
continue
|
|
54
|
+
description = tool["description"]
|
|
55
|
+
if toolkit_name:
|
|
56
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
57
|
+
description = description[:1000]
|
|
51
58
|
tools.append(BaseAction(
|
|
52
59
|
api_wrapper=testio_api_wrapper,
|
|
53
|
-
name=
|
|
54
|
-
description=
|
|
55
|
-
args_schema=tool["args_schema"]
|
|
60
|
+
name=tool["name"],
|
|
61
|
+
description=description,
|
|
62
|
+
args_schema=tool["args_schema"],
|
|
63
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
56
64
|
))
|
|
57
65
|
return cls(tools=tools)
|
|
58
66
|
|
|
@@ -6,16 +6,17 @@ import requests
|
|
|
6
6
|
|
|
7
7
|
from .api_wrapper import TestrailAPIWrapper
|
|
8
8
|
from ..base.tool import BaseAction
|
|
9
|
-
from ..
|
|
9
|
+
from ..elitea_base import filter_missconfigured_index_tools
|
|
10
|
+
from ..utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
10
11
|
from ...configurations.testrail import TestRailConfiguration
|
|
11
12
|
from ...configurations.pgvector import PgVectorConfiguration
|
|
13
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
12
14
|
|
|
13
15
|
name = "testrail"
|
|
14
16
|
|
|
15
17
|
def get_tools(tool):
|
|
16
18
|
return TestrailToolkit().get_toolkit(
|
|
17
19
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
18
|
-
url=tool['settings']['url'],
|
|
19
20
|
testrail_configuration=tool['settings']['testrail_configuration'],
|
|
20
21
|
toolkit_name=tool.get('toolkit_name'),
|
|
21
22
|
llm=tool['settings'].get('llm', None),
|
|
@@ -31,17 +32,12 @@ def get_tools(tool):
|
|
|
31
32
|
|
|
32
33
|
class TestrailToolkit(BaseToolkit):
|
|
33
34
|
tools: List[BaseTool] = []
|
|
34
|
-
toolkit_max_length: int = 0
|
|
35
35
|
|
|
36
36
|
@staticmethod
|
|
37
37
|
def toolkit_config_schema() -> BaseModel:
|
|
38
38
|
selected_tools = {x['name']: x['args_schema'].schema() for x in TestrailAPIWrapper.model_construct().get_available_tools()}
|
|
39
|
-
TestrailToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
40
39
|
m = create_model(
|
|
41
40
|
name,
|
|
42
|
-
name=(str, Field(description="Toolkit name", json_schema_extra={
|
|
43
|
-
'toolkit_name': True,
|
|
44
|
-
"max_length": TestrailToolkit.toolkit_max_length})),
|
|
45
41
|
testrail_configuration=(Optional[TestRailConfiguration], Field(description="TestRail Configuration", json_schema_extra={'configuration_types': ['testrail']})),
|
|
46
42
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default = None,
|
|
47
43
|
description="PgVector Configuration", json_schema_extra={'configuration_types': ['pgvector']})),
|
|
@@ -68,6 +64,7 @@ class TestrailToolkit(BaseToolkit):
|
|
|
68
64
|
return m
|
|
69
65
|
|
|
70
66
|
@classmethod
|
|
67
|
+
@filter_missconfigured_index_tools
|
|
71
68
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
72
69
|
if selected_tools is None:
|
|
73
70
|
selected_tools = []
|
|
@@ -78,18 +75,23 @@ class TestrailToolkit(BaseToolkit):
|
|
|
78
75
|
**(kwargs.get('pgvector_configuration') or {}),
|
|
79
76
|
}
|
|
80
77
|
testrail_api_wrapper = TestrailAPIWrapper(**wrapper_payload)
|
|
81
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
82
78
|
available_tools = testrail_api_wrapper.get_available_tools()
|
|
83
79
|
tools = []
|
|
84
80
|
for tool in available_tools:
|
|
85
81
|
if selected_tools:
|
|
86
82
|
if tool["name"] not in selected_tools:
|
|
87
83
|
continue
|
|
84
|
+
description = tool["description"]
|
|
85
|
+
if toolkit_name:
|
|
86
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
87
|
+
description = description + "\nTestrail instance: " + testrail_api_wrapper.url
|
|
88
|
+
description = description[:1000]
|
|
88
89
|
tools.append(BaseAction(
|
|
89
90
|
api_wrapper=testrail_api_wrapper,
|
|
90
|
-
name=
|
|
91
|
-
description=
|
|
92
|
-
args_schema=tool["args_schema"]
|
|
91
|
+
name=tool["name"],
|
|
92
|
+
description=description,
|
|
93
|
+
args_schema=tool["args_schema"],
|
|
94
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
93
95
|
))
|
|
94
96
|
return cls(tools=tools)
|
|
95
97
|
|