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
|
@@ -4,28 +4,42 @@ from langchain_core.tools import BaseTool, BaseToolkit
|
|
|
4
4
|
from pydantic import create_model, BaseModel, Field
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
+
|
|
8
|
+
from ...elitea_base import filter_missconfigured_index_tools
|
|
7
9
|
from ....configurations.ado import AdoConfiguration
|
|
8
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
9
11
|
from .test_plan_wrapper import TestPlanApiWrapper
|
|
10
12
|
from ...base.tool import BaseAction
|
|
11
|
-
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
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
name = "azure_devops_plans"
|
|
15
18
|
name_alias = "ado_plans"
|
|
16
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
|
+
)
|
|
17
34
|
|
|
18
35
|
class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
19
36
|
tools: List[BaseTool] = []
|
|
20
|
-
toolkit_max_length: int = 0
|
|
21
37
|
|
|
22
38
|
@staticmethod
|
|
23
39
|
def toolkit_config_schema() -> BaseModel:
|
|
24
40
|
selected_tools = {x['name']: x['args_schema'].schema() for x in TestPlanApiWrapper.model_construct().get_available_tools()}
|
|
25
|
-
AzureDevOpsPlansToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
26
41
|
m = create_model(
|
|
27
42
|
name_alias,
|
|
28
|
-
name=(str, Field(description="Toolkit name", json_schema_extra={'toolkit_name': True, 'max_toolkit_length': AzureDevOpsPlansToolkit.toolkit_max_length})),
|
|
29
43
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
30
44
|
limit=(Optional[int], Field(description="ADO plans limit used for limitation of the list with results", default=5)),
|
|
31
45
|
# indexer settings
|
|
@@ -79,6 +93,7 @@ class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
|
79
93
|
return m
|
|
80
94
|
|
|
81
95
|
@classmethod
|
|
96
|
+
@filter_missconfigured_index_tools
|
|
82
97
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
83
98
|
from os import environ
|
|
84
99
|
if not environ.get('AZURE_DEVOPS_CACHE_DIR', None):
|
|
@@ -94,17 +109,21 @@ class AzureDevOpsPlansToolkit(BaseToolkit):
|
|
|
94
109
|
azure_devops_api_wrapper = TestPlanApiWrapper(**wrapper_payload)
|
|
95
110
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
96
111
|
tools = []
|
|
97
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
98
112
|
for tool in available_tools:
|
|
99
113
|
if selected_tools:
|
|
100
114
|
if tool["name"] not in selected_tools:
|
|
101
115
|
continue
|
|
102
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]
|
|
103
121
|
tools.append(BaseAction(
|
|
104
122
|
api_wrapper=azure_devops_api_wrapper,
|
|
105
|
-
name=
|
|
106
|
-
description=
|
|
107
|
-
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"]}
|
|
108
127
|
))
|
|
109
128
|
return cls(tools=tools)
|
|
110
129
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
+
import re
|
|
3
4
|
import xml.etree.ElementTree as ET
|
|
4
|
-
from typing import Generator, Optional
|
|
5
|
+
from typing import Generator, Literal, Optional, List
|
|
5
6
|
|
|
6
7
|
from azure.devops.connection import Connection
|
|
7
8
|
from azure.devops.v7_0.test_plan.models import TestPlanCreateParams, TestSuiteCreateParams, \
|
|
@@ -14,12 +15,9 @@ from pydantic import create_model, PrivateAttr, model_validator, SecretStr
|
|
|
14
15
|
from pydantic.fields import FieldInfo as Field
|
|
15
16
|
|
|
16
17
|
from ..work_item import AzureDevOpsApiWrapper
|
|
17
|
-
from ...
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from alita_sdk.runtime.langchain.interfaces.llm_processor import get_embeddings
|
|
21
|
-
except ImportError:
|
|
22
|
-
from alita_sdk.langchain.interfaces.llm_processor import get_embeddings
|
|
18
|
+
from ...non_code_indexer_toolkit import NonCodeIndexerToolkit
|
|
19
|
+
from ...utils.available_tools_decorator import extend_with_parent_available_tools
|
|
20
|
+
from ....runtime.utils.utils import IndexerKeywords
|
|
23
21
|
|
|
24
22
|
logger = logging.getLogger(__name__)
|
|
25
23
|
|
|
@@ -163,7 +161,7 @@ TestCasesGetModel = create_model(
|
|
|
163
161
|
suite_id=(int, Field(description="ID of the test suite for which test cases are requested"))
|
|
164
162
|
)
|
|
165
163
|
|
|
166
|
-
class TestPlanApiWrapper(
|
|
164
|
+
class TestPlanApiWrapper(NonCodeIndexerToolkit):
|
|
167
165
|
# TODO use ado_configuration instead of organization_url, project and token
|
|
168
166
|
__test__ = False
|
|
169
167
|
organization_url: str
|
|
@@ -183,7 +181,7 @@ class TestPlanApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
183
181
|
cls._client = connection.clients.get_test_plan_client()
|
|
184
182
|
except Exception as e:
|
|
185
183
|
raise ImportError(f"Failed to connect to Azure DevOps: {e}")
|
|
186
|
-
return values
|
|
184
|
+
return super().validate_toolkit(values)
|
|
187
185
|
|
|
188
186
|
def create_test_plan(self, test_plan_create_params: str):
|
|
189
187
|
"""Create a test plan in Azure DevOps."""
|
|
@@ -280,7 +278,7 @@ class TestPlanApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
280
278
|
test_steps_format: str = 'json'):
|
|
281
279
|
"""Creates a new test case in specified suite in Azure DevOps."""
|
|
282
280
|
work_item_wrapper = AzureDevOpsApiWrapper(organization_url=self.organization_url,
|
|
283
|
-
token=self.token.get_secret_value(), project=self.project)
|
|
281
|
+
token=self.token.get_secret_value(), project=self.project, llm=self.llm)
|
|
284
282
|
if test_steps_format == 'json':
|
|
285
283
|
steps_xml = self.get_test_steps_xml(json.loads(test_steps))
|
|
286
284
|
elif test_steps_format == 'xml':
|
|
@@ -362,40 +360,70 @@ class TestPlanApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
362
360
|
test_cases = self._client.get_test_case_list(self.project, plan_id, suite_id)
|
|
363
361
|
return [test_case.as_dict() for test_case in test_cases]
|
|
364
362
|
except Exception as e:
|
|
363
|
+
self._log_tool_event(f"Error getting test cases: {e}", 'get_test_cases')
|
|
365
364
|
logger.error(f"Error getting test cases: {e}")
|
|
366
365
|
return ToolException(f"Error getting test cases: {e}")
|
|
367
366
|
|
|
368
|
-
def
|
|
367
|
+
def get_suites_in_plan(self, plan_id: int) -> List[dict]:
|
|
368
|
+
"""Get all test suites in a test plan."""
|
|
369
|
+
try:
|
|
370
|
+
test_suites = self._client.get_test_suites_for_plan(self.project, plan_id)
|
|
371
|
+
return [suite.as_dict() for suite in test_suites]
|
|
372
|
+
except Exception as e:
|
|
373
|
+
logger.error(f"Error getting test suites: {e}")
|
|
374
|
+
return ToolException(f"Error getting test suites: {e}")
|
|
375
|
+
|
|
376
|
+
def _base_loader(self, plan_id: int, suite_ids: Optional[List[int]] = [], chunking_tool: str = None, **kwargs) -> Generator[Document, None, None]:
|
|
369
377
|
cases = []
|
|
378
|
+
if not suite_ids:
|
|
379
|
+
suites = self.get_suites_in_plan(plan_id)
|
|
380
|
+
suite_ids = [suite['id'] for suite in suites if 'id' in suite]
|
|
370
381
|
for sid in suite_ids:
|
|
371
382
|
cases.extend(self.get_test_cases(plan_id, sid))
|
|
372
383
|
#
|
|
373
384
|
for case in cases:
|
|
374
385
|
field_dicts = case.get('work_item', {}).get('work_item_fields', [])
|
|
375
386
|
data = {k: v for d in field_dicts for k, v in d.items()}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
'
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
387
|
+
if chunking_tool:
|
|
388
|
+
steps = data.get('Microsoft.VSTS.TCM.Steps', '')
|
|
389
|
+
# Remove XML declaration if present (like <?xml version="1.0" encoding="utf-16"?>) to avoid encoding issues
|
|
390
|
+
steps_no_decl = re.sub(r'<\?xml[^>]*\?>', '', steps, count=1).lstrip()
|
|
391
|
+
|
|
392
|
+
yield Document(
|
|
393
|
+
page_content='',
|
|
394
|
+
metadata={
|
|
395
|
+
'id': case.get('work_item', {}).get('id', ''),
|
|
396
|
+
'title': case.get('work_item', {}).get('name', ''),
|
|
397
|
+
'plan_id': case.get('test_plan', {}).get('id', ''),
|
|
398
|
+
'suite_id': case.get('test_suite', {}).get('id', ''),
|
|
399
|
+
'description': data.get('System.Description', ''),
|
|
400
|
+
'updated_on': data.get('System.Rev', ''),
|
|
401
|
+
# content is in metadata for chunking tool post-processing
|
|
402
|
+
IndexerKeywords.CONTENT_IN_BYTES.value: steps_no_decl.encode("utf-8")
|
|
403
|
+
})
|
|
404
|
+
else:
|
|
405
|
+
yield Document(
|
|
406
|
+
page_content=data.get('Microsoft.VSTS.TCM.Steps', ''),
|
|
407
|
+
metadata={
|
|
408
|
+
'id': case.get('work_item', {}).get('id', ''),
|
|
409
|
+
'title': case.get('work_item', {}).get('name', ''),
|
|
410
|
+
'plan_id': case.get('test_plan', {}).get('id', ''),
|
|
411
|
+
'suite_id': case.get('test_suite', {}).get('id', ''),
|
|
412
|
+
'description': data.get('System.Description', ''),
|
|
413
|
+
'updated_on': data.get('System.Rev', ''),
|
|
414
|
+
})
|
|
390
415
|
|
|
391
416
|
def _index_tool_params(self):
|
|
392
417
|
"""Return the parameters for indexing data."""
|
|
393
418
|
return {
|
|
394
|
-
|
|
395
|
-
"
|
|
419
|
+
'chunking_tool': (Literal['xml', ''], Field(description="Name of chunking tool", default='xml')),
|
|
420
|
+
"plan_id": (int, Field(description="ID of the test plan for which test cases are requested")),
|
|
421
|
+
"suite_ids": (Optional[List[int]], Field(description='List of test suite IDs for which test cases are requested '
|
|
422
|
+
'(can be empty for all suites indexing from the plan). '
|
|
423
|
+
'Example: [2, 23]', default=[])),
|
|
396
424
|
}
|
|
397
425
|
|
|
398
|
-
@
|
|
426
|
+
@extend_with_parent_available_tools
|
|
399
427
|
def get_available_tools(self):
|
|
400
428
|
"""Return a list of available tools."""
|
|
401
429
|
return [
|
|
@@ -4,29 +4,40 @@ from langchain_core.tools import BaseTool, BaseToolkit
|
|
|
4
4
|
from pydantic import create_model, BaseModel, Field
|
|
5
5
|
|
|
6
6
|
import requests
|
|
7
|
+
|
|
8
|
+
from ...elitea_base import filter_missconfigured_index_tools
|
|
7
9
|
from ....configurations.ado import AdoConfiguration
|
|
8
10
|
from ....configurations.pgvector import PgVectorConfiguration
|
|
9
11
|
from ...base.tool import BaseAction
|
|
10
|
-
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
|
|
11
14
|
|
|
12
15
|
name = "azure_devops_wiki"
|
|
13
16
|
name_alias = 'ado_wiki'
|
|
14
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
|
+
|
|
15
33
|
class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
16
34
|
tools: List[BaseTool] = []
|
|
17
|
-
toolkit_max_length: int = 0
|
|
18
35
|
|
|
19
36
|
@staticmethod
|
|
20
37
|
def toolkit_config_schema() -> BaseModel:
|
|
21
38
|
selected_tools = {x['name']: x['args_schema'].schema() for x in AzureDevOpsApiWrapper.model_construct().get_available_tools()}
|
|
22
|
-
AzureDevOpsWikiToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
23
39
|
m = create_model(
|
|
24
40
|
name_alias,
|
|
25
|
-
name=(str, Field(description="Toolkit name",
|
|
26
|
-
json_schema_extra={
|
|
27
|
-
'toolkit_name': True,
|
|
28
|
-
'max_toolkit_length': AzureDevOpsWikiToolkit.toolkit_max_length})
|
|
29
|
-
),
|
|
30
41
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
31
42
|
# indexer settings
|
|
32
43
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None,
|
|
@@ -77,6 +88,7 @@ class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
|
77
88
|
return m
|
|
78
89
|
|
|
79
90
|
@classmethod
|
|
91
|
+
@filter_missconfigured_index_tools
|
|
80
92
|
def get_toolkit(cls, selected_tools: list[str] | None = None, toolkit_name: Optional[str] = None, **kwargs):
|
|
81
93
|
from os import environ
|
|
82
94
|
if not environ.get('AZURE_DEVOPS_CACHE_DIR', None):
|
|
@@ -92,16 +104,20 @@ class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
|
92
104
|
azure_devops_api_wrapper = AzureDevOpsApiWrapper(**wrapper_payload)
|
|
93
105
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
94
106
|
tools = []
|
|
95
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
96
107
|
for tool in available_tools:
|
|
97
108
|
if selected_tools:
|
|
98
109
|
if tool["name"] not in selected_tools:
|
|
99
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]
|
|
100
115
|
tools.append(BaseAction(
|
|
101
116
|
api_wrapper=azure_devops_api_wrapper,
|
|
102
|
-
name=
|
|
103
|
-
description=
|
|
104
|
-
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"]}
|
|
105
121
|
))
|
|
106
122
|
return cls(tools=tools)
|
|
107
123
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import logging
|
|
3
|
-
|
|
3
|
+
import re
|
|
4
|
+
import requests
|
|
5
|
+
from typing import Generator, Literal, Optional
|
|
4
6
|
|
|
5
7
|
from azure.devops.connection import Connection
|
|
6
8
|
from azure.devops.exceptions import AzureDevOpsServiceError
|
|
@@ -15,12 +17,12 @@ from pydantic import create_model, PrivateAttr, SecretStr
|
|
|
15
17
|
from pydantic import model_validator
|
|
16
18
|
from pydantic.fields import Field
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
import alita_sdk.tools.ado.work_item
|
|
21
|
+
from ..repos import ReposApiWrapper
|
|
22
|
+
from ...non_code_indexer_toolkit import NonCodeIndexerToolkit
|
|
23
|
+
from ...utils.available_tools_decorator import extend_with_parent_available_tools
|
|
24
|
+
from ...utils.content_parser import parse_file_content
|
|
25
|
+
from ....runtime.utils.utils import IndexerKeywords
|
|
24
26
|
|
|
25
27
|
logger = logging.getLogger(__name__)
|
|
26
28
|
|
|
@@ -32,13 +34,17 @@ GetWikiInput = create_model(
|
|
|
32
34
|
GetPageByPathInput = create_model(
|
|
33
35
|
"GetPageByPathInput",
|
|
34
36
|
wiki_identified=(str, Field(description="Wiki ID or wiki name")),
|
|
35
|
-
page_name=(str, Field(description="Wiki page path"))
|
|
37
|
+
page_name=(str, Field(description="Wiki page path")),
|
|
38
|
+
image_description_prompt=(Optional[str],
|
|
39
|
+
Field(description="Prompt which is used for image description", default=None))
|
|
36
40
|
)
|
|
37
41
|
|
|
38
42
|
GetPageByIdInput = create_model(
|
|
39
43
|
"GetPageByIdInput",
|
|
40
44
|
wiki_identified=(str, Field(description="Wiki ID or wiki name")),
|
|
41
|
-
page_id=(int, Field(description="Wiki page ID"))
|
|
45
|
+
page_id=(int, Field(description="Wiki page ID")),
|
|
46
|
+
image_description_prompt=(Optional[str],
|
|
47
|
+
Field(description="Prompt which is used for image description", default=None))
|
|
42
48
|
)
|
|
43
49
|
|
|
44
50
|
ModifyPageInput = create_model(
|
|
@@ -46,8 +52,9 @@ ModifyPageInput = create_model(
|
|
|
46
52
|
wiki_identified=(str, Field(description="Wiki ID or wiki name")),
|
|
47
53
|
page_name=(str, Field(description="Wiki page name")),
|
|
48
54
|
page_content=(str, Field(description="Wiki page content")),
|
|
49
|
-
version_identifier=(str, Field(description="Version string identifier (name of tag/branch, SHA1 of commit)")),
|
|
50
|
-
version_type=(Optional[str], Field(description="Version type (branch, tag, or commit). Determines how Id is interpreted", default="branch"))
|
|
55
|
+
version_identifier=(str, Field(description="Version string identifier (name of tag/branch, SHA1 of commit). Usually for wiki the branch is 'wikiMaster'")),
|
|
56
|
+
version_type=(Optional[str], Field(description="Version type (branch, tag, or commit). Determines how Id is interpreted", default="branch")),
|
|
57
|
+
expanded=(Optional[bool], Field(description="Whether to return the full page object or just its simplified version.", default=False))
|
|
51
58
|
)
|
|
52
59
|
|
|
53
60
|
RenamePageInput = create_model(
|
|
@@ -60,7 +67,20 @@ RenamePageInput = create_model(
|
|
|
60
67
|
)
|
|
61
68
|
|
|
62
69
|
|
|
63
|
-
|
|
70
|
+
def _format_wiki_page_response(wiki_page_response, expanded: bool = False):
|
|
71
|
+
"""Format wiki page response."""
|
|
72
|
+
try:
|
|
73
|
+
return {
|
|
74
|
+
'eTag': wiki_page_response.eTag,
|
|
75
|
+
'page': wiki_page_response.page.__dict__ if wiki_page_response.page else None
|
|
76
|
+
} if expanded else {"eTag": wiki_page_response.eTag, "id": wiki_page_response.page.id,
|
|
77
|
+
"page": wiki_page_response.page.url}
|
|
78
|
+
except:
|
|
79
|
+
logger.error(f"Unable to format wiki page response: {wiki_page_response}")
|
|
80
|
+
return wiki_page_response
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
64
84
|
# TODO use ado_configuration instead of organization_url, project and token
|
|
65
85
|
organization_url: str
|
|
66
86
|
project: str
|
|
@@ -68,13 +88,6 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
68
88
|
_client: Optional[WikiClient] = PrivateAttr() # Private attribute for the wiki client
|
|
69
89
|
_core_client: Optional[CoreClient] = PrivateAttr() # Private attribute for the CoreClient client
|
|
70
90
|
|
|
71
|
-
llm: Any = None
|
|
72
|
-
connection_string: Optional[SecretStr] = None
|
|
73
|
-
collection_name: Optional[str] = None
|
|
74
|
-
embedding_model: Optional[str] = "HuggingFaceEmbeddings"
|
|
75
|
-
embedding_model_params: Optional[Dict[str, Any]] = {"model_name": "sentence-transformers/all-MiniLM-L6-v2"}
|
|
76
|
-
vectorstore_type: Optional[str] = "PGVector"
|
|
77
|
-
|
|
78
91
|
class Config:
|
|
79
92
|
arbitrary_types_allowed = True # Allow arbitrary types (e.g., WorkItemTrackingClient)
|
|
80
93
|
|
|
@@ -94,7 +107,7 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
94
107
|
except Exception as e:
|
|
95
108
|
return ImportError(f"Failed to connect to Azure DevOps: {e}")
|
|
96
109
|
|
|
97
|
-
return values
|
|
110
|
+
return super().validate_toolkit(values)
|
|
98
111
|
|
|
99
112
|
def get_wiki(self, wiki_identified: str):
|
|
100
113
|
"""Extract ADO wiki information."""
|
|
@@ -104,24 +117,75 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
104
117
|
logger.error(f"Error during the attempt to extract wiki: {str(e)}")
|
|
105
118
|
return ToolException(f"Error during the attempt to extract wiki: {str(e)}")
|
|
106
119
|
|
|
107
|
-
def get_wiki_page_by_path(self, wiki_identified: str, page_name: str):
|
|
120
|
+
def get_wiki_page_by_path(self, wiki_identified: str, page_name: str, image_description_prompt=None):
|
|
108
121
|
"""Extract ADO wiki page content."""
|
|
109
122
|
try:
|
|
110
|
-
return self._client.get_page(project=self.project, wiki_identifier=wiki_identified, path=page_name,
|
|
111
|
-
include_content=True).page.content
|
|
123
|
+
return self._process_images(self._client.get_page(project=self.project, wiki_identifier=wiki_identified, path=page_name,
|
|
124
|
+
include_content=True).page.content,
|
|
125
|
+
image_description_prompt=image_description_prompt)
|
|
112
126
|
except Exception as e:
|
|
113
127
|
logger.error(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
114
128
|
return ToolException(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
115
129
|
|
|
116
|
-
def get_wiki_page_by_id(self, wiki_identified: str, page_id: int):
|
|
130
|
+
def get_wiki_page_by_id(self, wiki_identified: str, page_id: int, image_description_prompt=None):
|
|
117
131
|
"""Extract ADO wiki page content."""
|
|
118
132
|
try:
|
|
119
|
-
return (self._client.get_page_by_id(project=self.project, wiki_identifier=wiki_identified, id=page_id,
|
|
120
|
-
include_content=True).page.content
|
|
133
|
+
return self._process_images(self._client.get_page_by_id(project=self.project, wiki_identifier=wiki_identified, id=page_id,
|
|
134
|
+
include_content=True).page.content,
|
|
135
|
+
image_description_prompt=image_description_prompt)
|
|
121
136
|
except Exception as e:
|
|
122
137
|
logger.error(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
123
138
|
return ToolException(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
124
139
|
|
|
140
|
+
def _process_images(self, page_content: str, image_description_prompt=None):
|
|
141
|
+
|
|
142
|
+
image_pattern = r"!\[(.*?)\]\((.*?)\)"
|
|
143
|
+
matches = re.findall(image_pattern, page_content)
|
|
144
|
+
|
|
145
|
+
for image_name, image_url in matches:
|
|
146
|
+
if image_url.startswith("/.attachments/"):
|
|
147
|
+
try:
|
|
148
|
+
description = self.process_attachment(attachment_url=image_url,
|
|
149
|
+
attachment_name=image_name,
|
|
150
|
+
image_description_prompt=image_description_prompt)
|
|
151
|
+
except Exception as e:
|
|
152
|
+
logger.error(f"Error parsing attachment: {str(e)}")
|
|
153
|
+
description = f"Error parsing attachment: {image_url}"
|
|
154
|
+
else:
|
|
155
|
+
try:
|
|
156
|
+
response = requests.get(image_url)
|
|
157
|
+
response.raise_for_status()
|
|
158
|
+
file_content = response.content
|
|
159
|
+
description = parse_file_content(
|
|
160
|
+
file_content=file_content,
|
|
161
|
+
file_name="image.png",
|
|
162
|
+
llm=self.llm,
|
|
163
|
+
prompt=image_description_prompt
|
|
164
|
+
)
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.error(f"Error fetching external image: {str(e)}")
|
|
167
|
+
description = f"Error fetching external image: image_url"
|
|
168
|
+
|
|
169
|
+
new_image_markdown = f""
|
|
170
|
+
page_content = page_content.replace(f"", new_image_markdown)
|
|
171
|
+
return page_content
|
|
172
|
+
|
|
173
|
+
def process_attachment(self, attachment_url, attachment_name, image_description_prompt):
|
|
174
|
+
wiki_master_branch = "wikiMaster"
|
|
175
|
+
repos_wrapper = ReposApiWrapper(organization_url=self.organization_url,
|
|
176
|
+
project=self.project,
|
|
177
|
+
token=self.token.get_secret_value(),
|
|
178
|
+
repository_id="Test_agent.wiki",
|
|
179
|
+
base_branch=wiki_master_branch,
|
|
180
|
+
active_branch=wiki_master_branch)
|
|
181
|
+
attachment_content = repos_wrapper.download_file(path=attachment_url)
|
|
182
|
+
return parse_file_content(
|
|
183
|
+
file_content=attachment_content,
|
|
184
|
+
file_name=attachment_name,
|
|
185
|
+
llm=self.llm,
|
|
186
|
+
prompt=image_description_prompt
|
|
187
|
+
)
|
|
188
|
+
|
|
125
189
|
def delete_page_by_path(self, wiki_identified: str, page_name: str):
|
|
126
190
|
"""Extract ADO wiki page content."""
|
|
127
191
|
try:
|
|
@@ -176,7 +240,7 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
176
240
|
logger.error(f"Unable to rename wiki page: {str(e)}")
|
|
177
241
|
return ToolException(f"Unable to rename wiki page: {str(e)}")
|
|
178
242
|
|
|
179
|
-
def modify_wiki_page(self, wiki_identified: str, page_name: str, page_content: str, version_identifier: str, version_type: str = "branch"):
|
|
243
|
+
def modify_wiki_page(self, wiki_identified: str, page_name: str, page_content: str, version_identifier: str, version_type: str = "branch", expanded: Optional[bool] = False):
|
|
180
244
|
"""Create or Update ADO wiki page content."""
|
|
181
245
|
try:
|
|
182
246
|
all_wikis = [wiki.name for wiki in self._client.get_all_wikis(project=self.project)]
|
|
@@ -207,31 +271,31 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
207
271
|
return ToolException(f"Unable to extract page by path {page_name}: {str(get_page_e)}")
|
|
208
272
|
|
|
209
273
|
try:
|
|
210
|
-
return self._client.create_or_update_page(
|
|
274
|
+
return _format_wiki_page_response(self._client.create_or_update_page(
|
|
211
275
|
project=self.project,
|
|
212
276
|
wiki_identifier=wiki_identified,
|
|
213
277
|
path=page_name,
|
|
214
278
|
parameters=WikiPageCreateOrUpdateParameters(content=page_content),
|
|
215
279
|
version=version,
|
|
216
280
|
version_descriptor=GitVersionDescriptor(version=version_identifier, version_type=version_type)
|
|
217
|
-
)
|
|
281
|
+
), expanded=expanded)
|
|
218
282
|
except AzureDevOpsServiceError as e:
|
|
219
283
|
if "The version '{0}' either is invalid or does not exist." in str(e):
|
|
220
284
|
# Retry the request without version_descriptor
|
|
221
|
-
return self._client.create_or_update_page(
|
|
285
|
+
return _format_wiki_page_response(wiki_page_response=self._client.create_or_update_page(
|
|
222
286
|
project=self.project,
|
|
223
287
|
wiki_identifier=wiki_identified,
|
|
224
288
|
path=page_name,
|
|
225
289
|
parameters=WikiPageCreateOrUpdateParameters(content=page_content),
|
|
226
290
|
version=version
|
|
227
|
-
)
|
|
291
|
+
), expanded=expanded)
|
|
228
292
|
else:
|
|
229
293
|
raise
|
|
230
294
|
except Exception as e:
|
|
231
295
|
logger.error(f"Unable to modify wiki page: {str(e)}")
|
|
232
296
|
return ToolException(f"Unable to modify wiki page: {str(e)}")
|
|
233
297
|
|
|
234
|
-
def _base_loader(self, wiki_identifier: str, title_contains: Optional[str] = None, **kwargs) -> Generator[Document, None, None]:
|
|
298
|
+
def _base_loader(self, wiki_identifier: str, chunking_tool: str = None, title_contains: Optional[str] = None, **kwargs) -> Generator[Document, None, None]:
|
|
235
299
|
pages = self._client.get_pages_batch(pages_batch_request={}, project=self.project, wiki_identifier=wiki_identifier)
|
|
236
300
|
#
|
|
237
301
|
for page in pages:
|
|
@@ -239,21 +303,31 @@ class AzureDevOpsApiWrapper(BaseVectorStoreToolApiWrapper):
|
|
|
239
303
|
content_hash = hashlib.sha256(content.encode("utf-8")).hexdigest()
|
|
240
304
|
title = page.path.rsplit("/", 1)[-1]
|
|
241
305
|
if not title_contains or (title_contains and title_contains.lower() in title.lower()):
|
|
242
|
-
|
|
243
|
-
'
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
306
|
+
if chunking_tool:
|
|
307
|
+
yield Document(page_content='', metadata={
|
|
308
|
+
'id': str(page.id),
|
|
309
|
+
'path': page.path,
|
|
310
|
+
'title': title,
|
|
311
|
+
'updated_on': content_hash,
|
|
312
|
+
IndexerKeywords.CONTENT_IN_BYTES.value: content.encode("utf-8")
|
|
313
|
+
})
|
|
314
|
+
else:
|
|
315
|
+
yield Document(page_content=content, metadata={
|
|
316
|
+
'id': str(page.id),
|
|
317
|
+
'path': page.path,
|
|
318
|
+
'title': title,
|
|
319
|
+
'updated_on': content_hash
|
|
320
|
+
})
|
|
248
321
|
|
|
249
322
|
def _index_tool_params(self):
|
|
250
323
|
"""Return the parameters for indexing data."""
|
|
251
324
|
return {
|
|
325
|
+
'chunking_tool': (Literal['markdown', ''], Field(description="Name of chunking tool", default='markdown')),
|
|
252
326
|
"wiki_identifier": (str, Field(description="Wiki identifier to index, e.g., 'ABCProject.wiki'")),
|
|
253
|
-
'title_contains': (Optional[str], Field(default=None, description="Optional filter to include only pages with titles containing exact this string"))
|
|
327
|
+
'title_contains': (Optional[str], Field(default=None, description="Optional filter to include only pages with titles containing exact this string")),
|
|
254
328
|
}
|
|
255
329
|
|
|
256
|
-
@
|
|
330
|
+
@extend_with_parent_available_tools
|
|
257
331
|
def get_available_tools(self):
|
|
258
332
|
"""Return a list of available tools."""
|
|
259
333
|
return [
|