alita-sdk 0.3.379__py3-none-any.whl → 0.3.627__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +156 -0
- alita_sdk/cli/agent_loader.py +245 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3113 -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/testcases/__init__.py +94 -0
- alita_sdk/cli/testcases/data_generation.py +119 -0
- alita_sdk/cli/testcases/discovery.py +96 -0
- alita_sdk/cli/testcases/executor.py +84 -0
- alita_sdk/cli/testcases/logger.py +85 -0
- alita_sdk/cli/testcases/parser.py +172 -0
- alita_sdk/cli/testcases/prompts.py +91 -0
- alita_sdk/cli/testcases/reporting.py +125 -0
- alita_sdk/cli/testcases/setup.py +108 -0
- alita_sdk/cli/testcases/test_runner.py +282 -0
- alita_sdk/cli/testcases/utils.py +39 -0
- alita_sdk/cli/testcases/validation.py +90 -0
- alita_sdk/cli/testcases/workflow.py +196 -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 +1 -1
- alita_sdk/configurations/ado.py +141 -20
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/confluence.py +130 -1
- alita_sdk/configurations/figma.py +76 -0
- alita_sdk/configurations/gitlab.py +91 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/openapi.py +329 -0
- alita_sdk/configurations/qtest.py +72 -1
- alita_sdk/configurations/report_portal.py +96 -0
- alita_sdk/configurations/sharepoint.py +148 -0
- alita_sdk/configurations/testio.py +83 -0
- alita_sdk/configurations/testrail.py +88 -0
- alita_sdk/configurations/xray.py +93 -0
- alita_sdk/configurations/zephyr_enterprise.py +93 -0
- alita_sdk/configurations/zephyr_essential.py +75 -0
- alita_sdk/runtime/clients/artifact.py +3 -3
- alita_sdk/runtime/clients/client.py +388 -46
- 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 +8 -21
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +157 -39
- 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 +103 -60
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -4
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
- alita_sdk/runtime/langchain/document_loaders/constants.py +40 -19
- alita_sdk/runtime/langchain/langraph_agent.py +405 -84
- alita_sdk/runtime/langchain/utils.py +106 -7
- 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 +31 -0
- alita_sdk/runtime/toolkits/application.py +29 -10
- alita_sdk/runtime/toolkits/artifact.py +20 -11
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +783 -0
- alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +251 -6
- alita_sdk/runtime/toolkits/tools.py +356 -69
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +10 -3
- alita_sdk/runtime/tools/application.py +27 -6
- alita_sdk/runtime/tools/artifact.py +511 -28
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +67 -35
- alita_sdk/runtime/tools/graph.py +10 -4
- alita_sdk/runtime/tools/image_generation.py +148 -46
- alita_sdk/runtime/tools/llm.py +1003 -128
- 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 +8 -5
- 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 -4
- alita_sdk/runtime/tools/sandbox.py +65 -48
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +9 -3
- alita_sdk/runtime/tools/vectorstore_base.py +70 -14
- 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/serialization.py +155 -0
- alita_sdk/runtime/utils/streamlit.py +40 -13
- alita_sdk/runtime/utils/toolkit_utils.py +30 -9
- alita_sdk/runtime/utils/utils.py +36 -0
- alita_sdk/tools/__init__.py +134 -35
- alita_sdk/tools/ado/repos/__init__.py +51 -32
- alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
- alita_sdk/tools/ado/test_plan/__init__.py +25 -9
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
- alita_sdk/tools/ado/utils.py +1 -18
- alita_sdk/tools/ado/wiki/__init__.py +25 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
- alita_sdk/tools/ado/work_item/__init__.py +26 -13
- alita_sdk/tools/ado/work_item/ado_wrapper.py +73 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +11 -8
- alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +271 -84
- alita_sdk/tools/bitbucket/__init__.py +17 -11
- alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
- alita_sdk/tools/browser/__init__.py +5 -4
- alita_sdk/tools/carrier/__init__.py +5 -6
- alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
- alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
- alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
- alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
- 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 +10 -7
- alita_sdk/tools/cloud/azure/__init__.py +10 -7
- alita_sdk/tools/cloud/gcp/__init__.py +10 -7
- alita_sdk/tools/cloud/k8s/__init__.py +10 -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 +11 -8
- alita_sdk/tools/code_indexer_toolkit.py +82 -22
- alita_sdk/tools/confluence/__init__.py +22 -16
- alita_sdk/tools/confluence/api_wrapper.py +107 -30
- 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 +493 -30
- alita_sdk/tools/figma/__init__.py +58 -11
- alita_sdk/tools/figma/api_wrapper.py +1235 -143
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +14 -15
- alita_sdk/tools/github/github_client.py +224 -100
- alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
- alita_sdk/tools/github/schemas.py +14 -5
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/github/tool_prompts.py +9 -22
- alita_sdk/tools/gitlab/__init__.py +16 -11
- alita_sdk/tools/gitlab/api_wrapper.py +218 -48
- alita_sdk/tools/gitlab_org/__init__.py +10 -9
- alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
- alita_sdk/tools/google/bigquery/__init__.py +13 -12
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +11 -8
- alita_sdk/tools/google_places/api_wrapper.py +1 -1
- alita_sdk/tools/jira/__init__.py +17 -10
- alita_sdk/tools/jira/api_wrapper.py +92 -41
- 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 +12 -4
- alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +491 -106
- alita_sdk/tools/openapi/api_wrapper.py +1368 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- alita_sdk/tools/pandas/api_wrapper.py +38 -25
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +10 -9
- alita_sdk/tools/pptx/__init__.py +11 -10
- alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
- alita_sdk/tools/qtest/__init__.py +31 -11
- alita_sdk/tools/qtest/api_wrapper.py +2135 -86
- alita_sdk/tools/rally/__init__.py +10 -9
- alita_sdk/tools/rally/api_wrapper.py +1 -1
- alita_sdk/tools/report_portal/__init__.py +12 -8
- alita_sdk/tools/salesforce/__init__.py +10 -8
- alita_sdk/tools/servicenow/__init__.py +17 -15
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +10 -7
- alita_sdk/tools/sharepoint/api_wrapper.py +129 -38
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +10 -7
- alita_sdk/tools/slack/api_wrapper.py +2 -2
- alita_sdk/tools/sql/__init__.py +12 -9
- alita_sdk/tools/testio/__init__.py +10 -7
- alita_sdk/tools/testrail/__init__.py +11 -10
- alita_sdk/tools/testrail/api_wrapper.py +1 -1
- alita_sdk/tools/utils/__init__.py +9 -4
- alita_sdk/tools/utils/content_parser.py +103 -18
- alita_sdk/tools/utils/text_operations.py +410 -0
- alita_sdk/tools/utils/tool_prompts.py +79 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +30 -13
- alita_sdk/tools/xray/__init__.py +13 -9
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +10 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +11 -7
- alita_sdk/tools/zephyr_essential/__init__.py +10 -7
- alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
- alita_sdk/tools/zephyr_essential/client.py +2 -2
- alita_sdk/tools/zephyr_scale/__init__.py +11 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
- alita_sdk/tools/zephyr_squad/__init__.py +10 -7
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +154 -8
- alita_sdk-0.3.627.dist-info/RECORD +468 -0
- alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
- alita_sdk-0.3.379.dist-info/RECORD +0 -360
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.379.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
|
@@ -7,13 +7,14 @@ from .api_wrapper import AlitaGitHubAPIWrapper
|
|
|
7
7
|
from .tool import GitHubAction
|
|
8
8
|
from ..elitea_base import filter_missconfigured_index_tools
|
|
9
9
|
|
|
10
|
-
from ..utils import clean_string,
|
|
10
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
11
11
|
from ...configurations.github import GithubConfiguration
|
|
12
12
|
from ...configurations.pgvector import PgVectorConfiguration
|
|
13
|
+
from ...runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
13
14
|
|
|
14
15
|
name = "github"
|
|
15
16
|
|
|
16
|
-
def
|
|
17
|
+
def get_toolkit(tool) -> BaseToolkit:
|
|
17
18
|
return AlitaGitHubToolkit().get_toolkit(
|
|
18
19
|
selected_tools=tool['settings'].get('selected_tools', []),
|
|
19
20
|
github_base_url=tool['settings'].get('base_url', ''),
|
|
@@ -31,21 +32,16 @@ def _get_toolkit(tool) -> BaseToolkit:
|
|
|
31
32
|
toolkit_name=tool.get('toolkit_name')
|
|
32
33
|
)
|
|
33
34
|
|
|
34
|
-
def get_toolkit():
|
|
35
|
-
return AlitaGitHubToolkit.toolkit_config_schema()
|
|
36
|
-
|
|
37
35
|
def get_tools(tool):
|
|
38
|
-
return
|
|
36
|
+
return get_toolkit(tool).get_tools()
|
|
39
37
|
|
|
40
38
|
class AlitaGitHubToolkit(BaseToolkit):
|
|
41
39
|
tools: List[BaseTool] = []
|
|
42
|
-
toolkit_max_length: int = 0
|
|
43
40
|
|
|
44
41
|
@staticmethod
|
|
45
42
|
def toolkit_config_schema() -> BaseModel:
|
|
46
43
|
selected_tools = {x['name']: x['args_schema'].schema() for x in
|
|
47
44
|
AlitaGitHubAPIWrapper.model_construct().get_available_tools()}
|
|
48
|
-
AlitaGitHubToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
49
45
|
return create_model(
|
|
50
46
|
name,
|
|
51
47
|
__config__=ConfigDict(
|
|
@@ -62,8 +58,7 @@ class AlitaGitHubToolkit(BaseToolkit):
|
|
|
62
58
|
json_schema_extra={'configuration_types': ['github']})),
|
|
63
59
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(description="PgVector configuration", default=None,
|
|
64
60
|
json_schema_extra={'configuration_types': ['pgvector']})),
|
|
65
|
-
repository=(str, Field(description="Github repository",
|
|
66
|
-
'max_toolkit_length': AlitaGitHubToolkit.toolkit_max_length})),
|
|
61
|
+
repository=(str, Field(description="Github repository")),
|
|
67
62
|
active_branch=(Optional[str], Field(description="Active branch", default="main")),
|
|
68
63
|
base_branch=(Optional[str], Field(description="Github Base branch", default="main")),
|
|
69
64
|
# embedder settings
|
|
@@ -87,18 +82,22 @@ class AlitaGitHubToolkit(BaseToolkit):
|
|
|
87
82
|
github_api_wrapper = AlitaGitHubAPIWrapper(**wrapper_payload)
|
|
88
83
|
available_tools: List[Dict] = github_api_wrapper.get_available_tools()
|
|
89
84
|
tools = []
|
|
90
|
-
prefix = clean_string(toolkit_name, AlitaGitHubToolkit.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
91
85
|
for tool in available_tools:
|
|
92
86
|
if selected_tools:
|
|
93
87
|
if tool["name"] not in selected_tools:
|
|
94
88
|
continue
|
|
89
|
+
description = tool["description"]
|
|
90
|
+
if toolkit_name:
|
|
91
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
92
|
+
description = f"Repository: {github_api_wrapper.github_repository}\n{description}"
|
|
93
|
+
description = description[:1000]
|
|
95
94
|
tools.append(GitHubAction(
|
|
96
95
|
api_wrapper=github_api_wrapper,
|
|
97
|
-
name=
|
|
96
|
+
name=tool["name"],
|
|
98
97
|
mode=tool["mode"],
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
description=description,
|
|
99
|
+
args_schema=tool["args_schema"],
|
|
100
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
102
101
|
))
|
|
103
102
|
return cls(tools=tools)
|
|
104
103
|
|
|
@@ -11,10 +11,7 @@ from github import Auth, Github, GithubIntegration, Repository
|
|
|
11
11
|
from github.Consts import DEFAULT_BASE_URL
|
|
12
12
|
from langchain_core.tools import ToolException
|
|
13
13
|
|
|
14
|
-
from
|
|
15
|
-
GitHubAuthConfig,
|
|
16
|
-
GitHubRepoConfig,
|
|
17
|
-
)
|
|
14
|
+
from ..elitea_base import extend_with_file_operations, BaseCodeToolApiWrapper
|
|
18
15
|
|
|
19
16
|
from .schemas import (
|
|
20
17
|
GitHubAuthConfig,
|
|
@@ -22,6 +19,7 @@ from .schemas import (
|
|
|
22
19
|
NoInput,
|
|
23
20
|
BranchName,
|
|
24
21
|
CreateBranchName,
|
|
22
|
+
DeleteBranchName,
|
|
25
23
|
DirectoryPath,
|
|
26
24
|
ReadFile,
|
|
27
25
|
UpdateFile,
|
|
@@ -48,9 +46,9 @@ from .schemas import (
|
|
|
48
46
|
# Import prompts for tools
|
|
49
47
|
from .tool_prompts import (
|
|
50
48
|
CREATE_FILE_PROMPT,
|
|
51
|
-
UPDATE_FILE_PROMPT,
|
|
52
49
|
CREATE_ISSUE_PROMPT,
|
|
53
50
|
UPDATE_ISSUE_PROMPT,
|
|
51
|
+
DELETE_BRANCH_PROMPT,
|
|
54
52
|
)
|
|
55
53
|
|
|
56
54
|
from langchain_community.tools.github.prompt import (
|
|
@@ -71,6 +69,8 @@ from langchain_community.tools.github.prompt import (
|
|
|
71
69
|
CREATE_PULL_REQUEST_PROMPT
|
|
72
70
|
)
|
|
73
71
|
|
|
72
|
+
from ..utils.tool_prompts import EDIT_FILE_DESCRIPTION
|
|
73
|
+
|
|
74
74
|
|
|
75
75
|
class GitHubClient(BaseModel):
|
|
76
76
|
"""Client for interacting with the GitHub REST API."""
|
|
@@ -94,6 +94,12 @@ class GitHubClient(BaseModel):
|
|
|
94
94
|
|
|
95
95
|
# Alita instance
|
|
96
96
|
alita: Optional[Any] = Field(default=None, exclude=True)
|
|
97
|
+
|
|
98
|
+
# Import file operation methods from BaseCodeToolApiWrapper
|
|
99
|
+
read_file_chunk = BaseCodeToolApiWrapper.read_file_chunk
|
|
100
|
+
read_multiple_files = BaseCodeToolApiWrapper.read_multiple_files
|
|
101
|
+
search_file = BaseCodeToolApiWrapper.search_file
|
|
102
|
+
edit_file = BaseCodeToolApiWrapper.edit_file
|
|
97
103
|
|
|
98
104
|
@property
|
|
99
105
|
def github_repo_instance(self) -> Optional[Repository.Repository]:
|
|
@@ -408,26 +414,53 @@ class GitHubClient(BaseModel):
|
|
|
408
414
|
Returns:
|
|
409
415
|
str: A detailed diff comparison between the two commits or an error message.
|
|
410
416
|
"""
|
|
417
|
+
def safe_author_info(commit_obj):
|
|
418
|
+
"""Safely extract author info from a commit object, handling None values."""
|
|
419
|
+
author = commit_obj.commit.author
|
|
420
|
+
if author:
|
|
421
|
+
return {
|
|
422
|
+
"name": author.name or "Unknown",
|
|
423
|
+
"date": author.date.isoformat() if author.date else None
|
|
424
|
+
}
|
|
425
|
+
# Fallback to GitHub user info if git author is not available
|
|
426
|
+
elif commit_obj.author:
|
|
427
|
+
return {
|
|
428
|
+
"name": commit_obj.author.login,
|
|
429
|
+
"date": None
|
|
430
|
+
}
|
|
431
|
+
return {"name": "Unknown", "date": None}
|
|
432
|
+
|
|
411
433
|
try:
|
|
412
434
|
# Get the repository
|
|
413
435
|
repo = self.github_api.get_repo(repo_name) if repo_name else self.github_repo_instance
|
|
414
|
-
|
|
436
|
+
|
|
415
437
|
# Get the comparison between the two commits
|
|
416
438
|
comparison = repo.compare(base_sha, head_sha)
|
|
417
|
-
|
|
439
|
+
|
|
440
|
+
# Get head commit - the GitHub Compare API doesn't return head_commit,
|
|
441
|
+
# so we get it from the commits list or fetch it directly
|
|
442
|
+
if comparison.commits:
|
|
443
|
+
head_commit_obj = comparison.commits[-1]
|
|
444
|
+
else:
|
|
445
|
+
# For identical commits or edge cases, fetch head commit directly
|
|
446
|
+
head_commit_obj = repo.get_commit(head_sha)
|
|
447
|
+
|
|
448
|
+
base_author = safe_author_info(comparison.base_commit)
|
|
449
|
+
head_author = safe_author_info(head_commit_obj)
|
|
450
|
+
|
|
418
451
|
# Extract comparison information
|
|
419
452
|
diff_info = {
|
|
420
453
|
"base_commit": {
|
|
421
454
|
"sha": comparison.base_commit.sha,
|
|
422
455
|
"message": comparison.base_commit.commit.message,
|
|
423
|
-
"author":
|
|
424
|
-
"date":
|
|
456
|
+
"author": base_author["name"],
|
|
457
|
+
"date": base_author["date"]
|
|
425
458
|
},
|
|
426
459
|
"head_commit": {
|
|
427
|
-
"sha":
|
|
428
|
-
"message":
|
|
429
|
-
"author":
|
|
430
|
-
"date":
|
|
460
|
+
"sha": head_commit_obj.sha,
|
|
461
|
+
"message": head_commit_obj.commit.message,
|
|
462
|
+
"author": head_author["name"],
|
|
463
|
+
"date": head_author["date"]
|
|
431
464
|
},
|
|
432
465
|
"status": comparison.status, # ahead, behind, identical, or diverged
|
|
433
466
|
"ahead_by": comparison.ahead_by,
|
|
@@ -436,14 +469,15 @@ class GitHubClient(BaseModel):
|
|
|
436
469
|
"commits": [],
|
|
437
470
|
"files": []
|
|
438
471
|
}
|
|
439
|
-
|
|
472
|
+
|
|
440
473
|
# Get commits in the comparison
|
|
441
474
|
for commit in comparison.commits:
|
|
475
|
+
author_info = safe_author_info(commit)
|
|
442
476
|
commit_info = {
|
|
443
477
|
"sha": commit.sha,
|
|
444
478
|
"message": commit.commit.message,
|
|
445
|
-
"author":
|
|
446
|
-
"date":
|
|
479
|
+
"author": author_info["name"],
|
|
480
|
+
"date": author_info["date"],
|
|
447
481
|
"url": commit.html_url
|
|
448
482
|
}
|
|
449
483
|
diff_info["commits"].append(commit_info)
|
|
@@ -1048,6 +1082,73 @@ class GitHubClient(BaseModel):
|
|
|
1048
1082
|
except Exception as e:
|
|
1049
1083
|
return f"Failed to create branch: {str(e)}"
|
|
1050
1084
|
|
|
1085
|
+
def delete_branch(self, branch_name: str, force: bool = False) -> str:
|
|
1086
|
+
"""
|
|
1087
|
+
Delete a branch from the GitHub repository.
|
|
1088
|
+
|
|
1089
|
+
Protected branches that cannot be deleted:
|
|
1090
|
+
- 'main' and 'master' branches are always protected
|
|
1091
|
+
- The configured base branch (github_base_branch) is protected
|
|
1092
|
+
- The currently active branch is protected (unless force=True)
|
|
1093
|
+
|
|
1094
|
+
Parameters:
|
|
1095
|
+
branch_name (str): Name of the branch to delete
|
|
1096
|
+
force (bool): If True, allows deletion of the current active branch
|
|
1097
|
+
|
|
1098
|
+
Returns:
|
|
1099
|
+
str: A success or error message.
|
|
1100
|
+
"""
|
|
1101
|
+
from github import GithubException
|
|
1102
|
+
|
|
1103
|
+
try:
|
|
1104
|
+
# Protected branch names that should never be deleted
|
|
1105
|
+
protected_branches = {'main', 'master'}
|
|
1106
|
+
|
|
1107
|
+
# Add base branch to protected list
|
|
1108
|
+
if self.github_base_branch:
|
|
1109
|
+
protected_branches.add(self.github_base_branch)
|
|
1110
|
+
|
|
1111
|
+
# Check if trying to delete a protected branch
|
|
1112
|
+
if branch_name.lower() in {b.lower() for b in protected_branches}:
|
|
1113
|
+
return (
|
|
1114
|
+
f"Cannot delete branch '{branch_name}': "
|
|
1115
|
+
f"It is a protected branch (main, master, or base branch). "
|
|
1116
|
+
f"Protected branches: {', '.join(sorted(protected_branches))}"
|
|
1117
|
+
)
|
|
1118
|
+
|
|
1119
|
+
# Check if trying to delete the active branch without force
|
|
1120
|
+
if branch_name == self.active_branch and not force:
|
|
1121
|
+
return (
|
|
1122
|
+
f"Cannot delete branch '{branch_name}': "
|
|
1123
|
+
f"It is currently the active branch. "
|
|
1124
|
+
f"Use force=True to delete it anyway, or switch to a different branch first."
|
|
1125
|
+
)
|
|
1126
|
+
|
|
1127
|
+
# Delete the branch
|
|
1128
|
+
repo = self.github_repo_instance
|
|
1129
|
+
ref = repo.get_git_ref(f"heads/{branch_name}")
|
|
1130
|
+
ref.delete()
|
|
1131
|
+
|
|
1132
|
+
# If we deleted the active branch, reset to base branch
|
|
1133
|
+
if branch_name == self.active_branch:
|
|
1134
|
+
self.active_branch = self.github_base_branch
|
|
1135
|
+
return (
|
|
1136
|
+
f"Branch '{branch_name}' deleted successfully. "
|
|
1137
|
+
f"Active branch has been reset to '{self.github_base_branch}'."
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
return f"Branch '{branch_name}' deleted successfully."
|
|
1141
|
+
|
|
1142
|
+
except GithubException as e:
|
|
1143
|
+
if e.status == 422:
|
|
1144
|
+
return f"Cannot delete branch '{branch_name}': {e.data.get('message', str(e))}"
|
|
1145
|
+
elif e.status == 404:
|
|
1146
|
+
return f"Branch '{branch_name}' not found in the repository."
|
|
1147
|
+
else:
|
|
1148
|
+
return f"Failed to delete branch '{branch_name}': {str(e)}"
|
|
1149
|
+
except Exception as e:
|
|
1150
|
+
return f"Failed to delete branch '{branch_name}': {str(e)}"
|
|
1151
|
+
|
|
1051
1152
|
def create_file(self, file_path: str, file_contents: str, repo_name: Optional[str] = None) -> str:
|
|
1052
1153
|
"""
|
|
1053
1154
|
Creates a new file on the GitHub repo
|
|
@@ -1087,65 +1188,12 @@ class GitHubClient(BaseModel):
|
|
|
1087
1188
|
except Exception as e:
|
|
1088
1189
|
return f"Unable to create file due to error:\n{str(e)}"
|
|
1089
1190
|
|
|
1090
|
-
def extract_old_new_pairs(self, file_query):
|
|
1091
|
-
# Split the file content by lines
|
|
1092
|
-
code_lines = file_query.split("\n")
|
|
1093
|
-
|
|
1094
|
-
# Initialize lists to hold the contents of OLD and NEW sections
|
|
1095
|
-
old_contents = []
|
|
1096
|
-
new_contents = []
|
|
1097
|
-
|
|
1098
|
-
# Initialize variables to track whether the current line is within an OLD or NEW section
|
|
1099
|
-
in_old_section = False
|
|
1100
|
-
in_new_section = False
|
|
1101
|
-
|
|
1102
|
-
# Temporary storage for the current section's content
|
|
1103
|
-
current_section_content = []
|
|
1104
|
-
|
|
1105
|
-
# Iterate through each line in the file content
|
|
1106
|
-
for line in code_lines:
|
|
1107
|
-
# Check for OLD section start
|
|
1108
|
-
if "OLD <<<" in line:
|
|
1109
|
-
in_old_section = True
|
|
1110
|
-
current_section_content = [] # Reset current section content
|
|
1111
|
-
continue # Skip the line with the marker
|
|
1112
|
-
|
|
1113
|
-
# Check for OLD section end
|
|
1114
|
-
if ">>>> OLD" in line:
|
|
1115
|
-
in_old_section = False
|
|
1116
|
-
old_contents.append("\n".join(current_section_content).strip()) # Add the captured content
|
|
1117
|
-
current_section_content = [] # Reset current section content
|
|
1118
|
-
continue # Skip the line with the marker
|
|
1119
|
-
|
|
1120
|
-
# Check for NEW section start
|
|
1121
|
-
if "NEW <<<" in line:
|
|
1122
|
-
in_new_section = True
|
|
1123
|
-
current_section_content = [] # Reset current section content
|
|
1124
|
-
continue # Skip the line with the marker
|
|
1125
|
-
|
|
1126
|
-
# Check for NEW section end
|
|
1127
|
-
if ">>>> NEW" in line:
|
|
1128
|
-
in_new_section = False
|
|
1129
|
-
new_contents.append("\n".join(current_section_content).strip()) # Add the captured content
|
|
1130
|
-
current_section_content = [] # Reset current section content
|
|
1131
|
-
continue # Skip the line with the marker
|
|
1132
|
-
|
|
1133
|
-
# If currently in an OLD or NEW section, add the line to the current section content
|
|
1134
|
-
if in_old_section or in_new_section:
|
|
1135
|
-
current_section_content.append(line)
|
|
1136
|
-
|
|
1137
|
-
# Pair the OLD and NEW contents
|
|
1138
|
-
paired_contents = list(zip(old_contents, new_contents))
|
|
1139
|
-
|
|
1140
|
-
return paired_contents
|
|
1141
|
-
|
|
1142
1191
|
def update_file(self, file_query: str, repo_name: Optional[str] = None, commit_message: Optional[str] = None) -> str:
|
|
1143
|
-
"""
|
|
1144
|
-
|
|
1192
|
+
"""Updates a file with new content using OLD/NEW markers and edit_file.
|
|
1193
|
+
|
|
1145
1194
|
Parameters:
|
|
1146
|
-
file_query(str): Contains the file path and the file contents
|
|
1147
|
-
|
|
1148
|
-
The new file contents is wrapped in NEW <<<< and >>>> NEW
|
|
1195
|
+
file_query(str): Contains the file path on the first line and the file contents
|
|
1196
|
+
wrapped in OLD <<<< and >>>> OLD / NEW <<<< and >>>> NEW markers.
|
|
1149
1197
|
For example:
|
|
1150
1198
|
/test/hello.txt
|
|
1151
1199
|
OLD <<<<
|
|
@@ -1154,13 +1202,13 @@ class GitHubClient(BaseModel):
|
|
|
1154
1202
|
NEW <<<<
|
|
1155
1203
|
Hello Mars!
|
|
1156
1204
|
>>>> NEW
|
|
1157
|
-
repo_name (Optional[str]): Name of the repository in format 'owner/repo'
|
|
1205
|
+
repo_name (Optional[str]): Name of the repository in format 'owner/repo'. Currently
|
|
1206
|
+
not used by edit_file and must refer to the initialized repository.
|
|
1158
1207
|
|
|
1159
1208
|
Returns:
|
|
1160
1209
|
A success or failure message
|
|
1161
1210
|
"""
|
|
1162
1211
|
try:
|
|
1163
|
-
repo = self.github_api.get_repo(repo_name) if repo_name else self.github_repo_instance
|
|
1164
1212
|
branch = self.active_branch
|
|
1165
1213
|
|
|
1166
1214
|
if branch == self.github_base_branch:
|
|
@@ -1169,29 +1217,36 @@ class GitHubClient(BaseModel):
|
|
|
1169
1217
|
"which is protected. Please create a new branch and try again."
|
|
1170
1218
|
)
|
|
1171
1219
|
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
if file_content == updated_file_content:
|
|
1220
|
+
# Split into lines and find first non-empty line for file_path
|
|
1221
|
+
lines = file_query.split("\n")
|
|
1222
|
+
first_non_empty_idx = None
|
|
1223
|
+
for i, line in enumerate(lines):
|
|
1224
|
+
if line.strip():
|
|
1225
|
+
first_non_empty_idx = i
|
|
1226
|
+
break
|
|
1227
|
+
|
|
1228
|
+
if first_non_empty_idx is None:
|
|
1182
1229
|
return (
|
|
1183
|
-
"
|
|
1184
|
-
"
|
|
1230
|
+
"Invalid file_query format. Expected first non-empty line to be the file path "
|
|
1231
|
+
"followed by OLD/NEW blocks."
|
|
1185
1232
|
)
|
|
1186
1233
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1234
|
+
file_path = lines[first_non_empty_idx].strip()
|
|
1235
|
+
# Keep all lines after file_path line (preserving empty lines)
|
|
1236
|
+
edit_content = "\n".join(lines[first_non_empty_idx + 1:])
|
|
1237
|
+
|
|
1238
|
+
# Set temporary repo override for internal helpers
|
|
1239
|
+
self._tmp_repo_for_edit = repo_name
|
|
1240
|
+
try:
|
|
1241
|
+
return self.edit_file(
|
|
1242
|
+
file_path=file_path,
|
|
1243
|
+
file_query=edit_content,
|
|
1244
|
+
branch=branch,
|
|
1245
|
+
commit_message=commit_message or f"Update {file_path}",
|
|
1246
|
+
)
|
|
1247
|
+
finally:
|
|
1248
|
+
if hasattr(self, "_tmp_repo_for_edit"):
|
|
1249
|
+
delattr(self, "_tmp_repo_for_edit")
|
|
1195
1250
|
except Exception as e:
|
|
1196
1251
|
return f"Unable to update file due to error:\n{str(e)}"
|
|
1197
1252
|
|
|
@@ -1414,23 +1469,27 @@ class GitHubClient(BaseModel):
|
|
|
1414
1469
|
except Exception as e:
|
|
1415
1470
|
return f"File not found `{file_path}` on branch `{branch}`. Error: {str(e)}"
|
|
1416
1471
|
|
|
1417
|
-
def _read_file(self, file_path: str, branch: str, repo_name: Optional[str] = None) -> str:
|
|
1472
|
+
def _read_file(self, file_path: str, branch: str, repo_name: Optional[str] = None, **kwargs) -> str:
|
|
1418
1473
|
"""
|
|
1419
|
-
Read a file from specified branch
|
|
1474
|
+
Read a file from specified branch with optional partial read support.
|
|
1475
|
+
|
|
1420
1476
|
Parameters:
|
|
1421
1477
|
file_path(str): the file path
|
|
1422
1478
|
branch(str): the branch to read the file from
|
|
1423
1479
|
repo_name (Optional[str]): Name of the repository in format 'owner/repo'
|
|
1480
|
+
**kwargs: Additional parameters (offset, limit, head, tail) - currently ignored,
|
|
1481
|
+
partial read handled client-side by base class methods
|
|
1424
1482
|
|
|
1425
1483
|
Returns:
|
|
1426
1484
|
str: The file decoded as a string, or an error message if not found
|
|
1427
1485
|
"""
|
|
1428
1486
|
try:
|
|
1429
|
-
repo
|
|
1487
|
+
# Prefer temporary repo set by update_file, then explicit repo_name
|
|
1488
|
+
effective_repo = getattr(self, "_tmp_repo_for_edit", None) or repo_name
|
|
1489
|
+
repo = self.github_api.get_repo(effective_repo) if effective_repo else self.github_repo_instance
|
|
1430
1490
|
file = repo.get_contents(file_path, ref=branch)
|
|
1431
1491
|
return file.decoded_content.decode("utf-8")
|
|
1432
1492
|
except Exception as e:
|
|
1433
|
-
from traceback import format_exc
|
|
1434
1493
|
return f"File not found `{file_path}` on branch `{branch}`. Error: {str(e)}"
|
|
1435
1494
|
|
|
1436
1495
|
def read_file(self, file_path: str, branch: Optional[str] = None, repo_name: Optional[str] = None) -> str:
|
|
@@ -1445,6 +1504,63 @@ class GitHubClient(BaseModel):
|
|
|
1445
1504
|
str: The file contents as a string
|
|
1446
1505
|
"""
|
|
1447
1506
|
return self._read_file(file_path, branch if branch else self.active_branch, repo_name)
|
|
1507
|
+
|
|
1508
|
+
def _write_file(
|
|
1509
|
+
self,
|
|
1510
|
+
file_path: str,
|
|
1511
|
+
content: str,
|
|
1512
|
+
branch: str = None,
|
|
1513
|
+
commit_message: str = None,
|
|
1514
|
+
repo_name: Optional[str] = None
|
|
1515
|
+
) -> str:
|
|
1516
|
+
"""
|
|
1517
|
+
Write content to a file (create or update).
|
|
1518
|
+
|
|
1519
|
+
Parameters:
|
|
1520
|
+
file_path: Path to the file
|
|
1521
|
+
content: New file content
|
|
1522
|
+
branch: Branch name (uses active branch if None)
|
|
1523
|
+
commit_message: Commit message
|
|
1524
|
+
repo_name: Name of the repository in format 'owner/repo'
|
|
1525
|
+
|
|
1526
|
+
Returns:
|
|
1527
|
+
Success message
|
|
1528
|
+
"""
|
|
1529
|
+
try:
|
|
1530
|
+
# Prefer temporary repo set by update_file, then explicit repo_name
|
|
1531
|
+
effective_repo = getattr(self, "_tmp_repo_for_edit", None) or repo_name
|
|
1532
|
+
repo = self.github_api.get_repo(effective_repo) if effective_repo else self.github_repo_instance
|
|
1533
|
+
branch = branch or self.active_branch
|
|
1534
|
+
|
|
1535
|
+
if branch == self.github_base_branch:
|
|
1536
|
+
raise ToolException(
|
|
1537
|
+
f"Cannot commit directly to the {self.github_base_branch} branch. "
|
|
1538
|
+
"Please create a new branch and try again."
|
|
1539
|
+
)
|
|
1540
|
+
|
|
1541
|
+
# Check if file exists
|
|
1542
|
+
try:
|
|
1543
|
+
existing_file = repo.get_contents(file_path, ref=branch)
|
|
1544
|
+
# File exists, update it
|
|
1545
|
+
repo.update_file(
|
|
1546
|
+
path=file_path,
|
|
1547
|
+
message=commit_message or f"Update {file_path}",
|
|
1548
|
+
content=content,
|
|
1549
|
+
branch=branch,
|
|
1550
|
+
sha=existing_file.sha,
|
|
1551
|
+
)
|
|
1552
|
+
return f"Updated file {file_path}"
|
|
1553
|
+
except:
|
|
1554
|
+
# File doesn't exist, create it
|
|
1555
|
+
repo.create_file(
|
|
1556
|
+
path=file_path,
|
|
1557
|
+
message=commit_message or f"Create {file_path}",
|
|
1558
|
+
content=content,
|
|
1559
|
+
branch=branch,
|
|
1560
|
+
)
|
|
1561
|
+
return f"Created file {file_path}"
|
|
1562
|
+
except Exception as e:
|
|
1563
|
+
raise ToolException(f"Unable to write file {file_path}: {str(e)}")
|
|
1448
1564
|
|
|
1449
1565
|
def loader(self,
|
|
1450
1566
|
branch: Optional[str] = None,
|
|
@@ -1877,6 +1993,7 @@ class GitHubClient(BaseModel):
|
|
|
1877
1993
|
import traceback
|
|
1878
1994
|
return f"API call failed: {traceback.format_exc()}"
|
|
1879
1995
|
|
|
1996
|
+
@extend_with_file_operations
|
|
1880
1997
|
def get_available_tools(self) -> List[Dict[str, Any]]:
|
|
1881
1998
|
return [
|
|
1882
1999
|
{
|
|
@@ -1946,7 +2063,7 @@ class GitHubClient(BaseModel):
|
|
|
1946
2063
|
"ref": self.update_file,
|
|
1947
2064
|
"name": "update_file",
|
|
1948
2065
|
"mode": "update_file",
|
|
1949
|
-
"description":
|
|
2066
|
+
"description": EDIT_FILE_DESCRIPTION,
|
|
1950
2067
|
"args_schema": UpdateFile,
|
|
1951
2068
|
},
|
|
1952
2069
|
{
|
|
@@ -1991,6 +2108,13 @@ class GitHubClient(BaseModel):
|
|
|
1991
2108
|
"description": CREATE_BRANCH_PROMPT,
|
|
1992
2109
|
"args_schema": CreateBranchName,
|
|
1993
2110
|
},
|
|
2111
|
+
{
|
|
2112
|
+
"ref": self.delete_branch,
|
|
2113
|
+
"name": "delete_branch",
|
|
2114
|
+
"mode": "delete_branch",
|
|
2115
|
+
"description": DELETE_BRANCH_PROMPT,
|
|
2116
|
+
"args_schema": DeleteBranchName,
|
|
2117
|
+
},
|
|
1994
2118
|
{
|
|
1995
2119
|
"ref": self.get_files_from_directory,
|
|
1996
2120
|
"name": "get_files_from_directory",
|