alita-sdk 0.3.462__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/agent/__init__.py +5 -0
- alita_sdk/cli/agent/default.py +258 -0
- alita_sdk/cli/agent_executor.py +15 -3
- alita_sdk/cli/agent_loader.py +56 -8
- alita_sdk/cli/agent_ui.py +93 -31
- alita_sdk/cli/agents.py +2274 -230
- alita_sdk/cli/callbacks.py +96 -25
- alita_sdk/cli/cli.py +10 -1
- alita_sdk/cli/config.py +162 -9
- 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/input_handler.py +419 -0
- alita_sdk/cli/inventory.py +1073 -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 +14 -17
- alita_sdk/cli/toolkit_loader.py +35 -5
- alita_sdk/cli/tools/__init__.py +36 -2
- alita_sdk/cli/tools/approval.py +224 -0
- alita_sdk/cli/tools/filesystem.py +910 -64
- 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 +0 -3
- alita_sdk/configurations/confluence.py +76 -42
- alita_sdk/configurations/figma.py +76 -0
- alita_sdk/configurations/gitlab.py +17 -5
- 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/runtime/clients/artifact.py +3 -3
- alita_sdk/runtime/clients/client.py +353 -48
- alita_sdk/runtime/clients/sandbox_client.py +0 -21
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +123 -26
- alita_sdk/runtime/langchain/constants.py +642 -1
- 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 +6 -3
- 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 +12 -7
- alita_sdk/runtime/langchain/langraph_agent.py +279 -73
- alita_sdk/runtime/langchain/utils.py +82 -15
- alita_sdk/runtime/llms/preloaded.py +2 -6
- 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 +7 -0
- alita_sdk/runtime/toolkits/application.py +21 -9
- alita_sdk/runtime/toolkits/artifact.py +15 -5
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +139 -251
- 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 +238 -32
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +3 -1
- alita_sdk/runtime/tools/application.py +20 -6
- alita_sdk/runtime/tools/artifact.py +511 -28
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +43 -15
- alita_sdk/runtime/tools/image_generation.py +50 -44
- alita_sdk/runtime/tools/llm.py +852 -67
- alita_sdk/runtime/tools/loop.py +3 -1
- alita_sdk/runtime/tools/loop_output.py +3 -1
- alita_sdk/runtime/tools/mcp_remote_tool.py +25 -10
- alita_sdk/runtime/tools/mcp_server_tool.py +7 -6
- 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 +9 -6
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +7 -2
- alita_sdk/runtime/tools/vectorstore_base.py +51 -11
- 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 +202 -5
- alita_sdk/runtime/utils/mcp_sse_client.py +36 -7
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/serialization.py +155 -0
- alita_sdk/runtime/utils/streamlit.py +6 -10
- alita_sdk/runtime/utils/toolkit_utils.py +16 -5
- alita_sdk/runtime/utils/utils.py +36 -0
- alita_sdk/tools/__init__.py +113 -29
- alita_sdk/tools/ado/repos/__init__.py +51 -33
- 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 -8
- alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
- alita_sdk/tools/ado/work_item/__init__.py +26 -9
- alita_sdk/tools/ado/work_item/ado_wrapper.py +56 -3
- 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 +170 -45
- alita_sdk/tools/bitbucket/__init__.py +17 -12
- 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/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 +10 -7
- alita_sdk/tools/code_indexer_toolkit.py +73 -23
- alita_sdk/tools/confluence/__init__.py +21 -15
- alita_sdk/tools/confluence/api_wrapper.py +78 -23
- alita_sdk/tools/confluence/loader.py +4 -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 +13 -14
- 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 +15 -11
- alita_sdk/tools/gitlab/api_wrapper.py +207 -41
- alita_sdk/tools/gitlab_org/__init__.py +10 -8
- 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 +10 -8
- alita_sdk/tools/google_places/api_wrapper.py +1 -1
- alita_sdk/tools/jira/__init__.py +17 -11
- alita_sdk/tools/jira/api_wrapper.py +91 -40
- 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 +11 -3
- alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +490 -114
- 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 +11 -11
- alita_sdk/tools/pptx/__init__.py +10 -9
- alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
- alita_sdk/tools/qtest/__init__.py +30 -10
- alita_sdk/tools/qtest/api_wrapper.py +430 -13
- alita_sdk/tools/rally/__init__.py +10 -8
- alita_sdk/tools/rally/api_wrapper.py +1 -1
- alita_sdk/tools/report_portal/__init__.py +12 -9
- alita_sdk/tools/salesforce/__init__.py +10 -9
- alita_sdk/tools/servicenow/__init__.py +17 -14
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +10 -8
- alita_sdk/tools/sharepoint/api_wrapper.py +4 -4
- alita_sdk/tools/slack/__init__.py +10 -8
- alita_sdk/tools/slack/api_wrapper.py +2 -2
- alita_sdk/tools/sql/__init__.py +11 -9
- alita_sdk/tools/testio/__init__.py +10 -8
- alita_sdk/tools/testrail/__init__.py +11 -8
- alita_sdk/tools/testrail/api_wrapper.py +1 -1
- alita_sdk/tools/utils/__init__.py +9 -4
- alita_sdk/tools/utils/content_parser.py +77 -3
- 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 +17 -13
- alita_sdk/tools/xray/__init__.py +12 -9
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +9 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +11 -8
- alita_sdk/tools/zephyr_essential/__init__.py +10 -8
- 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 -9
- alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
- alita_sdk/tools/zephyr_squad/__init__.py +10 -8
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +147 -7
- 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.462.dist-info/RECORD +0 -384
- alita_sdk-0.3.462.dist-info/entry_points.txt +0 -2
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
|
@@ -23,9 +23,11 @@ from langchain_core.tools import ToolException
|
|
|
23
23
|
from msrest.authentication import BasicAuthentication
|
|
24
24
|
from pydantic import Field, PrivateAttr, create_model, model_validator, SecretStr
|
|
25
25
|
|
|
26
|
-
from
|
|
26
|
+
from ...elitea_base import BaseCodeToolApiWrapper
|
|
27
|
+
from ..utils import generate_diff, get_content_from_generator
|
|
27
28
|
from ...code_indexer_toolkit import CodeIndexerToolkit
|
|
28
29
|
from ...utils.available_tools_decorator import extend_with_parent_available_tools
|
|
30
|
+
from ...utils.tool_prompts import EDIT_FILE_DESCRIPTION, UPDATE_FILE_PROMPT_NO_PATH
|
|
29
31
|
|
|
30
32
|
logger = logging.getLogger(__name__)
|
|
31
33
|
|
|
@@ -111,8 +113,7 @@ class ArgsSchema(Enum):
|
|
|
111
113
|
Field(
|
|
112
114
|
description=(
|
|
113
115
|
"Branch to be used for read file operation."
|
|
114
|
-
)
|
|
115
|
-
default=None
|
|
116
|
+
)
|
|
116
117
|
),
|
|
117
118
|
)
|
|
118
119
|
)
|
|
@@ -130,9 +131,18 @@ class ArgsSchema(Enum):
|
|
|
130
131
|
)
|
|
131
132
|
UpdateFile = create_model(
|
|
132
133
|
"UpdateFile",
|
|
133
|
-
branch_name=(
|
|
134
|
-
|
|
135
|
-
|
|
134
|
+
branch_name=(
|
|
135
|
+
str,
|
|
136
|
+
Field(description="The name of the branch, e.g. `my_branch`.")
|
|
137
|
+
),
|
|
138
|
+
file_path=(
|
|
139
|
+
str,
|
|
140
|
+
Field(description="Path of a file to be updated."),
|
|
141
|
+
),
|
|
142
|
+
update_query=(
|
|
143
|
+
str,
|
|
144
|
+
Field(description=UPDATE_FILE_PROMPT_NO_PATH),
|
|
145
|
+
),
|
|
136
146
|
)
|
|
137
147
|
DeleteFile = create_model(
|
|
138
148
|
"DeleteFile",
|
|
@@ -244,14 +254,24 @@ class ArgsSchema(Enum):
|
|
|
244
254
|
|
|
245
255
|
|
|
246
256
|
class ReposApiWrapper(CodeIndexerToolkit):
|
|
247
|
-
#
|
|
248
|
-
organization_url: Optional[str]
|
|
249
|
-
project: Optional[str]
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
# ADO Configuration fields (from AdoConfiguration)
|
|
258
|
+
organization_url: Optional[str] = None
|
|
259
|
+
project: Optional[str] = None
|
|
260
|
+
token: Optional[SecretStr] = None
|
|
261
|
+
|
|
262
|
+
# Repository-specific fields (toolkit level)
|
|
263
|
+
repository_id: Optional[str] = None
|
|
264
|
+
base_branch: Optional[str] = None
|
|
265
|
+
active_branch: Optional[str] = None
|
|
266
|
+
|
|
267
|
+
# Alita instance
|
|
268
|
+
alita: Optional[Any] = None
|
|
269
|
+
|
|
270
|
+
# Client instance - marked as exclude=True
|
|
271
|
+
ado_client_instance: Optional[GitClient] = Field(default=None, exclude=True)
|
|
272
|
+
|
|
273
|
+
# Reuse common file helpers from BaseCodeToolApiWrapper
|
|
274
|
+
edit_file = BaseCodeToolApiWrapper.edit_file
|
|
255
275
|
|
|
256
276
|
class Config:
|
|
257
277
|
arbitrary_types_allowed = True
|
|
@@ -259,43 +279,71 @@ class ReposApiWrapper(CodeIndexerToolkit):
|
|
|
259
279
|
@model_validator(mode="before")
|
|
260
280
|
@classmethod
|
|
261
281
|
def validate_toolkit(cls, values):
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
282
|
+
from langchain.utils import get_from_dict_or_env
|
|
283
|
+
|
|
284
|
+
# Get ADO configuration values
|
|
285
|
+
organization_url = get_from_dict_or_env(values, ["organization_url"], "ADO_ORGANIZATION_URL", default=None)
|
|
286
|
+
project = get_from_dict_or_env(values, ["project"], "ADO_PROJECT", default=None)
|
|
287
|
+
token = get_from_dict_or_env(values, ["token"], "ADO_TOKEN", default=None)
|
|
288
|
+
|
|
289
|
+
# Get repository-specific values
|
|
290
|
+
repository_id = get_from_dict_or_env(values, ["repository_id"], "ADO_REPOSITORY_ID", default=None)
|
|
291
|
+
base_branch = get_from_dict_or_env(values, ["base_branch"], "ADO_BASE_BRANCH", default="main")
|
|
292
|
+
active_branch = get_from_dict_or_env(values, ["active_branch"], "ADO_ACTIVE_BRANCH", default="main")
|
|
268
293
|
|
|
269
294
|
if not organization_url or not project or not repository_id:
|
|
270
295
|
raise ToolException(
|
|
271
296
|
"Parameters: organization_url, project, and repository_id are required."
|
|
272
297
|
)
|
|
273
298
|
|
|
299
|
+
credentials = BasicAuthentication("", token)
|
|
300
|
+
|
|
274
301
|
try:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
302
|
+
# Initialize ADO Git client
|
|
303
|
+
ado_client = GitClient(base_url=organization_url, creds=credentials)
|
|
304
|
+
# Verify access to repository
|
|
305
|
+
ado_client.get_repository(repository_id, project=project)
|
|
306
|
+
|
|
307
|
+
# Store client instance
|
|
308
|
+
values["ado_client_instance"] = ado_client
|
|
309
|
+
|
|
310
|
+
def branch_exists(branch_name):
|
|
311
|
+
try:
|
|
312
|
+
branch = ado_client.get_branch(
|
|
313
|
+
repository_id=repository_id, name=branch_name, project=project
|
|
314
|
+
)
|
|
315
|
+
return branch is not None
|
|
316
|
+
except Exception:
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
if base_branch:
|
|
320
|
+
if not branch_exists(base_branch):
|
|
321
|
+
raise ToolException(f"The base branch '{base_branch}' does not exist.")
|
|
322
|
+
if active_branch:
|
|
323
|
+
if not branch_exists(active_branch):
|
|
324
|
+
raise ToolException(f"The active branch '{active_branch}' does not exist.")
|
|
325
|
+
|
|
278
326
|
except Exception as e:
|
|
327
|
+
if isinstance(e, ToolException):
|
|
328
|
+
raise
|
|
279
329
|
raise ToolException(f"Failed to connect to Azure DevOps: {e}")
|
|
280
330
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return False
|
|
289
|
-
|
|
290
|
-
if base_branch:
|
|
291
|
-
if not branch_exists(base_branch):
|
|
292
|
-
raise ToolException(f"The base branch '{base_branch}' does not exist.")
|
|
293
|
-
if active_branch:
|
|
294
|
-
if not branch_exists(active_branch):
|
|
295
|
-
raise ToolException(f"The active branch '{active_branch}' does not exist.")
|
|
331
|
+
# Update values with configuration
|
|
332
|
+
values["organization_url"] = organization_url
|
|
333
|
+
values["project"] = project
|
|
334
|
+
values["token"] = token
|
|
335
|
+
values["repository_id"] = repository_id
|
|
336
|
+
values["base_branch"] = base_branch
|
|
337
|
+
values["active_branch"] = active_branch
|
|
296
338
|
|
|
297
339
|
return super().validate_toolkit(values)
|
|
298
340
|
|
|
341
|
+
# Expose ADO Git client via property
|
|
342
|
+
@property
|
|
343
|
+
def _client(self) -> GitClient:
|
|
344
|
+
"""Access to ADO Git client methods"""
|
|
345
|
+
return self.ado_client_instance
|
|
346
|
+
|
|
299
347
|
def _get_commits(self, file_path: str, branch: str, top: int = None) -> List[GitCommitRef]:
|
|
300
348
|
"""
|
|
301
349
|
Get commits for a specific file in a specific branch.
|
|
@@ -645,8 +693,18 @@ class ReposApiWrapper(CodeIndexerToolkit):
|
|
|
645
693
|
|
|
646
694
|
return dumps(data)
|
|
647
695
|
|
|
648
|
-
def download_file(self, path):
|
|
649
|
-
|
|
696
|
+
def download_file(self, path: str, branch: str = None):
|
|
697
|
+
branch = branch or self.active_branch or self.base_branch
|
|
698
|
+
version_descriptor = GitVersionDescriptor(
|
|
699
|
+
version=branch, version_type="branch"
|
|
700
|
+
)
|
|
701
|
+
return b"".join(self._client.get_item_content(
|
|
702
|
+
self.repository_id,
|
|
703
|
+
path=path,
|
|
704
|
+
project=self.project,
|
|
705
|
+
download=True,
|
|
706
|
+
version_descriptor=version_descriptor
|
|
707
|
+
))
|
|
650
708
|
|
|
651
709
|
def get_file_content(self, commit_id, path):
|
|
652
710
|
version_descriptor = GitVersionDescriptor(
|
|
@@ -836,22 +894,50 @@ class ReposApiWrapper(CodeIndexerToolkit):
|
|
|
836
894
|
logger.error(msg)
|
|
837
895
|
return ToolException(msg)
|
|
838
896
|
|
|
839
|
-
def
|
|
897
|
+
def _write_file(self, file_path: str, content: str, branch: str = None, commit_message: str = None) -> str:
|
|
898
|
+
"""Write content to a file in Azure DevOps by creating an edit commit.
|
|
899
|
+
|
|
900
|
+
This implementation follows the previous `update_file` behavior: it always
|
|
901
|
+
performs an 'edit' change (does not create the file), gets the latest
|
|
902
|
+
commit id for the branch and pushes a new commit containing the change.
|
|
840
903
|
"""
|
|
841
|
-
|
|
904
|
+
try:
|
|
905
|
+
# Get the latest commit ID of the target branch
|
|
906
|
+
branch_obj = self._client.get_branch(
|
|
907
|
+
repository_id=self.repository_id,
|
|
908
|
+
project=self.project,
|
|
909
|
+
name=branch,
|
|
910
|
+
)
|
|
911
|
+
if branch_obj is None or not hasattr(branch_obj, 'commit') or not hasattr(branch_obj.commit, 'commit_id'):
|
|
912
|
+
raise ToolException(f"Branch `{branch}` does not exist or has no commits.")
|
|
913
|
+
|
|
914
|
+
latest_commit_id = branch_obj.commit.commit_id
|
|
915
|
+
|
|
916
|
+
# Build edit change and push
|
|
917
|
+
change = GitChange("edit", file_path, content).to_dict()
|
|
918
|
+
|
|
919
|
+
ref_update = GitRefUpdate(name=f"refs/heads/{branch}", old_object_id=latest_commit_id)
|
|
920
|
+
new_commit = GitCommit(comment=commit_message or ("Update " + file_path), changes=[change])
|
|
921
|
+
push = GitPush(commits=[new_commit], ref_updates=[ref_update])
|
|
922
|
+
|
|
923
|
+
self._client.create_push(push=push, repository_id=self.repository_id, project=self.project)
|
|
924
|
+
return f"Updated file {file_path}"
|
|
925
|
+
except ToolException:
|
|
926
|
+
# Re-raise known tool exceptions
|
|
927
|
+
raise
|
|
928
|
+
except Exception as e:
|
|
929
|
+
logger.error(f"Unable to write file {file_path}: {e}")
|
|
930
|
+
raise ToolException(f"Unable to write file {file_path}: {str(e)}")
|
|
931
|
+
|
|
932
|
+
def update_file(self, branch_name: str, file_path: str, update_query: str) -> str:
|
|
933
|
+
"""Updates a file with new content in Azure DevOps using OLD/NEW markers.
|
|
934
|
+
|
|
842
935
|
Parameters:
|
|
843
936
|
branch_name (str): The name of the branch where update the file.
|
|
844
937
|
file_path (str): Path to the file for update.
|
|
845
|
-
update_query(str): Contains the file contents
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
For example:
|
|
849
|
-
OLD <<<<
|
|
850
|
-
Hello Earth!
|
|
851
|
-
>>>> OLD
|
|
852
|
-
NEW <<<<
|
|
853
|
-
Hello Mars!
|
|
854
|
-
>>>> NEW
|
|
938
|
+
update_query(str): Contains the file contents required to be updated,
|
|
939
|
+
wrapped in Git-style OLD/NEW blocks.
|
|
940
|
+
|
|
855
941
|
Returns:
|
|
856
942
|
A success or failure message
|
|
857
943
|
"""
|
|
@@ -864,43 +950,16 @@ class ReposApiWrapper(CodeIndexerToolkit):
|
|
|
864
950
|
"Please create a new branch and try again."
|
|
865
951
|
)
|
|
866
952
|
try:
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
if not old.strip():
|
|
875
|
-
continue
|
|
876
|
-
updated_file_content = updated_file_content.replace(old, new)
|
|
877
|
-
|
|
878
|
-
if file_content == updated_file_content:
|
|
879
|
-
return (
|
|
880
|
-
"File content was not updated because old content was not found or empty. "
|
|
881
|
-
"It may be helpful to use the read_file action to get "
|
|
882
|
-
"the current file contents."
|
|
883
|
-
)
|
|
884
|
-
|
|
885
|
-
# Get the latest commit ID of the active branch to use as oldObjectId
|
|
886
|
-
branch = self._client.get_branch(
|
|
887
|
-
repository_id=self.repository_id,
|
|
888
|
-
project=self.project,
|
|
889
|
-
name=self.active_branch,
|
|
890
|
-
)
|
|
891
|
-
latest_commit_id = branch.commit.commit_id
|
|
892
|
-
|
|
893
|
-
change = GitChange("edit", file_path, updated_file_content).to_dict()
|
|
894
|
-
|
|
895
|
-
ref_update = GitRefUpdate(
|
|
896
|
-
name=f"refs/heads/{self.active_branch}", old_object_id=latest_commit_id
|
|
897
|
-
)
|
|
898
|
-
new_commit = GitCommit(comment=f"Update {file_path}", changes=[change])
|
|
899
|
-
push = GitPush(commits=[new_commit], ref_updates=[ref_update])
|
|
900
|
-
self._client.create_push(
|
|
901
|
-
push=push, repository_id=self.repository_id, project=self.project
|
|
953
|
+
# Let edit_file handle parsing and content updates; this will call _read_file and _write_file.
|
|
954
|
+
# For ADO, branch_name is used as branch; commit message is derived from file_path.
|
|
955
|
+
return self.edit_file(
|
|
956
|
+
file_path=file_path,
|
|
957
|
+
file_query=update_query,
|
|
958
|
+
branch=self.active_branch,
|
|
959
|
+
commit_message=f"Update {file_path}",
|
|
902
960
|
)
|
|
903
|
-
|
|
961
|
+
except ToolException as e:
|
|
962
|
+
return str(e)
|
|
904
963
|
except Exception as e:
|
|
905
964
|
msg = f"Unable to update file due to error:\n{str(e)}"
|
|
906
965
|
logger.error(msg)
|
|
@@ -1236,7 +1295,7 @@ class ReposApiWrapper(CodeIndexerToolkit):
|
|
|
1236
1295
|
{
|
|
1237
1296
|
"ref": self.update_file,
|
|
1238
1297
|
"name": "update_file",
|
|
1239
|
-
"description":
|
|
1298
|
+
"description": EDIT_FILE_DESCRIPTION,
|
|
1240
1299
|
"args_schema": ArgsSchema.UpdateFile.value,
|
|
1241
1300
|
},
|
|
1242
1301
|
{
|
|
@@ -10,25 +10,38 @@ from ....configurations.ado import AdoConfiguration
|
|
|
10
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
11
11
|
from .test_plan_wrapper import TestPlanApiWrapper
|
|
12
12
|
from ...base.tool import BaseAction
|
|
13
|
-
from ...utils import clean_string,
|
|
13
|
+
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
14
|
+
from ....runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
name = "azure_devops_plans"
|
|
17
18
|
name_alias = "ado_plans"
|
|
18
19
|
|
|
20
|
+
def get_toolkit(tool):
|
|
21
|
+
return AzureDevOpsPlansToolkit().get_toolkit(
|
|
22
|
+
selected_tools=tool['settings'].get('selected_tools', []),
|
|
23
|
+
ado_configuration=tool['settings']['ado_configuration'],
|
|
24
|
+
limit=tool['settings'].get('limit', 5),
|
|
25
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
26
|
+
alita=tool['settings'].get('alita', None),
|
|
27
|
+
llm=tool['settings'].get('llm', None),
|
|
28
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
29
|
+
collection_name=tool['toolkit_name'],
|
|
30
|
+
doctype='doc',
|
|
31
|
+
embedding_model=tool['settings'].get('embedding_model'),
|
|
32
|
+
vectorstore_type="PGVector"
|
|
33
|
+
)
|
|
19
34
|
|
|
20
35
|
class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
21
36
|
tools: List[BaseTool] = []
|
|
22
|
-
toolkit_max_length: int = 0
|
|
23
37
|
|
|
24
38
|
@staticmethod
|
|
25
39
|
def toolkit_config_schema() -> BaseModel:
|
|
26
40
|
selected_tools = {x['name']: x['args_schema'].schema() for x in TestPlanApiWrapper.model_construct().get_available_tools()}
|
|
27
|
-
AzureDevOpsPlansToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
28
41
|
m = create_model(
|
|
29
42
|
name_alias,
|
|
30
43
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
31
|
-
limit=(Optional[int], Field(description="ADO plans limit used for limitation of the list with results", default=5)),
|
|
44
|
+
limit=(Optional[int], Field(description="ADO plans limit used for limitation of the list with results", default=5, gt=0)),
|
|
32
45
|
# indexer settings
|
|
33
46
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None,
|
|
34
47
|
description="PgVector Configuration", json_schema_extra={'configuration_types': ['pgvector']})),
|
|
@@ -39,7 +52,6 @@ class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
|
39
52
|
{
|
|
40
53
|
"label": "ADO plans",
|
|
41
54
|
"icon_url": "ado-plans.svg",
|
|
42
|
-
"max_length": AzureDevOpsPlansToolkit.toolkit_max_length,
|
|
43
55
|
"categories": ["test management"],
|
|
44
56
|
"extra_categories": ["test case management", "qa"],
|
|
45
57
|
"sections": {
|
|
@@ -97,17 +109,21 @@ class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
|
97
109
|
azure_devops_api_wrapper = TestPlanApiWrapper(**wrapper_payload)
|
|
98
110
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
99
111
|
tools = []
|
|
100
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
101
112
|
for tool in available_tools:
|
|
102
113
|
if selected_tools:
|
|
103
114
|
if tool["name"] not in selected_tools:
|
|
104
115
|
continue
|
|
105
116
|
print(tool)
|
|
117
|
+
description = tool["description"] + f"\nADO instance: {azure_devops_api_wrapper.organization_url}"
|
|
118
|
+
if toolkit_name:
|
|
119
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
120
|
+
description = description[:1000]
|
|
106
121
|
tools.append(BaseAction(
|
|
107
122
|
api_wrapper=azure_devops_api_wrapper,
|
|
108
|
-
name=
|
|
109
|
-
description=
|
|
110
|
-
args_schema=tool["args_schema"]
|
|
123
|
+
name=tool["name"],
|
|
124
|
+
description=description,
|
|
125
|
+
args_schema=tool["args_schema"],
|
|
126
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
111
127
|
))
|
|
112
128
|
return cls(tools=tools)
|
|
113
129
|
|
|
@@ -180,7 +180,29 @@ class TestPlanApiWrapper(NonCodeIndexerToolkit):
|
|
|
180
180
|
connection = Connection(base_url=values['organization_url'], creds=credentials)
|
|
181
181
|
cls._client = connection.clients.get_test_plan_client()
|
|
182
182
|
except Exception as e:
|
|
183
|
-
|
|
183
|
+
error_msg = str(e).lower()
|
|
184
|
+
if "expired" in error_msg or "token" in error_msg and ("invalid" in error_msg or "unauthorized" in error_msg):
|
|
185
|
+
raise ValueError(
|
|
186
|
+
"Azure DevOps connection failed: Your access token has expired or is invalid. "
|
|
187
|
+
"Please refresh your token in the toolkit configuration."
|
|
188
|
+
)
|
|
189
|
+
elif "401" in error_msg or "unauthorized" in error_msg:
|
|
190
|
+
raise ValueError(
|
|
191
|
+
"Azure DevOps connection failed: Authentication failed. "
|
|
192
|
+
"Please check your credentials in the toolkit configuration."
|
|
193
|
+
)
|
|
194
|
+
elif "404" in error_msg or "not found" in error_msg:
|
|
195
|
+
raise ValueError(
|
|
196
|
+
"Azure DevOps connection failed: Organization or project not found. "
|
|
197
|
+
"Please verify your organization URL and project name."
|
|
198
|
+
)
|
|
199
|
+
elif "timeout" in error_msg or "timed out" in error_msg:
|
|
200
|
+
raise ValueError(
|
|
201
|
+
"Azure DevOps connection failed: Connection timed out. "
|
|
202
|
+
"Please check your network connection and try again."
|
|
203
|
+
)
|
|
204
|
+
else:
|
|
205
|
+
raise ValueError(f"Azure DevOps connection failed: {e}")
|
|
184
206
|
return super().validate_toolkit(values)
|
|
185
207
|
|
|
186
208
|
def create_test_plan(self, test_plan_create_params: str):
|
alita_sdk/tools/ado/utils.py
CHANGED
|
@@ -1,24 +1,6 @@
|
|
|
1
|
-
import re
|
|
2
1
|
import difflib
|
|
3
2
|
|
|
4
3
|
|
|
5
|
-
def extract_old_new_pairs(file_query: str):
|
|
6
|
-
"""
|
|
7
|
-
Extracts old and new content pairs from a file query.
|
|
8
|
-
Parameters:
|
|
9
|
-
file_query (str): The file query containing old and new content.
|
|
10
|
-
Returns:
|
|
11
|
-
list of tuples: A list where each tuple contains (old_content, new_content).
|
|
12
|
-
"""
|
|
13
|
-
old_pattern = re.compile(r"OLD <<<<\s*(.*?)\s*>>>> OLD", re.DOTALL)
|
|
14
|
-
new_pattern = re.compile(r"NEW <<<<\s*(.*?)\s*>>>> NEW", re.DOTALL)
|
|
15
|
-
|
|
16
|
-
old_contents = old_pattern.findall(file_query)
|
|
17
|
-
new_contents = new_pattern.findall(file_query)
|
|
18
|
-
|
|
19
|
-
return list(zip(old_contents, new_contents))
|
|
20
|
-
|
|
21
|
-
|
|
22
4
|
def generate_diff(base_text, target_text, file_path):
|
|
23
5
|
base_lines = base_text.splitlines(keepends=True)
|
|
24
6
|
target_lines = target_text.splitlines(keepends=True)
|
|
@@ -28,6 +10,7 @@ def generate_diff(base_text, target_text, file_path):
|
|
|
28
10
|
|
|
29
11
|
return "".join(diff)
|
|
30
12
|
|
|
13
|
+
|
|
31
14
|
def get_content_from_generator(content_generator):
|
|
32
15
|
def safe_decode(chunk):
|
|
33
16
|
try:
|
|
@@ -9,19 +9,33 @@ from ...elitea_base import filter_missconfigured_index_tools
|
|
|
9
9
|
from ....configurations.ado import AdoConfiguration
|
|
10
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
11
11
|
from ...base.tool import BaseAction
|
|
12
|
-
from ...utils import clean_string,
|
|
12
|
+
from ...utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
13
|
+
from ....runtime.utils.constants import TOOLKIT_NAME_META, TOOL_NAME_META, TOOLKIT_TYPE_META
|
|
13
14
|
|
|
14
15
|
name = "azure_devops_wiki"
|
|
15
16
|
name_alias = 'ado_wiki'
|
|
16
17
|
|
|
18
|
+
def get_toolkit(tool):
|
|
19
|
+
return AzureDevOpsWikiToolkit().get_toolkit(
|
|
20
|
+
selected_tools=tool['settings'].get('selected_tools', []),
|
|
21
|
+
ado_configuration=tool['settings']['ado_configuration'],
|
|
22
|
+
limit=tool['settings'].get('limit', 5),
|
|
23
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
24
|
+
alita=tool['settings'].get('alita', None),
|
|
25
|
+
llm=tool['settings'].get('llm', None),
|
|
26
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
27
|
+
collection_name=tool['toolkit_name'],
|
|
28
|
+
doctype='doc',
|
|
29
|
+
embedding_model=tool['settings'].get('embedding_model'),
|
|
30
|
+
vectorstore_type="PGVector"
|
|
31
|
+
)
|
|
32
|
+
|
|
17
33
|
class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
18
34
|
tools: List[BaseTool] = []
|
|
19
|
-
toolkit_max_length: int = 0
|
|
20
35
|
|
|
21
36
|
@staticmethod
|
|
22
37
|
def toolkit_config_schema() -> BaseModel:
|
|
23
38
|
selected_tools = {x['name']: x['args_schema'].schema() for x in AzureDevOpsApiWrapper.model_construct().get_available_tools()}
|
|
24
|
-
AzureDevOpsWikiToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
25
39
|
m = create_model(
|
|
26
40
|
name_alias,
|
|
27
41
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
@@ -37,7 +51,6 @@ class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
|
37
51
|
'metadata': {
|
|
38
52
|
"label": "ADO wiki",
|
|
39
53
|
"icon_url": "ado-wiki-icon.svg",
|
|
40
|
-
"max_length": AzureDevOpsWikiToolkit.toolkit_max_length,
|
|
41
54
|
"categories": ["documentation"],
|
|
42
55
|
"extra_categories": ["knowledge base", "documentation management", "wiki"],
|
|
43
56
|
"sections": {
|
|
@@ -91,16 +104,20 @@ class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
|
91
104
|
azure_devops_api_wrapper = AzureDevOpsApiWrapper(**wrapper_payload)
|
|
92
105
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
93
106
|
tools = []
|
|
94
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
95
107
|
for tool in available_tools:
|
|
96
108
|
if selected_tools:
|
|
97
109
|
if tool["name"] not in selected_tools:
|
|
98
110
|
continue
|
|
111
|
+
description = tool["description"] + f"\nADO instance: {azure_devops_api_wrapper.organization_url}/{azure_devops_api_wrapper.project}"
|
|
112
|
+
if toolkit_name:
|
|
113
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
114
|
+
description = description[:1000]
|
|
99
115
|
tools.append(BaseAction(
|
|
100
116
|
api_wrapper=azure_devops_api_wrapper,
|
|
101
|
-
name=
|
|
102
|
-
description=
|
|
103
|
-
args_schema=tool["args_schema"]
|
|
117
|
+
name=tool["name"],
|
|
118
|
+
description=description,
|
|
119
|
+
args_schema=tool["args_schema"],
|
|
120
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
104
121
|
))
|
|
105
122
|
return cls(tools=tools)
|
|
106
123
|
|