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
|
@@ -9,26 +9,35 @@ 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
|
-
name=(str, Field(description="Toolkit name",
|
|
28
|
-
json_schema_extra={
|
|
29
|
-
'toolkit_name': True,
|
|
30
|
-
'max_toolkit_length': AzureDevOpsWikiToolkit.toolkit_max_length})
|
|
31
|
-
),
|
|
32
41
|
ado_configuration=(AdoConfiguration, Field(description="Ado configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
33
42
|
# indexer settings
|
|
34
43
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default=None,
|
|
@@ -95,16 +104,20 @@ class AzureDevOpsWikiToolkit(BaseToolkit):
|
|
|
95
104
|
azure_devops_api_wrapper = AzureDevOpsApiWrapper(**wrapper_payload)
|
|
96
105
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
97
106
|
tools = []
|
|
98
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
99
107
|
for tool in available_tools:
|
|
100
108
|
if selected_tools:
|
|
101
109
|
if tool["name"] not in selected_tools:
|
|
102
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]
|
|
103
115
|
tools.append(BaseAction(
|
|
104
116
|
api_wrapper=azure_devops_api_wrapper,
|
|
105
|
-
name=
|
|
106
|
-
description=
|
|
107
|
-
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"]}
|
|
108
121
|
))
|
|
109
122
|
return cls(tools=tools)
|
|
110
123
|
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import re
|
|
4
4
|
import requests
|
|
5
5
|
from typing import Generator, Literal, Optional
|
|
6
|
+
from urllib.parse import unquote
|
|
6
7
|
|
|
7
8
|
from azure.devops.connection import Connection
|
|
8
9
|
from azure.devops.exceptions import AzureDevOpsServiceError
|
|
@@ -13,7 +14,7 @@ from azure.devops.v7_0.wiki.models import GitVersionDescriptor
|
|
|
13
14
|
from langchain_core.documents import Document
|
|
14
15
|
from langchain_core.tools import ToolException
|
|
15
16
|
from msrest.authentication import BasicAuthentication
|
|
16
|
-
from pydantic import create_model, PrivateAttr, SecretStr
|
|
17
|
+
from pydantic import create_model, PrivateAttr, SecretStr, BaseModel
|
|
17
18
|
from pydantic import model_validator
|
|
18
19
|
from pydantic.fields import Field
|
|
19
20
|
|
|
@@ -47,13 +48,35 @@ GetPageByIdInput = create_model(
|
|
|
47
48
|
Field(description="Prompt which is used for image description", default=None))
|
|
48
49
|
)
|
|
49
50
|
|
|
51
|
+
|
|
52
|
+
class GetPageInput(BaseModel):
|
|
53
|
+
"""Input schema for get_wiki_page tool with validation."""
|
|
54
|
+
wiki_identified: str = Field(description="Wiki ID or wiki name")
|
|
55
|
+
page_path: Optional[str] = Field(default=None, description="Wiki page path (e.g., '/MB_Heading/MB_2')")
|
|
56
|
+
page_id: Optional[int] = Field(default=None, description="Wiki page ID")
|
|
57
|
+
include_content: Optional[bool] = Field(default=False, description="Whether to include page content in the response. If True, content will be processed for image descriptions.")
|
|
58
|
+
image_description_prompt: Optional[str] = Field(default=None, description="Prompt which is used for image description when include_content is True")
|
|
59
|
+
recursion_level: Optional[str] = Field(default="oneLevel", description="Level of recursion to retrieve sub-pages. Options: 'none' (no subpages), 'oneLevel' (direct children only), 'full' (all descendants). Defaults to 'oneLevel'.")
|
|
60
|
+
|
|
61
|
+
@model_validator(mode='before')
|
|
62
|
+
@classmethod
|
|
63
|
+
def validate_inputs(cls, values):
|
|
64
|
+
"""Validator to ensure at least one of page_path or page_id is provided."""
|
|
65
|
+
page_path = values.get('page_path')
|
|
66
|
+
page_id = values.get('page_id')
|
|
67
|
+
if not page_path and not page_id:
|
|
68
|
+
raise ValueError("At least one of 'page_path' or 'page_id' must be provided")
|
|
69
|
+
return values
|
|
70
|
+
|
|
71
|
+
|
|
50
72
|
ModifyPageInput = create_model(
|
|
51
73
|
"ModifyPageInput",
|
|
52
74
|
wiki_identified=(str, Field(description="Wiki ID or wiki name")),
|
|
53
75
|
page_name=(str, Field(description="Wiki page name")),
|
|
54
76
|
page_content=(str, Field(description="Wiki page content")),
|
|
55
|
-
version_identifier=(str, Field(description="Version string identifier (name of tag/branch, SHA1 of commit)")),
|
|
56
|
-
version_type=(Optional[str], Field(description="Version type (branch, tag, or commit). Determines how Id is interpreted", default="branch"))
|
|
77
|
+
version_identifier=(str, Field(description="Version string identifier (name of tag/branch, SHA1 of commit). Usually for wiki the branch is 'wikiMaster'")),
|
|
78
|
+
version_type=(Optional[str], Field(description="Version type (branch, tag, or commit). Determines how Id is interpreted", default="branch")),
|
|
79
|
+
expanded=(Optional[bool], Field(description="Whether to return the full page object or just its simplified version.", default=False))
|
|
57
80
|
)
|
|
58
81
|
|
|
59
82
|
RenamePageInput = create_model(
|
|
@@ -66,6 +89,76 @@ RenamePageInput = create_model(
|
|
|
66
89
|
)
|
|
67
90
|
|
|
68
91
|
|
|
92
|
+
def _format_wiki_page_response(wiki_page_response, expanded: bool = False, include_content: bool = False):
|
|
93
|
+
"""Format wiki page response.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
wiki_page_response: The WikiPageResponse object from Azure DevOps API
|
|
97
|
+
expanded: If True, returns comprehensive page metadata. If False, returns simplified format.
|
|
98
|
+
include_content: If True and expanded=True, includes the page content in the response.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Dictionary with eTag and page information. Format depends on expanded parameter.
|
|
102
|
+
"""
|
|
103
|
+
try:
|
|
104
|
+
if expanded:
|
|
105
|
+
# Comprehensive metadata format
|
|
106
|
+
page = wiki_page_response.page
|
|
107
|
+
|
|
108
|
+
# Process sub_pages if present
|
|
109
|
+
sub_pages = []
|
|
110
|
+
if page and hasattr(page, 'sub_pages') and page.sub_pages:
|
|
111
|
+
for sub_page in page.sub_pages:
|
|
112
|
+
sub_page_dict = {
|
|
113
|
+
'id': sub_page.id if hasattr(sub_page, 'id') else None,
|
|
114
|
+
'path': sub_page.path if hasattr(sub_page, 'path') else None,
|
|
115
|
+
'order': sub_page.order if hasattr(sub_page, 'order') else None,
|
|
116
|
+
'git_item_path': sub_page.git_item_path if hasattr(sub_page, 'git_item_path') else None,
|
|
117
|
+
'url': sub_page.url if hasattr(sub_page, 'url') else None,
|
|
118
|
+
'remote_url': sub_page.remote_url if hasattr(sub_page, 'remote_url') else None,
|
|
119
|
+
}
|
|
120
|
+
# Recursively process nested sub_pages if present
|
|
121
|
+
if hasattr(sub_page, 'sub_pages') and sub_page.sub_pages:
|
|
122
|
+
sub_page_dict['sub_pages'] = [
|
|
123
|
+
{
|
|
124
|
+
'id': sp.id if hasattr(sp, 'id') else None,
|
|
125
|
+
'path': sp.path if hasattr(sp, 'path') else None,
|
|
126
|
+
'order': sp.order if hasattr(sp, 'order') else None,
|
|
127
|
+
}
|
|
128
|
+
for sp in sub_page.sub_pages
|
|
129
|
+
]
|
|
130
|
+
sub_pages.append(sub_page_dict)
|
|
131
|
+
|
|
132
|
+
result = {
|
|
133
|
+
'eTag': wiki_page_response.eTag,
|
|
134
|
+
'page': {
|
|
135
|
+
'id': page.id if page else None,
|
|
136
|
+
'path': page.path if page else None,
|
|
137
|
+
'git_item_path': page.git_item_path if page and hasattr(page, 'git_item_path') else None,
|
|
138
|
+
'remote_url': page.remote_url if page and hasattr(page, 'remote_url') else None,
|
|
139
|
+
'url': page.url if page else None,
|
|
140
|
+
'order': page.order if page and hasattr(page, 'order') else None,
|
|
141
|
+
'is_parent_page': page.is_parent_page if page and hasattr(page, 'is_parent_page') else None,
|
|
142
|
+
'is_non_conformant': page.is_non_conformant if page and hasattr(page, 'is_non_conformant') else None,
|
|
143
|
+
'sub_pages': sub_pages,
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
# Include content if requested
|
|
147
|
+
if include_content and page and hasattr(page, 'content'):
|
|
148
|
+
result['page']['content'] = page.content
|
|
149
|
+
return result
|
|
150
|
+
else:
|
|
151
|
+
# Simplified format for backward compatibility
|
|
152
|
+
return {
|
|
153
|
+
"eTag": wiki_page_response.eTag,
|
|
154
|
+
"id": wiki_page_response.page.id,
|
|
155
|
+
"page": wiki_page_response.page.url
|
|
156
|
+
}
|
|
157
|
+
except Exception as e:
|
|
158
|
+
logger.error(f"Unable to format wiki page response: {wiki_page_response}, error: {str(e)}")
|
|
159
|
+
return wiki_page_response
|
|
160
|
+
|
|
161
|
+
|
|
69
162
|
class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
70
163
|
# TODO use ado_configuration instead of organization_url, project and token
|
|
71
164
|
organization_url: str
|
|
@@ -91,7 +184,29 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
91
184
|
cls._core_client = connection.clients.get_core_client()
|
|
92
185
|
|
|
93
186
|
except Exception as e:
|
|
94
|
-
|
|
187
|
+
error_msg = str(e).lower()
|
|
188
|
+
if "expired" in error_msg or "token" in error_msg and ("invalid" in error_msg or "unauthorized" in error_msg):
|
|
189
|
+
raise ValueError(
|
|
190
|
+
"Azure DevOps connection failed: Your access token has expired or is invalid. "
|
|
191
|
+
"Please refresh your token in the toolkit configuration."
|
|
192
|
+
)
|
|
193
|
+
elif "401" in error_msg or "unauthorized" in error_msg:
|
|
194
|
+
raise ValueError(
|
|
195
|
+
"Azure DevOps connection failed: Authentication failed. "
|
|
196
|
+
"Please check your credentials in the toolkit configuration."
|
|
197
|
+
)
|
|
198
|
+
elif "404" in error_msg or "not found" in error_msg:
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"Azure DevOps connection failed: Organization or project not found. "
|
|
201
|
+
"Please verify your organization URL and project name."
|
|
202
|
+
)
|
|
203
|
+
elif "timeout" in error_msg or "timed out" in error_msg:
|
|
204
|
+
raise ValueError(
|
|
205
|
+
"Azure DevOps connection failed: Connection timed out. "
|
|
206
|
+
"Please check your network connection and try again."
|
|
207
|
+
)
|
|
208
|
+
else:
|
|
209
|
+
raise ValueError(f"Azure DevOps connection failed: {e}")
|
|
95
210
|
|
|
96
211
|
return super().validate_toolkit(values)
|
|
97
212
|
|
|
@@ -108,7 +223,7 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
108
223
|
try:
|
|
109
224
|
return self._process_images(self._client.get_page(project=self.project, wiki_identifier=wiki_identified, path=page_name,
|
|
110
225
|
include_content=True).page.content,
|
|
111
|
-
image_description_prompt=image_description_prompt)
|
|
226
|
+
image_description_prompt=image_description_prompt, wiki_identified=wiki_identified)
|
|
112
227
|
except Exception as e:
|
|
113
228
|
logger.error(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
114
229
|
return ToolException(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
@@ -118,22 +233,176 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
118
233
|
try:
|
|
119
234
|
return self._process_images(self._client.get_page_by_id(project=self.project, wiki_identifier=wiki_identified, id=page_id,
|
|
120
235
|
include_content=True).page.content,
|
|
121
|
-
image_description_prompt=image_description_prompt)
|
|
236
|
+
image_description_prompt=image_description_prompt, wiki_identified=wiki_identified)
|
|
122
237
|
except Exception as e:
|
|
123
238
|
logger.error(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
124
239
|
return ToolException(f"Error during the attempt to extract wiki page: {str(e)}")
|
|
125
240
|
|
|
126
|
-
def
|
|
241
|
+
def get_wiki_page(self, wiki_identified: str, page_path: Optional[str] = None, page_id: Optional[int] = None,
|
|
242
|
+
include_content: bool = False, image_description_prompt: Optional[str] = None,
|
|
243
|
+
recursion_level: str = "oneLevel"):
|
|
244
|
+
"""Get wiki page metadata and optionally content.
|
|
245
|
+
|
|
246
|
+
Retrieves comprehensive metadata for a wiki page including eTag, id, path, git_item_path,
|
|
247
|
+
remote_url, url, sub_pages, order, and other properties. Optionally includes page content.
|
|
248
|
+
Supports lookup by either page_id (takes precedence) or page_path.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
wiki_identified: Wiki ID or wiki name
|
|
252
|
+
page_path: Wiki page path (e.g., '/MB_Heading/MB_2'). Optional if page_id is provided.
|
|
253
|
+
page_id: Wiki page ID. Optional if page_path is provided. Takes precedence over page_path.
|
|
254
|
+
include_content: Whether to include page content in response. Defaults to False (metadata only).
|
|
255
|
+
image_description_prompt: Optional prompt for image description when include_content is True.
|
|
256
|
+
recursion_level: Level of recursion to retrieve sub-pages. Options: 'none' (no subpages),
|
|
257
|
+
'oneLevel' (direct children only), 'full' (all descendants). Defaults to 'oneLevel'.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
Dictionary containing eTag and comprehensive page metadata including id, path, git_item_path,
|
|
261
|
+
remote_url, url, sub_pages, order, is_parent_page, is_non_conformant, and optionally content.
|
|
262
|
+
|
|
263
|
+
Raises:
|
|
264
|
+
ToolException: If page/wiki not found, authentication fails, or other errors occur.
|
|
265
|
+
"""
|
|
266
|
+
try:
|
|
267
|
+
# Validate that at least one identifier is provided
|
|
268
|
+
if not page_path and not page_id:
|
|
269
|
+
raise ToolException("At least one of 'page_path' or 'page_id' must be provided")
|
|
270
|
+
|
|
271
|
+
# Fetch page using page_id (priority) or page_path
|
|
272
|
+
if page_id:
|
|
273
|
+
logger.info(f"Fetching wiki page by ID: {page_id} from wiki: {wiki_identified}")
|
|
274
|
+
wiki_page_response = self._client.get_page_by_id(
|
|
275
|
+
project=self.project,
|
|
276
|
+
wiki_identifier=wiki_identified,
|
|
277
|
+
id=page_id,
|
|
278
|
+
include_content=include_content,
|
|
279
|
+
recursion_level=recursion_level
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
logger.info(f"Fetching wiki page by path: {page_path} from wiki: {wiki_identified}")
|
|
283
|
+
wiki_page_response = self._client.get_page(
|
|
284
|
+
project=self.project,
|
|
285
|
+
wiki_identifier=wiki_identified,
|
|
286
|
+
path=page_path,
|
|
287
|
+
include_content=include_content,
|
|
288
|
+
recursion_level=recursion_level
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Format response with comprehensive metadata
|
|
292
|
+
result = _format_wiki_page_response(
|
|
293
|
+
wiki_page_response,
|
|
294
|
+
expanded=True,
|
|
295
|
+
include_content=include_content
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Process images in content if requested
|
|
299
|
+
if include_content and result.get('page', {}).get('content'):
|
|
300
|
+
processed_content = self._process_images(
|
|
301
|
+
result['page']['content'],
|
|
302
|
+
image_description_prompt=image_description_prompt,
|
|
303
|
+
wiki_identified=wiki_identified
|
|
304
|
+
)
|
|
305
|
+
result['page']['content'] = processed_content
|
|
306
|
+
|
|
307
|
+
return result
|
|
308
|
+
|
|
309
|
+
except AzureDevOpsServiceError as e:
|
|
310
|
+
error_msg = str(e).lower()
|
|
311
|
+
|
|
312
|
+
# Page not found errors
|
|
313
|
+
if "404" in error_msg or "not found" in error_msg or "does not exist" in error_msg:
|
|
314
|
+
identifier = f"ID {page_id}" if page_id else f"path '{page_path}'"
|
|
315
|
+
logger.error(f"Page {identifier} not found in wiki '{wiki_identified}': {str(e)}")
|
|
316
|
+
return ToolException(
|
|
317
|
+
f"Page {identifier} not found in wiki '{wiki_identified}'. "
|
|
318
|
+
f"Please verify the page exists and the identifier is correct."
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
# Path validation errors
|
|
322
|
+
elif "path" in error_msg and ("correct" in error_msg or "invalid" in error_msg):
|
|
323
|
+
logger.error(f"Invalid page path '{page_path}' in wiki '{wiki_identified}': {str(e)}")
|
|
324
|
+
return ToolException(
|
|
325
|
+
f"Invalid page path '{page_path}'. Please ensure the path format is correct (e.g., '/PageName')."
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# Wiki not found errors
|
|
329
|
+
elif "wiki" in error_msg and ("not found" in error_msg or "does not exist" in error_msg):
|
|
330
|
+
logger.error(f"Wiki '{wiki_identified}' not found: {str(e)}")
|
|
331
|
+
return ToolException(
|
|
332
|
+
f"Wiki '{wiki_identified}' not found. Please verify the wiki identifier is correct."
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Authentication/authorization errors
|
|
336
|
+
elif "401" in error_msg or "unauthorized" in error_msg or "authentication" in error_msg:
|
|
337
|
+
logger.error(f"Authentication failed for wiki '{wiki_identified}': {str(e)}")
|
|
338
|
+
return ToolException(
|
|
339
|
+
f"Authentication failed. Please check your access token is valid and has permission to access wiki '{wiki_identified}'."
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
elif "403" in error_msg or "forbidden" in error_msg or "permission" in error_msg:
|
|
343
|
+
logger.error(f"Permission denied for wiki '{wiki_identified}': {str(e)}")
|
|
344
|
+
return ToolException(
|
|
345
|
+
f"Permission denied. You do not have access to wiki '{wiki_identified}' or page {page_id if page_id else page_path}."
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
# Generic Azure DevOps service errors
|
|
349
|
+
else:
|
|
350
|
+
logger.error(f"Azure DevOps service error while fetching page: {str(e)}")
|
|
351
|
+
return ToolException(f"Error accessing wiki page: {str(e)}")
|
|
352
|
+
|
|
353
|
+
except ValueError as e:
|
|
354
|
+
logger.error(f"Validation error: {str(e)}")
|
|
355
|
+
return ToolException(f"Validation error: {str(e)}")
|
|
356
|
+
|
|
357
|
+
except Exception as e:
|
|
358
|
+
error_msg = str(e).lower()
|
|
359
|
+
|
|
360
|
+
# Timeout errors
|
|
361
|
+
if "timeout" in error_msg or "timed out" in error_msg:
|
|
362
|
+
logger.error(f"Connection timeout while fetching page: {str(e)}")
|
|
363
|
+
return ToolException(
|
|
364
|
+
f"Connection timeout. Please check your network connection and try again."
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
# Generic errors
|
|
368
|
+
logger.error(f"Unexpected error during wiki page retrieval: {str(e)}")
|
|
369
|
+
return ToolException(f"Unexpected error during wiki page retrieval: {str(e)}")
|
|
370
|
+
|
|
371
|
+
def _process_images(self, page_content: str, wiki_identified: str, image_description_prompt=None):
|
|
127
372
|
|
|
128
373
|
image_pattern = r"!\[(.*?)\]\((.*?)\)"
|
|
129
374
|
matches = re.findall(image_pattern, page_content)
|
|
130
375
|
|
|
376
|
+
# Initialize repos_wrapper once for all attachments in this page
|
|
377
|
+
repos_wrapper = None
|
|
378
|
+
has_attachments = any(url.startswith("/.attachments/") for _, url in matches)
|
|
379
|
+
|
|
380
|
+
if has_attachments:
|
|
381
|
+
try:
|
|
382
|
+
wiki_master_branch = "wikiMaster"
|
|
383
|
+
wiki = self._client.get_wiki(project=self.project, wiki_identifier=wiki_identified)
|
|
384
|
+
repository_id = wiki.repository_id
|
|
385
|
+
repos_wrapper = ReposApiWrapper(
|
|
386
|
+
organization_url=self.organization_url,
|
|
387
|
+
project=self.project,
|
|
388
|
+
token=self.token.get_secret_value(),
|
|
389
|
+
repository_id=repository_id,
|
|
390
|
+
base_branch=wiki_master_branch,
|
|
391
|
+
active_branch=wiki_master_branch,
|
|
392
|
+
llm=self.llm
|
|
393
|
+
)
|
|
394
|
+
except Exception as e:
|
|
395
|
+
logger.error(f"Failed to initialize repos wrapper for wiki '{wiki_identified}': {str(e)}")
|
|
396
|
+
|
|
131
397
|
for image_name, image_url in matches:
|
|
132
398
|
if image_url.startswith("/.attachments/"):
|
|
133
399
|
try:
|
|
400
|
+
if repos_wrapper is None:
|
|
401
|
+
raise Exception("Repos wrapper not initialized")
|
|
134
402
|
description = self.process_attachment(attachment_url=image_url,
|
|
135
403
|
attachment_name=image_name,
|
|
136
|
-
image_description_prompt=image_description_prompt
|
|
404
|
+
image_description_prompt=image_description_prompt,
|
|
405
|
+
repos_wrapper=repos_wrapper)
|
|
137
406
|
except Exception as e:
|
|
138
407
|
logger.error(f"Error parsing attachment: {str(e)}")
|
|
139
408
|
description = f"Error parsing attachment: {image_url}"
|
|
@@ -156,15 +425,9 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
156
425
|
page_content = page_content.replace(f"", new_image_markdown)
|
|
157
426
|
return page_content
|
|
158
427
|
|
|
159
|
-
def process_attachment(self, attachment_url, attachment_name, image_description_prompt):
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
project=self.project,
|
|
163
|
-
token=self.token.get_secret_value(),
|
|
164
|
-
repository_id="Test_agent.wiki",
|
|
165
|
-
base_branch=wiki_master_branch,
|
|
166
|
-
active_branch=wiki_master_branch)
|
|
167
|
-
attachment_content = repos_wrapper.download_file(path=attachment_url)
|
|
428
|
+
def process_attachment(self, attachment_url, attachment_name, repos_wrapper, image_description_prompt):
|
|
429
|
+
file_path = unquote(attachment_url.lstrip('/'))
|
|
430
|
+
attachment_content = repos_wrapper.download_file(path=file_path)
|
|
168
431
|
return parse_file_content(
|
|
169
432
|
file_content=attachment_content,
|
|
170
433
|
file_name=attachment_name,
|
|
@@ -226,7 +489,7 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
226
489
|
logger.error(f"Unable to rename wiki page: {str(e)}")
|
|
227
490
|
return ToolException(f"Unable to rename wiki page: {str(e)}")
|
|
228
491
|
|
|
229
|
-
def modify_wiki_page(self, wiki_identified: str, page_name: str, page_content: str, version_identifier: str, version_type: str = "branch"):
|
|
492
|
+
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):
|
|
230
493
|
"""Create or Update ADO wiki page content."""
|
|
231
494
|
try:
|
|
232
495
|
all_wikis = [wiki.name for wiki in self._client.get_all_wikis(project=self.project)]
|
|
@@ -257,24 +520,24 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
257
520
|
return ToolException(f"Unable to extract page by path {page_name}: {str(get_page_e)}")
|
|
258
521
|
|
|
259
522
|
try:
|
|
260
|
-
return self._client.create_or_update_page(
|
|
523
|
+
return _format_wiki_page_response(self._client.create_or_update_page(
|
|
261
524
|
project=self.project,
|
|
262
525
|
wiki_identifier=wiki_identified,
|
|
263
526
|
path=page_name,
|
|
264
527
|
parameters=WikiPageCreateOrUpdateParameters(content=page_content),
|
|
265
528
|
version=version,
|
|
266
529
|
version_descriptor=GitVersionDescriptor(version=version_identifier, version_type=version_type)
|
|
267
|
-
)
|
|
530
|
+
), expanded=expanded)
|
|
268
531
|
except AzureDevOpsServiceError as e:
|
|
269
532
|
if "The version '{0}' either is invalid or does not exist." in str(e):
|
|
270
533
|
# Retry the request without version_descriptor
|
|
271
|
-
return self._client.create_or_update_page(
|
|
534
|
+
return _format_wiki_page_response(wiki_page_response=self._client.create_or_update_page(
|
|
272
535
|
project=self.project,
|
|
273
536
|
wiki_identifier=wiki_identified,
|
|
274
537
|
path=page_name,
|
|
275
538
|
parameters=WikiPageCreateOrUpdateParameters(content=page_content),
|
|
276
539
|
version=version
|
|
277
|
-
)
|
|
540
|
+
), expanded=expanded)
|
|
278
541
|
else:
|
|
279
542
|
raise
|
|
280
543
|
except Exception as e:
|
|
@@ -323,6 +586,12 @@ class AzureDevOpsApiWrapper(NonCodeIndexerToolkit):
|
|
|
323
586
|
"args_schema": GetWikiInput,
|
|
324
587
|
"ref": self.get_wiki,
|
|
325
588
|
},
|
|
589
|
+
{
|
|
590
|
+
"name": "get_wiki_page",
|
|
591
|
+
"description": self.get_wiki_page.__doc__,
|
|
592
|
+
"args_schema": GetPageInput,
|
|
593
|
+
"ref": self.get_wiki_page,
|
|
594
|
+
},
|
|
326
595
|
{
|
|
327
596
|
"name": "get_wiki_page_by_path",
|
|
328
597
|
"description": self.get_wiki_page_by_path.__doc__,
|
|
@@ -9,27 +9,36 @@ 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 = "ado_boards"
|
|
15
16
|
|
|
17
|
+
def get_toolkit(tool):
|
|
18
|
+
return AzureDevOpsWorkItemsToolkit().get_toolkit(
|
|
19
|
+
selected_tools=tool['settings'].get('selected_tools', []),
|
|
20
|
+
ado_configuration=tool['settings']['ado_configuration'],
|
|
21
|
+
limit=tool['settings'].get('limit', 5),
|
|
22
|
+
toolkit_name=tool.get('toolkit_name', ''),
|
|
23
|
+
alita=tool['settings'].get('alita', None),
|
|
24
|
+
llm=tool['settings'].get('llm', None),
|
|
25
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
26
|
+
collection_name=tool['toolkit_name'],
|
|
27
|
+
doctype='doc',
|
|
28
|
+
embedding_model=tool['settings'].get('embedding_model'),
|
|
29
|
+
vectorstore_type="PGVector"
|
|
30
|
+
)
|
|
31
|
+
|
|
16
32
|
class AzureDevOpsWorkItemsToolkit(BaseToolkit):
|
|
17
33
|
tools: List[BaseTool] = []
|
|
18
|
-
toolkit_max_length: int = 0
|
|
19
34
|
|
|
20
35
|
@staticmethod
|
|
21
36
|
def toolkit_config_schema() -> BaseModel:
|
|
22
37
|
selected_tools = {x['name']: x['args_schema'].schema() for x in AzureDevOpsApiWrapper.model_construct().get_available_tools()}
|
|
23
|
-
AzureDevOpsWorkItemsToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
24
38
|
m = create_model(
|
|
25
39
|
name,
|
|
26
|
-
name=(str, Field(description="Toolkit name",
|
|
27
|
-
json_schema_extra={
|
|
28
|
-
'toolkit_name': True,
|
|
29
|
-
'max_toolkit_length': AzureDevOpsWorkItemsToolkit.toolkit_max_length})
|
|
30
|
-
),
|
|
31
40
|
ado_configuration=(AdoConfiguration, Field(description="Ado Work Item configuration", json_schema_extra={'configuration_types': ['ado']})),
|
|
32
|
-
limit=(Optional[int], Field(description="ADO
|
|
41
|
+
limit=(Optional[int], Field(description="Default ADO boards result limit (can be overridden by agent instructions)", default=5, gt=0)),
|
|
33
42
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
34
43
|
# indexer settings
|
|
35
44
|
pgvector_configuration=(Optional[PgVectorConfiguration], Field(default = None,
|
|
@@ -96,16 +105,20 @@ class AzureDevOpsWorkItemsToolkit(BaseToolkit):
|
|
|
96
105
|
azure_devops_api_wrapper = AzureDevOpsApiWrapper(**wrapper_payload)
|
|
97
106
|
available_tools = azure_devops_api_wrapper.get_available_tools()
|
|
98
107
|
tools = []
|
|
99
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
100
108
|
for tool in available_tools:
|
|
101
109
|
if selected_tools:
|
|
102
110
|
if tool["name"] not in selected_tools:
|
|
103
111
|
continue
|
|
112
|
+
description = tool["description"] + f"\nADO instance: {azure_devops_api_wrapper.organization_url}/{azure_devops_api_wrapper.project}"
|
|
113
|
+
if toolkit_name:
|
|
114
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
115
|
+
description = description[:1000]
|
|
104
116
|
tools.append(BaseAction(
|
|
105
117
|
api_wrapper=azure_devops_api_wrapper,
|
|
106
|
-
name=
|
|
107
|
-
description=
|
|
108
|
-
args_schema=tool["args_schema"]
|
|
118
|
+
name=tool["name"],
|
|
119
|
+
description=description,
|
|
120
|
+
args_schema=tool["args_schema"],
|
|
121
|
+
metadata={TOOLKIT_NAME_META: toolkit_name, TOOLKIT_TYPE_META: name, TOOL_NAME_META: tool["name"]} if toolkit_name else {TOOL_NAME_META: tool["name"]}
|
|
109
122
|
))
|
|
110
123
|
return cls(tools=tools)
|
|
111
124
|
|