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
|
@@ -3,23 +3,25 @@ from typing import Dict, List, Literal, Optional
|
|
|
3
3
|
from requests.auth import HTTPBasicAuth
|
|
4
4
|
|
|
5
5
|
from .api_wrapper import BitbucketAPIWrapper
|
|
6
|
-
from .tools import __all__
|
|
7
6
|
from langchain_core.tools import BaseToolkit
|
|
8
7
|
from langchain_core.tools import BaseTool
|
|
9
8
|
from pydantic import BaseModel, Field, ConfigDict, create_model
|
|
10
|
-
|
|
9
|
+
|
|
10
|
+
from ..base.tool import BaseAction
|
|
11
|
+
from ..elitea_base import filter_missconfigured_index_tools
|
|
12
|
+
from ..utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
11
13
|
from ...configurations.bitbucket import BitbucketConfiguration
|
|
12
14
|
from ...configurations.pgvector import PgVectorConfiguration
|
|
13
15
|
import requests
|
|
16
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
name = "bitbucket"
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
def
|
|
22
|
+
def get_toolkit(tool):
|
|
20
23
|
return AlitaBitbucketToolkit.get_toolkit(
|
|
21
24
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
22
|
-
url=tool['settings']['url'],
|
|
23
25
|
project=tool['settings']['project'],
|
|
24
26
|
repository=tool['settings']['repository'],
|
|
25
27
|
bitbucket_configuration=tool['settings']['bitbucket_configuration'],
|
|
@@ -32,27 +34,26 @@ def get_tools(tool):
|
|
|
32
34
|
doctype='code',
|
|
33
35
|
embedding_model=tool['settings'].get('embedding_model'),
|
|
34
36
|
toolkit_name=tool.get('toolkit_name')
|
|
35
|
-
)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def get_tools(tool):
|
|
40
|
+
return get_toolkit(tool).get_tools()
|
|
36
41
|
|
|
37
42
|
|
|
38
43
|
class AlitaBitbucketToolkit(BaseToolkit):
|
|
39
44
|
tools: List[BaseTool] = []
|
|
40
|
-
toolkit_max_length: int = 0
|
|
41
45
|
|
|
42
46
|
@staticmethod
|
|
43
47
|
def toolkit_config_schema() -> BaseModel:
|
|
44
|
-
selected_tools = {
|
|
45
|
-
|
|
46
|
-
default = t['tool'].__pydantic_fields__['args_schema'].default
|
|
47
|
-
selected_tools[t['name']] = default.schema() if default else default
|
|
48
|
-
AlitaBitbucketToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
48
|
+
selected_tools = {x['name']: x['args_schema'].schema() for x in
|
|
49
|
+
BitbucketAPIWrapper.model_construct().get_available_tools()}
|
|
49
50
|
m = create_model(
|
|
50
51
|
name,
|
|
51
|
-
project=(str, Field(description="Project/Workspace"
|
|
52
|
-
repository=(str, Field(description="Repository"
|
|
52
|
+
project=(str, Field(description="Project/Workspace")),
|
|
53
|
+
repository=(str, Field(description="Repository")),
|
|
53
54
|
branch=(str, Field(description="Main branch", default="main")),
|
|
54
55
|
cloud=(Optional[bool], Field(description="Hosting Option", default=None)),
|
|
55
|
-
bitbucket_configuration=(
|
|
56
|
+
bitbucket_configuration=(BitbucketConfiguration, Field(description="Bitbucket Configuration", json_schema_extra={'configuration_types': ['bitbucket']})),
|
|
56
57
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None, description="PgVector Configuration", json_schema_extra={'configuration_types': ['pgvector']})),
|
|
57
58
|
# embedder settings
|
|
58
59
|
embedding_model=(Optional[str], Field(default=None, description="Embedding configuration.", json_schema_extra={'configuration_model': 'embedding'})),
|
|
@@ -86,6 +87,7 @@ class AlitaBitbucketToolkit(BaseToolkit):
|
|
|
86
87
|
return m
|
|
87
88
|
|
|
88
89
|
@classmethod
|
|
90
|
+
@filter_missconfigured_index_tools
|
|
89
91
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
90
92
|
if selected_tools is None:
|
|
91
93
|
selected_tools = []
|
|
@@ -98,16 +100,23 @@ class AlitaBitbucketToolkit(BaseToolkit):
|
|
|
98
100
|
**(kwargs.get('pgvector_configuration') or {}),
|
|
99
101
|
}
|
|
100
102
|
bitbucket_api_wrapper = BitbucketAPIWrapper(**wrapper_payload)
|
|
101
|
-
available_tools: List[Dict] =
|
|
102
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
103
|
+
available_tools: List[Dict] = bitbucket_api_wrapper.get_available_tools()
|
|
103
104
|
tools = []
|
|
104
105
|
for tool in available_tools:
|
|
105
106
|
if selected_tools:
|
|
106
107
|
if tool['name'] not in selected_tools:
|
|
107
108
|
continue
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
description = tool["description"] + f"\nrepo: {bitbucket_api_wrapper.repository}"
|
|
110
|
+
if toolkit_name:
|
|
111
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
112
|
+
description = description[:1000]
|
|
113
|
+
tools.append(BaseAction(
|
|
114
|
+
api_wrapper=bitbucket_api_wrapper,
|
|
115
|
+
name=tool["name"],
|
|
116
|
+
description=description,
|
|
117
|
+
args_schema=tool["args_schema"],
|
|
118
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
119
|
+
))
|
|
111
120
|
return cls(tools=tools)
|
|
112
121
|
|
|
113
122
|
def get_tools(self):
|
|
@@ -2,28 +2,134 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
import fnmatch
|
|
6
7
|
|
|
7
8
|
from langchain_core.tools import ToolException
|
|
8
|
-
from pydantic import model_validator, SecretStr
|
|
9
|
+
from pydantic import model_validator, SecretStr, create_model, Field
|
|
9
10
|
from .bitbucket_constants import create_pr_data
|
|
10
11
|
from .cloud_api_wrapper import BitbucketCloudApi, BitbucketServerApi
|
|
11
12
|
from pydantic.fields import PrivateAttr
|
|
12
13
|
|
|
13
|
-
from ..
|
|
14
|
+
from ..code_indexer_toolkit import CodeIndexerToolkit
|
|
15
|
+
from ..utils.available_tools_decorator import extend_with_parent_available_tools
|
|
16
|
+
from ..elitea_base import extend_with_file_operations, BaseCodeToolApiWrapper
|
|
14
17
|
|
|
15
18
|
logger = logging.getLogger(__name__)
|
|
16
19
|
|
|
20
|
+
# Pydantic model definitions for tool arguments
|
|
21
|
+
CreateBranchModel = create_model(
|
|
22
|
+
"CreateBranchModel",
|
|
23
|
+
branch_name=(str, Field(description="The name of the branch, e.g. `my_branch`.")),
|
|
24
|
+
)
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
CreatePullRequestModel = create_model(
|
|
27
|
+
"CreatePullRequestModel",
|
|
28
|
+
pr_json_data=(str, Field(description=create_pr_data)),
|
|
29
|
+
)
|
|
20
30
|
|
|
31
|
+
CreateFileModel = create_model(
|
|
32
|
+
"CreateFileModel",
|
|
33
|
+
file_path=(str, Field(description="The path of the file")),
|
|
34
|
+
file_contents=(str, Field(description="The contents of the file")),
|
|
35
|
+
branch=(str, Field(description="The branch to create the file in")),
|
|
36
|
+
)
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
UpdateFileModel = create_model(
|
|
39
|
+
"UpdateFileModel",
|
|
40
|
+
file_path=(str, Field(description="The path of the file")),
|
|
41
|
+
update_query=(str, Field(description="Contains the file contents required to be updated. "
|
|
42
|
+
"The old file contents is wrapped in OLD <<<< and >>>> OLD. "
|
|
43
|
+
"The new file contents is wrapped in NEW <<<< and >>>> NEW")),
|
|
44
|
+
branch=(str, Field(description="The branch to update the file in")),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
ReadFileModel = create_model(
|
|
48
|
+
"ReadFileModel",
|
|
49
|
+
file_path=(str, Field(description="The path of the file")),
|
|
50
|
+
branch=(str, Field(description="The branch to read the file from")),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
SetActiveBranchModel = create_model(
|
|
54
|
+
"SetActiveBranchModel",
|
|
55
|
+
branch_name=(str, Field(description="The name of the branch, e.g. `my_branch`.")),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
ListBranchesInRepoModel = create_model(
|
|
59
|
+
"ListBranchesInRepoModel",
|
|
60
|
+
limit=(Optional[int], Field(default=20, description="Maximum number of branches to return. If not provided, all branches will be returned.")),
|
|
61
|
+
branch_wildcard=(Optional[str], Field(default=None, description="Wildcard pattern to filter branches by name. If not provided, all branches will be returned."))
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
ListFilesModel = create_model(
|
|
65
|
+
"ListFilesModel",
|
|
66
|
+
path=(Optional[str], Field(description="The path to list files from", default=None)),
|
|
67
|
+
recursive=(bool, Field(description="Whether to list files recursively", default=True)),
|
|
68
|
+
branch=(Optional[str], Field(description="The branch to list files from")),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
GetPullRequestsCommitsModel = create_model(
|
|
72
|
+
"GetPullRequestsCommitsModel",
|
|
73
|
+
pr_id=(str, Field(description="The ID of the pull request to get commits from")),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
GetPullRequestModel = create_model(
|
|
77
|
+
"GetPullRequestModel",
|
|
78
|
+
pr_id=(str, Field(description="The ID of the pull request to get details from")),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
GetPullRequestsChangesModel = create_model(
|
|
82
|
+
"GetPullRequestsChangesModel",
|
|
83
|
+
pr_id=(str, Field(description="The ID of the pull request to get changes from")),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
AddPullRequestCommentModel = create_model(
|
|
87
|
+
"AddPullRequestCommentModel",
|
|
88
|
+
pr_id=(str, Field(description="The ID of the pull request to add a comment to")),
|
|
89
|
+
content=(str, Field(description="The comment content")),
|
|
90
|
+
inline=(Optional[dict], Field(default=None, description="Inline comment details. Example: {'from': 57, 'to': 122, 'path': '<string>'}"))
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
DeleteFileModel = create_model(
|
|
94
|
+
"DeleteFileModel",
|
|
95
|
+
file_path=(str, Field(description="The path of the file")),
|
|
96
|
+
branch=(str, Field(description="The branch to delete the file from")),
|
|
97
|
+
commit_message=(str, Field(default=None, description="Commit message for deleting the file. Optional.")),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
AppendFileModel = create_model(
|
|
101
|
+
"AppendFileModel",
|
|
102
|
+
file_path=(str, Field(description="The path of the file")),
|
|
103
|
+
content=(str, Field(description="The content to append to the file")),
|
|
104
|
+
branch=(str, Field(description="The branch to append the file in")),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
GetIssuesModel = create_model(
|
|
108
|
+
"GetIssuesModel",
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
GetIssueModel = create_model(
|
|
112
|
+
"GetIssueModel",
|
|
113
|
+
issue_number=(int, Field(description="The number of the issue")),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
CommentOnIssueModel = create_model(
|
|
117
|
+
"CommentOnIssueModel",
|
|
118
|
+
comment_query=(str, Field(description="The comment query string")),
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class BitbucketAPIWrapper(CodeIndexerToolkit):
|
|
23
123
|
"""Wrapper for Bitbucket API."""
|
|
24
124
|
|
|
25
125
|
_bitbucket: Any = PrivateAttr()
|
|
26
126
|
_active_branch: Any = PrivateAttr()
|
|
127
|
+
|
|
128
|
+
# Import file operation methods from BaseCodeToolApiWrapper
|
|
129
|
+
read_file_chunk = BaseCodeToolApiWrapper.read_file_chunk
|
|
130
|
+
read_multiple_files = BaseCodeToolApiWrapper.read_multiple_files
|
|
131
|
+
search_file = BaseCodeToolApiWrapper.search_file
|
|
132
|
+
edit_file = BaseCodeToolApiWrapper.edit_file
|
|
27
133
|
url: str = ''
|
|
28
134
|
project: str = ''
|
|
29
135
|
"""The key of the project this repo belongs to"""
|
|
@@ -41,18 +147,6 @@ class BitbucketAPIWrapper(BaseCodeToolApiWrapper):
|
|
|
41
147
|
"""Bitbucket installation type: true for cloud, false for server.
|
|
42
148
|
"""
|
|
43
149
|
|
|
44
|
-
llm: Optional[Any] = None
|
|
45
|
-
# Alita instance
|
|
46
|
-
alita: Optional[Any] = None
|
|
47
|
-
|
|
48
|
-
# Vector store configuration
|
|
49
|
-
connection_string: Optional[SecretStr] = None
|
|
50
|
-
collection_name: Optional[str] = None
|
|
51
|
-
doctype: Optional[str] = 'code'
|
|
52
|
-
embedding_model: Optional[str] = "HuggingFaceEmbeddings"
|
|
53
|
-
embedding_model_params: Optional[Dict[str, Any]] = {"model_name": "sentence-transformers/all-MiniLM-L6-v2"}
|
|
54
|
-
vectorstore_type: Optional[str] = "PGVector"
|
|
55
|
-
|
|
56
150
|
@model_validator(mode='before')
|
|
57
151
|
@classmethod
|
|
58
152
|
def validate_env(cls, values: Dict) -> Dict:
|
|
@@ -81,16 +175,36 @@ class BitbucketAPIWrapper(BaseCodeToolApiWrapper):
|
|
|
81
175
|
repository=values['repository']
|
|
82
176
|
)
|
|
83
177
|
cls._active_branch = values.get('branch')
|
|
84
|
-
return values
|
|
178
|
+
return super().validate_toolkit(values)
|
|
85
179
|
|
|
86
|
-
def set_active_branch(self,
|
|
180
|
+
def set_active_branch(self, branch_name: str) -> str:
|
|
87
181
|
"""Set the active branch for the bot."""
|
|
88
|
-
self._active_branch =
|
|
89
|
-
return f"Active branch set to `{
|
|
182
|
+
self._active_branch = branch_name
|
|
183
|
+
return f"Active branch set to `{branch_name}`"
|
|
184
|
+
|
|
185
|
+
def list_branches_in_repo(self, limit: Optional[int] = 20, branch_wildcard: Optional[str] = None) -> List[str]:
|
|
186
|
+
"""
|
|
187
|
+
Lists branches in the repository with optional limit and wildcard filtering.
|
|
188
|
+
|
|
189
|
+
Parameters:
|
|
190
|
+
limit (Optional[int]): Maximum number of branches to return
|
|
191
|
+
branch_wildcard (Optional[str]): Wildcard pattern to filter branches (e.g., '*dev')
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
List[str]: List containing names of branches
|
|
195
|
+
"""
|
|
196
|
+
try:
|
|
197
|
+
branches = self._bitbucket.list_branches()
|
|
198
|
+
|
|
199
|
+
if branch_wildcard:
|
|
200
|
+
branches = [branch for branch in branches if fnmatch.fnmatch(branch, branch_wildcard)]
|
|
90
201
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
202
|
+
if limit is not None:
|
|
203
|
+
branches = branches[:limit]
|
|
204
|
+
|
|
205
|
+
return "Found branches: " + ", ".join(branches)
|
|
206
|
+
except Exception as e:
|
|
207
|
+
return f"Failed to list branches: {str(e)}"
|
|
94
208
|
|
|
95
209
|
def create_branch(self, branch_name: str) -> None:
|
|
96
210
|
"""Create a new branch in the repository."""
|
|
@@ -253,12 +367,15 @@ class BitbucketAPIWrapper(BaseCodeToolApiWrapper):
|
|
|
253
367
|
# except Exception as e:
|
|
254
368
|
# raise ToolException(f"Can't extract file commit hash (`{file_path}`) due to error:\n{str(e)}")
|
|
255
369
|
|
|
256
|
-
def _read_file(self, file_path: str, branch: str) -> str:
|
|
370
|
+
def _read_file(self, file_path: str, branch: str, **kwargs) -> str:
|
|
257
371
|
"""
|
|
258
|
-
Reads a file from the
|
|
372
|
+
Reads a file from the bitbucket repo with optional partial read support.
|
|
373
|
+
|
|
259
374
|
Parameters:
|
|
260
375
|
file_path(str): the file path
|
|
261
376
|
branch(str): branch name (by default: active_branch)
|
|
377
|
+
**kwargs: Additional parameters (offset, limit, head, tail) - currently ignored,
|
|
378
|
+
partial read handled client-side by base class methods
|
|
262
379
|
Returns:
|
|
263
380
|
str: The file decoded as a string
|
|
264
381
|
"""
|
|
@@ -266,3 +383,144 @@ class BitbucketAPIWrapper(BaseCodeToolApiWrapper):
|
|
|
266
383
|
return self._bitbucket.get_file(file_path=file_path, branch=branch)
|
|
267
384
|
except Exception as e:
|
|
268
385
|
raise ToolException(f"Can't extract file content (`{file_path}`) due to error:\n{str(e)}")
|
|
386
|
+
|
|
387
|
+
def list_files(self, path: str = None, recursive: bool = True, branch: str = None) -> List[str]:
|
|
388
|
+
"""List files in the repository with optional path, recursive search, and branch."""
|
|
389
|
+
branch = branch if branch else self._active_branch
|
|
390
|
+
try:
|
|
391
|
+
files_str = self._get_files(path, branch)
|
|
392
|
+
# Parse the string response to extract file paths
|
|
393
|
+
# This is a simplified implementation - might need adjustment based on actual response format
|
|
394
|
+
import ast
|
|
395
|
+
try:
|
|
396
|
+
files_list = ast.literal_eval(files_str)
|
|
397
|
+
if isinstance(files_list, list):
|
|
398
|
+
return files_list
|
|
399
|
+
else:
|
|
400
|
+
return [str(files_list)]
|
|
401
|
+
except:
|
|
402
|
+
return [files_str] if files_str else []
|
|
403
|
+
except Exception as e:
|
|
404
|
+
return f"Failed to list files: {str(e)}"
|
|
405
|
+
|
|
406
|
+
def read_file(self, file_path: str, branch: str) -> str:
|
|
407
|
+
"""Read the contents of a file in the repository."""
|
|
408
|
+
try:
|
|
409
|
+
return self._read_file(file_path, branch)
|
|
410
|
+
except Exception as e:
|
|
411
|
+
return f"Failed to read file {file_path}: {str(e)}"
|
|
412
|
+
|
|
413
|
+
def _write_file(
|
|
414
|
+
self,
|
|
415
|
+
file_path: str,
|
|
416
|
+
content: str,
|
|
417
|
+
branch: str = None,
|
|
418
|
+
commit_message: str = None
|
|
419
|
+
) -> str:
|
|
420
|
+
"""
|
|
421
|
+
Write content to a file (create or update).
|
|
422
|
+
|
|
423
|
+
Parameters:
|
|
424
|
+
file_path: Path to the file
|
|
425
|
+
content: New file content
|
|
426
|
+
branch: Branch name (uses active branch if None)
|
|
427
|
+
commit_message: Commit message (not used by Bitbucket API)
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
Success message
|
|
431
|
+
"""
|
|
432
|
+
try:
|
|
433
|
+
branch = branch or self._active_branch
|
|
434
|
+
|
|
435
|
+
# Check if file exists by attempting to read it
|
|
436
|
+
try:
|
|
437
|
+
self._read_file(file_path, branch)
|
|
438
|
+
# File exists, update it using OLD/NEW format
|
|
439
|
+
old_content = self._read_file(file_path, branch)
|
|
440
|
+
update_query = f"OLD <<<<\n{old_content}\n>>>> OLD\nNEW <<<<\n{content}\n>>>> NEW"
|
|
441
|
+
self._bitbucket.update_file(file_path=file_path, update_query=update_query, branch=branch)
|
|
442
|
+
return f"Updated file {file_path}"
|
|
443
|
+
except:
|
|
444
|
+
# File doesn't exist, create it
|
|
445
|
+
self._bitbucket.create_file(file_path=file_path, file_contents=content, branch=branch)
|
|
446
|
+
return f"Created file {file_path}"
|
|
447
|
+
except Exception as e:
|
|
448
|
+
raise ToolException(f"Unable to write file {file_path}: {str(e)}")
|
|
449
|
+
|
|
450
|
+
@extend_with_parent_available_tools
|
|
451
|
+
@extend_with_file_operations
|
|
452
|
+
def get_available_tools(self):
|
|
453
|
+
return [
|
|
454
|
+
{
|
|
455
|
+
"name": "create_branch",
|
|
456
|
+
"ref": self.create_branch,
|
|
457
|
+
"description": self.create_branch.__doc__ or "Create a new branch in the repository.",
|
|
458
|
+
"args_schema": CreateBranchModel,
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
"name": "list_branches_in_repo",
|
|
462
|
+
"ref": self.list_branches_in_repo,
|
|
463
|
+
"description": self.list_branches_in_repo.__doc__ or "List branches in the repository with optional limit and wildcard filtering.",
|
|
464
|
+
"args_schema": ListBranchesInRepoModel,
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"name": "list_files",
|
|
468
|
+
"ref": self.list_files,
|
|
469
|
+
"description": self.list_files.__doc__ or "List files in the repository with optional path, recursive search, and branch.",
|
|
470
|
+
"args_schema": ListFilesModel,
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
"name": "create_pull_request",
|
|
474
|
+
"ref": self.create_pull_request,
|
|
475
|
+
"description": self.create_pull_request.__doc__ or "Create a pull request in the repository.",
|
|
476
|
+
"args_schema": CreatePullRequestModel,
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
"name": "create_file",
|
|
480
|
+
"ref": self.create_file,
|
|
481
|
+
"description": self.create_file.__doc__ or "Create a new file in the repository.",
|
|
482
|
+
"args_schema": CreateFileModel,
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"name": "read_file",
|
|
486
|
+
"ref": self.read_file,
|
|
487
|
+
"description": self.read_file.__doc__ or "Read the contents of a file in the repository.",
|
|
488
|
+
"args_schema": ReadFileModel,
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"name": "update_file",
|
|
492
|
+
"ref": self.update_file,
|
|
493
|
+
"description": self.update_file.__doc__ or "Update the contents of a file in the repository.",
|
|
494
|
+
"args_schema": UpdateFileModel,
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
"name": "set_active_branch",
|
|
498
|
+
"ref": self.set_active_branch,
|
|
499
|
+
"description": self.set_active_branch.__doc__ or "Set the active branch in the repository.",
|
|
500
|
+
"args_schema": SetActiveBranchModel,
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"name": "get_pull_requests_commits",
|
|
504
|
+
"ref": self.get_pull_requests_commits,
|
|
505
|
+
"description": self.get_pull_requests_commits.__doc__ or "Get commits from a pull request in the repository.",
|
|
506
|
+
"args_schema": GetPullRequestsCommitsModel,
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"name": "get_pull_request",
|
|
510
|
+
"ref": self.get_pull_request,
|
|
511
|
+
"description": self.get_pull_request.__doc__ or "Get details of a pull request in the repository.",
|
|
512
|
+
"args_schema": GetPullRequestModel,
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
"name": "get_pull_requests_changes",
|
|
516
|
+
"ref": self.get_pull_requests_changes,
|
|
517
|
+
"description": self.get_pull_requests_changes.__doc__ or "Get changes from a pull request in the repository.",
|
|
518
|
+
"args_schema": GetPullRequestsChangesModel,
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"name": "add_pull_request_comment",
|
|
522
|
+
"ref": self.add_pull_request_comment,
|
|
523
|
+
"description": self.add_pull_request_comment.__doc__ or "Add a comment to a pull request in the repository.",
|
|
524
|
+
"args_schema": AddPullRequestCommentModel,
|
|
525
|
+
}
|
|
526
|
+
]
|
|
@@ -35,7 +35,7 @@ def normalize_response(response) -> Dict[str, Any]:
|
|
|
35
35
|
class BitbucketApiAbstract(ABC):
|
|
36
36
|
|
|
37
37
|
@abstractmethod
|
|
38
|
-
def list_branches(self) -> str:
|
|
38
|
+
def list_branches(self) -> List[str]:
|
|
39
39
|
pass
|
|
40
40
|
|
|
41
41
|
@abstractmethod
|
|
@@ -86,9 +86,9 @@ class BitbucketServerApi(BitbucketApiAbstract):
|
|
|
86
86
|
self.password = password
|
|
87
87
|
self.api_client = Bitbucket(url=url, username=username, password=password)
|
|
88
88
|
|
|
89
|
-
def list_branches(self) -> str:
|
|
89
|
+
def list_branches(self) -> List[str]:
|
|
90
90
|
branches = self.api_client.get_branches(project_key=self.project, repository_slug=self.repository)
|
|
91
|
-
return
|
|
91
|
+
return [branch['displayId'] for branch in branches]
|
|
92
92
|
|
|
93
93
|
def create_branch(self, branch_name: str, branch_from: str) -> Response:
|
|
94
94
|
return self.api_client.create_branch(
|
|
@@ -257,10 +257,10 @@ class BitbucketCloudApi(BitbucketApiAbstract):
|
|
|
257
257
|
except Exception as e:
|
|
258
258
|
raise ToolException(f"Unable to connect to the repository '{self.repository_name}' due to error:\n{str(e)}")
|
|
259
259
|
|
|
260
|
-
def list_branches(self) -> str:
|
|
260
|
+
def list_branches(self) -> List[str]:
|
|
261
261
|
branches = self.repository.branches.each()
|
|
262
262
|
branch_names = [branch.name for branch in branches]
|
|
263
|
-
return
|
|
263
|
+
return branch_names
|
|
264
264
|
|
|
265
265
|
def _get_branch(self, branch_name: str) -> Response:
|
|
266
266
|
return self.repository.branches.get(branch_name)
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
from typing import List, Optional, Literal
|
|
2
2
|
from langchain_core.tools import BaseTool, BaseToolkit
|
|
3
3
|
|
|
4
|
-
from pydantic import create_model, BaseModel, ConfigDict, Field,
|
|
4
|
+
from pydantic import create_model, BaseModel, ConfigDict, Field, model_validator
|
|
5
5
|
|
|
6
6
|
from langchain_community.utilities.google_search import GoogleSearchAPIWrapper
|
|
7
7
|
from langchain_community.utilities.wikipedia import WikipediaAPIWrapper
|
|
8
8
|
from .google_search_rag import GoogleSearchResults
|
|
9
9
|
from .crawler import SingleURLCrawler, MultiURLCrawler, GetHTMLContent, GetPDFContent
|
|
10
10
|
from .wiki import WikipediaQueryRun
|
|
11
|
-
from ..utils import get_max_toolkit_length, clean_string
|
|
11
|
+
from ..utils import get_max_toolkit_length, clean_string
|
|
12
|
+
from ...configurations.browser import BrowserConfiguration
|
|
12
13
|
from logging import getLogger
|
|
13
14
|
|
|
15
|
+
from ...configurations.pgvector import PgVectorConfiguration
|
|
16
|
+
|
|
14
17
|
logger = getLogger(__name__)
|
|
15
18
|
|
|
16
19
|
name = "browser"
|
|
@@ -19,8 +22,9 @@ name = "browser"
|
|
|
19
22
|
def get_tools(tool):
|
|
20
23
|
return BrowserToolkit().get_toolkit(
|
|
21
24
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
browser_configuration=tool['settings']['browser_configuration'],
|
|
26
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
27
|
+
embedding_model=tool['settings'].get('embedding_model'),
|
|
24
28
|
toolkit_name=tool.get('toolkit_name', '')
|
|
25
29
|
).get_tools()
|
|
26
30
|
|
|
@@ -38,22 +42,29 @@ class BrowserToolkit(BaseToolkit):
|
|
|
38
42
|
'google': GoogleSearchResults.__pydantic_fields__['args_schema'].default.schema(),
|
|
39
43
|
'wiki': WikipediaQueryRun.__pydantic_fields__['args_schema'].default.schema()
|
|
40
44
|
}
|
|
41
|
-
BrowserToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
42
45
|
|
|
43
46
|
def validate_google_fields(cls, values):
|
|
44
47
|
if 'google' in values.get('selected_tools', []):
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
browser_config = values.get('browser_configuration', {})
|
|
49
|
+
google_cse_id = browser_config.get('google_cse_id') is not None if browser_config else False
|
|
50
|
+
google_api_key = browser_config.get('google_api_key') is not None if browser_config else False
|
|
47
51
|
if not (google_cse_id and google_api_key):
|
|
48
52
|
raise ValueError("google_cse_id and google_api_key are required when 'google' is in selected_tools")
|
|
49
53
|
return values
|
|
50
54
|
|
|
51
55
|
return create_model(
|
|
52
56
|
name,
|
|
53
|
-
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Browser", "icon_url": None,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Browser", "icon_url": None,
|
|
58
|
+
"categories": ["testing"],
|
|
59
|
+
"extra_categories": [
|
|
60
|
+
"web scraping", "search", "crawler"
|
|
61
|
+
]}}),
|
|
62
|
+
browser_configuration=(Optional[BrowserConfiguration],
|
|
63
|
+
Field(description="Browser Configuration (required for tools and `google`)",
|
|
64
|
+
default=None, json_schema_extra={'configuration_types': ['browser']})),
|
|
65
|
+
pgvector_configuration=(Optional[PgVectorConfiguration],
|
|
66
|
+
Field(description="PgVector configuration (required for tools `multi_url_crawler`)",
|
|
67
|
+
default=None, json_schema_extra={'configuration_types': ['pgvector']})),
|
|
57
68
|
selected_tools=(List[Literal[tuple(selected_tools)]],
|
|
58
69
|
Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
59
70
|
__validators__={
|
|
@@ -65,8 +76,19 @@ class BrowserToolkit(BaseToolkit):
|
|
|
65
76
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
66
77
|
if selected_tools is None:
|
|
67
78
|
selected_tools = []
|
|
79
|
+
|
|
80
|
+
wrapper_payload_google = {
|
|
81
|
+
**kwargs,
|
|
82
|
+
**kwargs.get('browser_configuration', {}),
|
|
83
|
+
**kwargs.get('pgvector_configuration', {}),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
wrapper_payload_rag_based = {
|
|
87
|
+
**kwargs,
|
|
88
|
+
**kwargs.get('pgvector_configuration', {}),
|
|
89
|
+
}
|
|
90
|
+
|
|
68
91
|
tools = []
|
|
69
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
70
92
|
if not selected_tools:
|
|
71
93
|
selected_tools = [
|
|
72
94
|
'single_url_crawler',
|
|
@@ -80,7 +102,7 @@ class BrowserToolkit(BaseToolkit):
|
|
|
80
102
|
if tool == 'single_url_crawler':
|
|
81
103
|
tool_entry = SingleURLCrawler()
|
|
82
104
|
elif tool == 'multi_url_crawler':
|
|
83
|
-
tool_entry = MultiURLCrawler()
|
|
105
|
+
tool_entry = MultiURLCrawler(**wrapper_payload_rag_based)
|
|
84
106
|
elif tool == 'get_html_content':
|
|
85
107
|
tool_entry = GetHTMLContent()
|
|
86
108
|
elif tool == 'get_pdf_content':
|
|
@@ -88,8 +110,8 @@ class BrowserToolkit(BaseToolkit):
|
|
|
88
110
|
elif tool == 'google':
|
|
89
111
|
try:
|
|
90
112
|
google_api_wrapper = GoogleSearchAPIWrapper(
|
|
91
|
-
google_api_key=
|
|
92
|
-
google_cse_id=
|
|
113
|
+
google_api_key=wrapper_payload_google.get('google_api_key'),
|
|
114
|
+
google_cse_id=wrapper_payload_google.get('google_cse_id')
|
|
93
115
|
)
|
|
94
116
|
tool_entry = GoogleSearchResults(api_wrapper=google_api_wrapper)
|
|
95
117
|
# rename the tool to avoid conflicts
|
|
@@ -103,7 +125,10 @@ class BrowserToolkit(BaseToolkit):
|
|
|
103
125
|
|
|
104
126
|
# Only add the tool if it was successfully created
|
|
105
127
|
if tool_entry is not None:
|
|
106
|
-
|
|
128
|
+
if toolkit_name:
|
|
129
|
+
tool_entry.description = f"{tool_entry.description}\nToolkit: {toolkit_name}"
|
|
130
|
+
tool_entry.description = tool_entry.description[:1000]
|
|
131
|
+
tool_entry.metadata = {"toolkit_name": toolkit_name, "toolkit_type": name}
|
|
107
132
|
tools.append(tool_entry)
|
|
108
133
|
return cls(tools=tools)
|
|
109
134
|
|
|
@@ -27,13 +27,15 @@ class MultiURLCrawler(BaseTool):
|
|
|
27
27
|
max_response_size: int = 3000
|
|
28
28
|
name: str = "multi_url_crawler"
|
|
29
29
|
description: str = "Crawls multiple URLs and returns the content related to query"
|
|
30
|
+
connection_string: str = None
|
|
30
31
|
args_schema: Type[BaseModel] = create_model("MultiURLCrawlerModel",
|
|
31
32
|
query=(str, Field(description="Query text to search pages")),
|
|
32
33
|
urls=(list[str], Field(description="list of URLs to search like ['url1', 'url2']")))
|
|
33
34
|
|
|
34
35
|
def _run(self, query: str, urls: list[str], run_manager=None):
|
|
35
36
|
urls = [url.strip() for url in urls]
|
|
36
|
-
return webRag(urls, self.max_response_size, query
|
|
37
|
+
return webRag(urls=urls, max_response_size=self.max_response_size, query=query,
|
|
38
|
+
connection_string=self.connection_string)
|
|
37
39
|
|
|
38
40
|
|
|
39
41
|
class GetHTMLContent(BaseTool):
|