alita-sdk 0.3.263__py3-none-any.whl → 0.3.499__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 +155 -0
- alita_sdk/cli/agent_loader.py +215 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3601 -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 +1256 -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 +64 -8
- alita_sdk/community/inventory/__init__.py +224 -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/visualize.py +1370 -0
- alita_sdk/configurations/__init__.py +10 -0
- alita_sdk/configurations/ado.py +4 -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 +96 -1
- alita_sdk/configurations/delta_lake.py +1 -1
- alita_sdk/configurations/figma.py +0 -5
- alita_sdk/configurations/github.py +65 -1
- alita_sdk/configurations/gitlab.py +79 -0
- alita_sdk/configurations/google_places.py +17 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/postman.py +1 -1
- alita_sdk/configurations/qtest.py +1 -3
- alita_sdk/configurations/report_portal.py +19 -0
- alita_sdk/configurations/salesforce.py +19 -0
- alita_sdk/configurations/service_now.py +1 -12
- alita_sdk/configurations/sharepoint.py +19 -0
- alita_sdk/configurations/sonar.py +18 -0
- alita_sdk/configurations/sql.py +20 -0
- alita_sdk/configurations/testio.py +18 -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 +12 -2
- alita_sdk/runtime/clients/client.py +235 -66
- 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 +373 -0
- alita_sdk/runtime/langchain/assistant.py +123 -17
- alita_sdk/runtime/langchain/constants.py +8 -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/AlitaJSONLoader.py +8 -2
- 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 +187 -40
- alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
- alita_sdk/runtime/langchain/langraph_agent.py +406 -91
- alita_sdk/runtime/langchain/utils.py +51 -8
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/models/mcp_models.py +61 -0
- alita_sdk/runtime/toolkits/__init__.py +26 -0
- alita_sdk/runtime/toolkits/application.py +9 -2
- alita_sdk/runtime/toolkits/artifact.py +19 -7
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +780 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/subgraph.py +11 -6
- alita_sdk/runtime/toolkits/tools.py +214 -60
- alita_sdk/runtime/toolkits/vectorstore.py +9 -4
- alita_sdk/runtime/tools/__init__.py +22 -0
- alita_sdk/runtime/tools/application.py +16 -4
- alita_sdk/runtime/tools/artifact.py +312 -19
- alita_sdk/runtime/tools/function.py +100 -4
- alita_sdk/runtime/tools/graph.py +81 -0
- alita_sdk/runtime/tools/image_generation.py +212 -0
- alita_sdk/runtime/tools/llm.py +539 -180
- 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/vectorstore.py +62 -63
- alita_sdk/runtime/tools/vectorstore_base.py +156 -85
- alita_sdk/runtime/utils/AlitaCallback.py +106 -20
- alita_sdk/runtime/utils/mcp_client.py +465 -0
- alita_sdk/runtime/utils/mcp_oauth.py +244 -0
- alita_sdk/runtime/utils/mcp_sse_client.py +405 -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 +14 -0
- alita_sdk/tools/__init__.py +78 -35
- alita_sdk/tools/ado/__init__.py +0 -1
- alita_sdk/tools/ado/repos/__init__.py +10 -6
- alita_sdk/tools/ado/repos/repos_wrapper.py +12 -11
- alita_sdk/tools/ado/test_plan/__init__.py +10 -7
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -23
- alita_sdk/tools/ado/wiki/__init__.py +10 -11
- alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -28
- alita_sdk/tools/ado/work_item/__init__.py +10 -11
- alita_sdk/tools/ado/work_item/ado_wrapper.py +63 -10
- alita_sdk/tools/advanced_jira_mining/__init__.py +10 -7
- alita_sdk/tools/aws/delta_lake/__init__.py +13 -11
- alita_sdk/tools/azure_ai/search/__init__.py +11 -7
- alita_sdk/tools/base_indexer_toolkit.py +392 -86
- alita_sdk/tools/bitbucket/__init__.py +18 -11
- alita_sdk/tools/bitbucket/api_wrapper.py +52 -9
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
- alita_sdk/tools/browser/__init__.py +40 -16
- alita_sdk/tools/browser/crawler.py +3 -1
- alita_sdk/tools/browser/utils.py +15 -6
- alita_sdk/tools/carrier/__init__.py +17 -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 +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 +9 -6
- alita_sdk/tools/cloud/azure/__init__.py +9 -6
- alita_sdk/tools/cloud/gcp/__init__.py +9 -6
- alita_sdk/tools/cloud/k8s/__init__.py +9 -6
- alita_sdk/tools/code/linter/__init__.py +7 -7
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +18 -12
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +14 -11
- alita_sdk/tools/confluence/api_wrapper.py +198 -58
- alita_sdk/tools/confluence/loader.py +10 -0
- alita_sdk/tools/custom_open_api/__init__.py +9 -4
- alita_sdk/tools/elastic/__init__.py +8 -7
- alita_sdk/tools/elitea_base.py +543 -64
- alita_sdk/tools/figma/__init__.py +10 -8
- alita_sdk/tools/figma/api_wrapper.py +352 -153
- alita_sdk/tools/github/__init__.py +13 -11
- alita_sdk/tools/github/api_wrapper.py +9 -26
- alita_sdk/tools/github/github_client.py +75 -12
- alita_sdk/tools/github/schemas.py +2 -1
- alita_sdk/tools/gitlab/__init__.py +11 -10
- alita_sdk/tools/gitlab/api_wrapper.py +135 -45
- alita_sdk/tools/gitlab_org/__init__.py +11 -9
- alita_sdk/tools/google/bigquery/__init__.py +12 -13
- alita_sdk/tools/google_places/__init__.py +18 -10
- alita_sdk/tools/jira/__init__.py +14 -8
- alita_sdk/tools/jira/api_wrapper.py +315 -168
- alita_sdk/tools/keycloak/__init__.py +8 -7
- alita_sdk/tools/localgit/local_git.py +56 -54
- alita_sdk/tools/memory/__init__.py +27 -11
- alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
- alita_sdk/tools/ocr/__init__.py +8 -7
- alita_sdk/tools/openapi/__init__.py +10 -1
- alita_sdk/tools/pandas/__init__.py +8 -7
- alita_sdk/tools/pandas/api_wrapper.py +7 -25
- alita_sdk/tools/postman/__init__.py +8 -10
- alita_sdk/tools/postman/api_wrapper.py +19 -8
- alita_sdk/tools/postman/postman_analysis.py +8 -1
- alita_sdk/tools/pptx/__init__.py +8 -9
- alita_sdk/tools/qtest/__init__.py +19 -13
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +10 -9
- alita_sdk/tools/report_portal/__init__.py +20 -15
- alita_sdk/tools/salesforce/__init__.py +19 -15
- alita_sdk/tools/servicenow/__init__.py +14 -11
- alita_sdk/tools/sharepoint/__init__.py +14 -13
- 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 +10 -7
- alita_sdk/tools/sql/__init__.py +19 -18
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +18 -12
- alita_sdk/tools/testrail/__init__.py +10 -10
- alita_sdk/tools/testrail/api_wrapper.py +213 -45
- alita_sdk/tools/utils/__init__.py +28 -4
- alita_sdk/tools/utils/content_parser.py +181 -61
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
- alita_sdk/tools/xray/__init__.py +12 -7
- alita_sdk/tools/xray/api_wrapper.py +58 -113
- alita_sdk/tools/zephyr/__init__.py +9 -6
- alita_sdk/tools/zephyr_enterprise/__init__.py +13 -8
- alita_sdk/tools/zephyr_enterprise/api_wrapper.py +17 -7
- alita_sdk/tools/zephyr_essential/__init__.py +13 -9
- alita_sdk/tools/zephyr_essential/api_wrapper.py +289 -47
- alita_sdk/tools/zephyr_essential/client.py +6 -4
- alita_sdk/tools/zephyr_scale/__init__.py +10 -7
- alita_sdk/tools/zephyr_scale/api_wrapper.py +6 -2
- alita_sdk/tools/zephyr_squad/__init__.py +9 -6
- {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/METADATA +180 -33
- alita_sdk-0.3.499.dist-info/RECORD +433 -0
- alita_sdk-0.3.499.dist-info/entry_points.txt +2 -0
- alita_sdk-0.3.263.dist-info/RECORD +0 -342
- {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.263.dist-info → alita_sdk-0.3.499.dist-info}/top_level.txt +0 -0
|
@@ -5,7 +5,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field, SecretStr
|
|
|
5
5
|
|
|
6
6
|
from .api_wrapper import KeycloakApiWrapper
|
|
7
7
|
from ..base.tool import BaseAction
|
|
8
|
-
from ..utils import clean_string,
|
|
8
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
9
9
|
|
|
10
10
|
name = "keycloak"
|
|
11
11
|
|
|
@@ -21,15 +21,13 @@ def get_tools(tool):
|
|
|
21
21
|
|
|
22
22
|
class KeycloakToolkit(BaseToolkit):
|
|
23
23
|
tools: list[BaseTool] = []
|
|
24
|
-
toolkit_max_length: int = 0
|
|
25
24
|
|
|
26
25
|
@staticmethod
|
|
27
26
|
def toolkit_config_schema() -> BaseModel:
|
|
28
27
|
selected_tools = {x['name']: x['args_schema'].schema() for x in KeycloakApiWrapper.model_construct().get_available_tools()}
|
|
29
|
-
KeycloakToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
30
28
|
return create_model(
|
|
31
29
|
name,
|
|
32
|
-
base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True
|
|
30
|
+
base_url=(str, Field(default="", title="Server URL", description="Keycloak server URL", json_schema_extra={'toolkit_name': True})),
|
|
33
31
|
realm=(str, Field(default="", title="Realm", description="Keycloak realm")),
|
|
34
32
|
client_id=(str, Field(default="", title="Client ID", description="Keycloak client ID")),
|
|
35
33
|
client_secret=(SecretStr, Field(default="", title="Client sercet", description="Keycloak client secret", json_schema_extra={'secret': True})),
|
|
@@ -42,16 +40,19 @@ class KeycloakToolkit(BaseToolkit):
|
|
|
42
40
|
if selected_tools is None:
|
|
43
41
|
selected_tools = []
|
|
44
42
|
keycloak_api_wrapper = KeycloakApiWrapper(**kwargs)
|
|
45
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
46
43
|
available_tools = keycloak_api_wrapper.get_available_tools()
|
|
47
44
|
tools = []
|
|
48
45
|
for tool in available_tools:
|
|
49
46
|
if selected_tools and tool["name"] not in selected_tools:
|
|
50
47
|
continue
|
|
48
|
+
description = f"{tool['description']}\nUrl: {keycloak_api_wrapper.base_url}"
|
|
49
|
+
if toolkit_name:
|
|
50
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
51
|
+
description = description[:1000]
|
|
51
52
|
tools.append(BaseAction(
|
|
52
53
|
api_wrapper=keycloak_api_wrapper,
|
|
53
|
-
name=
|
|
54
|
-
description=
|
|
54
|
+
name=tool["name"],
|
|
55
|
+
description=description,
|
|
55
56
|
args_schema=tool["args_schema"]
|
|
56
57
|
))
|
|
57
58
|
return cls(tools=tools)
|
|
@@ -8,7 +8,8 @@ from git import Repo
|
|
|
8
8
|
from pydantic import BaseModel, Field, create_model, model_validator
|
|
9
9
|
from langchain_core.tools import ToolException
|
|
10
10
|
|
|
11
|
-
from ..elitea_base import BaseToolApiWrapper
|
|
11
|
+
from ..elitea_base import BaseToolApiWrapper, extend_with_file_operations
|
|
12
|
+
from ..utils.text_operations import parse_old_new_markers
|
|
12
13
|
|
|
13
14
|
logger = logging.getLogger(__name__)
|
|
14
15
|
CREATE_FILE_PROMPT = """Create new file in your local repository."""
|
|
@@ -128,58 +129,6 @@ class LocalGit(BaseToolApiWrapper):
|
|
|
128
129
|
repo.head.reset(commit=commit_sha, working_tree=True)
|
|
129
130
|
return values
|
|
130
131
|
|
|
131
|
-
def extract_old_new_pairs(self, file_query):
|
|
132
|
-
# Split the file content by lines
|
|
133
|
-
code_lines = file_query.split("\n")
|
|
134
|
-
|
|
135
|
-
# Initialize lists to hold the contents of OLD and NEW sections
|
|
136
|
-
old_contents = []
|
|
137
|
-
new_contents = []
|
|
138
|
-
|
|
139
|
-
# Initialize variables to track whether the current line is within an OLD or NEW section
|
|
140
|
-
in_old_section = False
|
|
141
|
-
in_new_section = False
|
|
142
|
-
|
|
143
|
-
# Temporary storage for the current section's content
|
|
144
|
-
current_section_content = []
|
|
145
|
-
|
|
146
|
-
# Iterate through each line in the file content
|
|
147
|
-
for line in code_lines:
|
|
148
|
-
# Check for OLD section start
|
|
149
|
-
if "OLD <<<" in line:
|
|
150
|
-
in_old_section = True
|
|
151
|
-
current_section_content = [] # Reset current section content
|
|
152
|
-
continue # Skip the line with the marker
|
|
153
|
-
|
|
154
|
-
# Check for OLD section end
|
|
155
|
-
if ">>>> OLD" in line:
|
|
156
|
-
in_old_section = False
|
|
157
|
-
old_contents.append("\n".join(current_section_content).strip()) # Add the captured content
|
|
158
|
-
current_section_content = [] # Reset current section content
|
|
159
|
-
continue # Skip the line with the marker
|
|
160
|
-
|
|
161
|
-
# Check for NEW section start
|
|
162
|
-
if "NEW <<<" in line:
|
|
163
|
-
in_new_section = True
|
|
164
|
-
current_section_content = [] # Reset current section content
|
|
165
|
-
continue # Skip the line with the marker
|
|
166
|
-
|
|
167
|
-
# Check for NEW section end
|
|
168
|
-
if ">>>> NEW" in line:
|
|
169
|
-
in_new_section = False
|
|
170
|
-
new_contents.append("\n".join(current_section_content).strip()) # Add the captured content
|
|
171
|
-
current_section_content = [] # Reset current section content
|
|
172
|
-
continue # Skip the line with the marker
|
|
173
|
-
|
|
174
|
-
# If currently in an OLD or NEW section, add the line to the current section content
|
|
175
|
-
if in_old_section or in_new_section:
|
|
176
|
-
current_section_content.append(line)
|
|
177
|
-
|
|
178
|
-
# Pair the OLD and NEW contents
|
|
179
|
-
paired_contents = list(zip(old_contents, new_contents))
|
|
180
|
-
|
|
181
|
-
return paired_contents
|
|
182
|
-
|
|
183
132
|
def checkout_commit(self, commit_sha: str) -> str:
|
|
184
133
|
""" Checkout specific commit from repository """
|
|
185
134
|
try:
|
|
@@ -233,6 +182,58 @@ class LocalGit(BaseToolApiWrapper):
|
|
|
233
182
|
return f.read()
|
|
234
183
|
else:
|
|
235
184
|
return "File '{}' cannot be read because it is not existed".format(file_path)
|
|
185
|
+
|
|
186
|
+
def _read_file(self, file_path: str, branch: str = None, **kwargs) -> str:
|
|
187
|
+
"""
|
|
188
|
+
Read a file from the repository with optional partial read support.
|
|
189
|
+
|
|
190
|
+
Parameters:
|
|
191
|
+
file_path: the file path (relative to repo root)
|
|
192
|
+
branch: branch name (not used for local git, always reads from working dir)
|
|
193
|
+
**kwargs: Additional parameters (offset, limit, head, tail) - currently ignored,
|
|
194
|
+
partial read handled client-side by base class methods
|
|
195
|
+
|
|
196
|
+
Returns:
|
|
197
|
+
File content as string
|
|
198
|
+
"""
|
|
199
|
+
return self.read_file(file_path)
|
|
200
|
+
|
|
201
|
+
def _write_file(
|
|
202
|
+
self,
|
|
203
|
+
file_path: str,
|
|
204
|
+
content: str,
|
|
205
|
+
branch: str = None,
|
|
206
|
+
commit_message: str = None
|
|
207
|
+
) -> str:
|
|
208
|
+
"""
|
|
209
|
+
Write content to a file (create or update).
|
|
210
|
+
|
|
211
|
+
Parameters:
|
|
212
|
+
file_path: Path to the file (relative to repo root)
|
|
213
|
+
content: New file content
|
|
214
|
+
branch: Branch name (not used for local git)
|
|
215
|
+
commit_message: Commit message (not used - files are written without commit)
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
Success message
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
full_path = os.path.normpath(os.path.join(self.repo.working_dir, file_path))
|
|
222
|
+
|
|
223
|
+
# Ensure directory exists
|
|
224
|
+
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
|
225
|
+
|
|
226
|
+
# Write the file
|
|
227
|
+
with open(full_path, 'w') as f:
|
|
228
|
+
f.write(content)
|
|
229
|
+
|
|
230
|
+
# Determine if file was created or updated
|
|
231
|
+
if os.path.exists(full_path):
|
|
232
|
+
return f"Updated file {file_path}"
|
|
233
|
+
else:
|
|
234
|
+
return f"Created file {file_path}"
|
|
235
|
+
except Exception as e:
|
|
236
|
+
raise ToolException(f"Unable to write file {file_path}: {str(e)}")
|
|
236
237
|
|
|
237
238
|
def update_file_content_by_lines(self, file_path: str, start_line_index: int, end_line_index: int,
|
|
238
239
|
new_content: str) -> str:
|
|
@@ -314,7 +315,7 @@ class LocalGit(BaseToolApiWrapper):
|
|
|
314
315
|
file_path = os.path.normpath(os.path.join(self.repo.working_dir, file_path))
|
|
315
316
|
file_content = self.read_file(file_path)
|
|
316
317
|
updated_file_content = file_content
|
|
317
|
-
for old, new in
|
|
318
|
+
for old, new in parse_old_new_markers(file_query): # Use shared utility
|
|
318
319
|
if not old.strip():
|
|
319
320
|
continue
|
|
320
321
|
updated_file_content = updated_file_content.replace(old, new)
|
|
@@ -332,6 +333,7 @@ class LocalGit(BaseToolApiWrapper):
|
|
|
332
333
|
except Exception as e:
|
|
333
334
|
return "Unable to update file due to error:\n" + str(e)
|
|
334
335
|
|
|
336
|
+
@extend_with_file_operations
|
|
335
337
|
def get_available_tools(self):
|
|
336
338
|
return [
|
|
337
339
|
{
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import List, Literal
|
|
2
2
|
|
|
3
|
-
from langchain_core.tools import BaseToolkit, BaseTool
|
|
3
|
+
from langchain_core.tools import BaseToolkit, BaseTool, ToolException
|
|
4
|
+
|
|
5
|
+
from alita_sdk.configurations.pgvector import PgVectorConfiguration
|
|
4
6
|
|
|
5
7
|
try:
|
|
6
8
|
from langmem import create_manage_memory_tool, create_search_memory_tool
|
|
@@ -15,7 +17,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field, SecretStr
|
|
|
15
17
|
|
|
16
18
|
name = "memory"
|
|
17
19
|
|
|
18
|
-
def get_tools(tools_list: list,
|
|
20
|
+
def get_tools(tools_list: list, memory_store=None):
|
|
19
21
|
"""
|
|
20
22
|
Get memory tools for the provided tool configurations.
|
|
21
23
|
|
|
@@ -35,8 +37,9 @@ def get_tools(tools_list: list, alita_client, llm, memory_store=None):
|
|
|
35
37
|
try:
|
|
36
38
|
toolkit_instance = MemoryToolkit().get_toolkit(
|
|
37
39
|
namespace=tool['settings'].get('namespace', str(tool['id'])),
|
|
38
|
-
username=tool['settings'].get('username', ''),
|
|
40
|
+
# username=tool['settings'].get('username', ''),
|
|
39
41
|
store=tool['settings'].get('store', memory_store),
|
|
42
|
+
pgvector_configuration=tool['settings'].get('pgvector_configuration', {}),
|
|
40
43
|
toolkit_name=tool.get('toolkit_name', '')
|
|
41
44
|
)
|
|
42
45
|
all_tools.extend(toolkit_instance.get_tools())
|
|
@@ -53,18 +56,23 @@ class MemoryToolkit(BaseToolkit):
|
|
|
53
56
|
|
|
54
57
|
@staticmethod
|
|
55
58
|
def toolkit_config_schema() -> BaseModel:
|
|
59
|
+
memory_tools = [create_manage_memory_tool('test'), create_search_memory_tool('test')]
|
|
60
|
+
selected_tools = {x.name: x.args_schema.schema() for x in memory_tools}
|
|
61
|
+
|
|
56
62
|
return create_model(
|
|
57
|
-
'
|
|
58
|
-
namespace=(str, Field(description="Memory namespace"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
'memory',
|
|
64
|
+
namespace=(str, Field(description="Memory namespace")),
|
|
65
|
+
pgvector_configuration=(PgVectorConfiguration, Field(description="PgVector Configuration",
|
|
66
|
+
json_schema_extra={
|
|
67
|
+
'configuration_types': ['pgvector']})),
|
|
68
|
+
selected_tools=(List[Literal[tuple(selected_tools)]],
|
|
69
|
+
Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
70
|
+
|
|
63
71
|
__config__=ConfigDict(json_schema_extra={
|
|
64
72
|
'metadata': {
|
|
65
73
|
"label": "Memory",
|
|
66
74
|
"icon_url": "memory.svg",
|
|
67
|
-
"hidden":
|
|
75
|
+
"hidden": False,
|
|
68
76
|
"categories": ["other"],
|
|
69
77
|
"extra_categories": ["long-term memory", "langmem"],
|
|
70
78
|
}
|
|
@@ -88,6 +96,14 @@ class MemoryToolkit(BaseToolkit):
|
|
|
88
96
|
"PostgreSQL dependencies (psycopg) are required for MemoryToolkit. "
|
|
89
97
|
"Install with: pip install psycopg[binary]"
|
|
90
98
|
)
|
|
99
|
+
|
|
100
|
+
if store is None:
|
|
101
|
+
# The store is not provided, attempt to create it from configuration
|
|
102
|
+
from ...runtime.langchain.store_manager import get_manager
|
|
103
|
+
conn_str = (kwargs.get('pgvector_configuration') or {}).get('connection_string', '')
|
|
104
|
+
if not conn_str:
|
|
105
|
+
raise ToolException("Connection string is required to create PostgresStore for memory toolkit.")
|
|
106
|
+
store = get_manager().get_store(conn_str)
|
|
91
107
|
|
|
92
108
|
# Validate store type
|
|
93
109
|
if store is not None and not isinstance(store, PostgresStore):
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
from langchain_core.documents import Document
|
|
2
|
+
from langchain_core.tools import ToolException
|
|
2
3
|
|
|
3
4
|
from alita_sdk.runtime.utils.utils import IndexerKeywords
|
|
4
5
|
from alita_sdk.tools.base_indexer_toolkit import BaseIndexerToolkit
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
class NonCodeIndexerToolkit(BaseIndexerToolkit):
|
|
8
|
-
def _get_indexed_data(self,
|
|
9
|
-
|
|
9
|
+
def _get_indexed_data(self, index_name: str):
|
|
10
|
+
self._ensure_vectorstore_initialized()
|
|
11
|
+
if not self.vector_adapter:
|
|
12
|
+
raise ToolException("Vector adapter is not initialized. "
|
|
13
|
+
"Check your configuration: embedding_model and vectorstore_type.")
|
|
14
|
+
return self.vector_adapter.get_indexed_data(self, index_name)
|
|
10
15
|
|
|
11
16
|
def key_fn(self, document: Document):
|
|
12
17
|
return document.metadata.get('id')
|
alita_sdk/tools/ocr/__init__.py
CHANGED
|
@@ -5,7 +5,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field
|
|
|
5
5
|
|
|
6
6
|
from .api_wrapper import OCRApiWrapper
|
|
7
7
|
from ..base.tool import BaseAction
|
|
8
|
-
from ..utils import clean_string,
|
|
8
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
9
9
|
|
|
10
10
|
name = "ocr"
|
|
11
11
|
|
|
@@ -23,15 +23,13 @@ def get_tools(tool):
|
|
|
23
23
|
|
|
24
24
|
class OCRToolkit(BaseToolkit):
|
|
25
25
|
tools: list[BaseTool] = []
|
|
26
|
-
toolkit_max_length: int = 0
|
|
27
26
|
|
|
28
27
|
@staticmethod
|
|
29
28
|
def toolkit_config_schema() -> BaseModel:
|
|
30
29
|
selected_tools = {x['name']: x['args_schema'].schema() for x in OCRApiWrapper.model_construct().get_available_tools()}
|
|
31
|
-
OCRToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
32
30
|
return create_model(
|
|
33
31
|
name,
|
|
34
|
-
artifacts_folder=(str, Field(description="Folder path containing artifacts to process", json_schema_extra={'toolkit_name': True
|
|
32
|
+
artifacts_folder=(str, Field(description="Folder path containing artifacts to process", json_schema_extra={'toolkit_name': True})),
|
|
35
33
|
tesseract_settings=(dict, Field(description="Settings for Tesseract OCR processing", default={})),
|
|
36
34
|
structured_output=(bool, Field(description="Whether to return structured JSON output", default=False)),
|
|
37
35
|
expected_fields=(dict, Field(description="Expected fields for structured output", default={})),
|
|
@@ -47,16 +45,19 @@ class OCRToolkit(BaseToolkit):
|
|
|
47
45
|
if selected_tools is None:
|
|
48
46
|
selected_tools = []
|
|
49
47
|
ocr_api_wrapper = OCRApiWrapper(**kwargs)
|
|
50
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
51
48
|
available_tools = ocr_api_wrapper.get_available_tools()
|
|
52
49
|
tools = []
|
|
53
50
|
for tool in available_tools:
|
|
54
51
|
if selected_tools and tool["name"] not in selected_tools:
|
|
55
52
|
continue
|
|
53
|
+
description = tool["description"]
|
|
54
|
+
if toolkit_name:
|
|
55
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
56
|
+
description = description[:1000]
|
|
56
57
|
tools.append(BaseAction(
|
|
57
58
|
api_wrapper=ocr_api_wrapper,
|
|
58
|
-
name=
|
|
59
|
-
description=
|
|
59
|
+
name=tool["name"],
|
|
60
|
+
description=description,
|
|
60
61
|
args_schema=tool["args_schema"]
|
|
61
62
|
))
|
|
62
63
|
return cls(tools=tools)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import re
|
|
3
3
|
import logging
|
|
4
|
+
import yaml
|
|
4
5
|
from typing import List, Any, Optional, Dict
|
|
5
6
|
from langchain_core.tools import BaseTool, BaseToolkit, ToolException
|
|
6
7
|
from requests_openapi import Operation, Client, Server
|
|
@@ -101,7 +102,15 @@ class AlitaOpenAPIToolkit(BaseToolkit):
|
|
|
101
102
|
else:
|
|
102
103
|
tools_set = {}
|
|
103
104
|
if isinstance(openapi_spec, str):
|
|
104
|
-
|
|
105
|
+
# Try to detect if it's YAML or JSON by attempting to parse as JSON first
|
|
106
|
+
try:
|
|
107
|
+
openapi_spec = json.loads(openapi_spec)
|
|
108
|
+
except json.JSONDecodeError:
|
|
109
|
+
# If JSON parsing fails, try YAML
|
|
110
|
+
try:
|
|
111
|
+
openapi_spec = yaml.safe_load(openapi_spec)
|
|
112
|
+
except yaml.YAMLError as e:
|
|
113
|
+
raise ToolException(f"Failed to parse OpenAPI spec as JSON or YAML: {e}")
|
|
105
114
|
c = Client()
|
|
106
115
|
c.load_spec(openapi_spec)
|
|
107
116
|
if headers:
|
|
@@ -5,7 +5,7 @@ from pydantic import BaseModel, ConfigDict, create_model, Field
|
|
|
5
5
|
|
|
6
6
|
from .api_wrapper import PandasWrapper
|
|
7
7
|
from ..base.tool import BaseAction
|
|
8
|
-
from ..utils import clean_string,
|
|
8
|
+
from ..utils import clean_string, get_max_toolkit_length
|
|
9
9
|
|
|
10
10
|
name = "pandas"
|
|
11
11
|
|
|
@@ -21,15 +21,13 @@ def get_tools(tool):
|
|
|
21
21
|
|
|
22
22
|
class PandasToolkit(BaseToolkit):
|
|
23
23
|
tools: List[BaseTool] = []
|
|
24
|
-
toolkit_max_length: int = 0
|
|
25
24
|
|
|
26
25
|
@staticmethod
|
|
27
26
|
def toolkit_config_schema() -> BaseModel:
|
|
28
27
|
selected_tools = {x['name']: x['args_schema'].schema() for x in PandasWrapper.model_construct().get_available_tools()}
|
|
29
|
-
PandasToolkit.toolkit_max_length = get_max_toolkit_length(selected_tools)
|
|
30
28
|
return create_model(
|
|
31
29
|
name,
|
|
32
|
-
bucket_name=(str, Field(default=None, title="Bucket name", description="Bucket where the content file is stored"
|
|
30
|
+
bucket_name=(str, Field(default=None, title="Bucket name", description="Bucket where the content file is stored")),
|
|
33
31
|
selected_tools=(List[Literal[tuple(selected_tools)]], Field(default=[], json_schema_extra={'args_schemas': selected_tools})),
|
|
34
32
|
__config__=ConfigDict(json_schema_extra={'metadata': {"label": "Pandas", "icon_url": "pandas-icon.svg",
|
|
35
33
|
"categories": ["analysis"],
|
|
@@ -41,16 +39,19 @@ class PandasToolkit(BaseToolkit):
|
|
|
41
39
|
if selected_tools is None:
|
|
42
40
|
selected_tools = []
|
|
43
41
|
csv_tool_api_wrapper = PandasWrapper(**kwargs)
|
|
44
|
-
prefix = clean_string(toolkit_name, cls.toolkit_max_length) + TOOLKIT_SPLITTER if toolkit_name else ''
|
|
45
42
|
available_tools = csv_tool_api_wrapper.get_available_tools()
|
|
46
43
|
tools = []
|
|
47
44
|
for tool in available_tools:
|
|
48
45
|
if selected_tools and tool["name"] not in selected_tools:
|
|
49
46
|
continue
|
|
47
|
+
description = tool["description"]
|
|
48
|
+
if toolkit_name:
|
|
49
|
+
description = f"Toolkit: {toolkit_name}\n{description}"
|
|
50
|
+
description = description[:1000]
|
|
50
51
|
tools.append(BaseAction(
|
|
51
52
|
api_wrapper=csv_tool_api_wrapper,
|
|
52
|
-
name=
|
|
53
|
-
description=
|
|
53
|
+
name=tool["name"],
|
|
54
|
+
description=description,
|
|
54
55
|
args_schema=tool["args_schema"]
|
|
55
56
|
))
|
|
56
57
|
return cls(tools=tools)
|
|
@@ -93,7 +93,7 @@ class PandasWrapper(BaseToolApiWrapper):
|
|
|
93
93
|
if file_extension in ['csv', 'txt']:
|
|
94
94
|
df = pd.read_csv(file_obj)
|
|
95
95
|
elif file_extension in ['xlsx', 'xls']:
|
|
96
|
-
df = pd.read_excel(file_obj)
|
|
96
|
+
df = pd.read_excel(file_obj, engine='calamine')
|
|
97
97
|
elif file_extension == 'parquet':
|
|
98
98
|
df = pd.read_parquet(file_obj)
|
|
99
99
|
elif file_extension == 'json':
|
|
@@ -162,35 +162,17 @@ class PandasWrapper(BaseToolApiWrapper):
|
|
|
162
162
|
"""Analyze and process using query on dataset"""
|
|
163
163
|
df = self._get_dataframe(filename)
|
|
164
164
|
code = self.generate_code_with_retries(df, query)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
data={
|
|
168
|
-
"message": f"Executing generated code... \n\n```python\n{code}\n```",
|
|
169
|
-
"tool_name": "process_query",
|
|
170
|
-
"toolkit": "pandas"
|
|
171
|
-
}
|
|
172
|
-
)
|
|
165
|
+
self._log_tool_event(tool_name="process_query",
|
|
166
|
+
message=f"Executing generated code... \n\n```python\n{code}\n```")
|
|
173
167
|
try:
|
|
174
168
|
result = self.execute_code(df, code)
|
|
175
169
|
except Exception as e:
|
|
176
170
|
logger.error(f"Code execution failed: {format_exc()}")
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
data={
|
|
180
|
-
"message": f"Code execution failed: {format_exc()}",
|
|
181
|
-
"tool_name": "process_query",
|
|
182
|
-
"toolkit": "pandas"
|
|
183
|
-
}
|
|
184
|
-
)
|
|
171
|
+
self._log_tool_event(tool_name="process_query",
|
|
172
|
+
message=f"Executing generated code... \n\n```python\n{code}\n```")
|
|
185
173
|
raise
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
data={
|
|
189
|
-
"message": f"Result of code execution... \n\n```\n{result['result']}\n```",
|
|
190
|
-
"tool_name": "process_query",
|
|
191
|
-
"toolkit": "pandas"
|
|
192
|
-
}
|
|
193
|
-
)
|
|
174
|
+
self._log_tool_event(tool_name="process_query",
|
|
175
|
+
message=f"Executing generated code... \n\n```python\n{code}\n```")
|
|
194
176
|
if result.get("df") is not None:
|
|
195
177
|
df = result.pop("df")
|
|
196
178
|
# Not saving dataframe to artifact repo for now
|
|
@@ -6,7 +6,7 @@ from pydantic import create_model, BaseModel, ConfigDict, Field, field_validator
|
|
|
6
6
|
from ..base.tool import BaseAction
|
|
7
7
|
|
|
8
8
|
from .api_wrapper import PostmanApiWrapper
|
|
9
|
-
from ..utils import clean_string, get_max_toolkit_length,
|
|
9
|
+
from ..utils import clean_string, get_max_toolkit_length, check_connection_response
|
|
10
10
|
from ...configurations.postman import PostmanConfiguration
|
|
11
11
|
|
|
12
12
|
name = "postman"
|
|
@@ -43,20 +43,16 @@ def get_tools(tool):
|
|
|
43
43
|
|
|
44
44
|
class PostmanToolkit(BaseToolkit):
|
|
45
45
|
tools: List[BaseTool] = []
|
|
46
|
-
toolkit_max_length: int = 0
|
|
47
46
|
|
|
48
47
|
@staticmethod
|
|
49
48
|
def toolkit_config_schema() -> BaseModel:
|
|
50
49
|
selected_tools = {x['name']: x['args_schema'].schema(
|
|
51
50
|
) for x in PostmanApiWrapper.model_construct().get_available_tools()}
|
|
52
|
-
PostmanToolkit.toolkit_max_length = get_max_toolkit_length(
|
|
53
|
-
selected_tools)
|
|
54
51
|
m = create_model(
|
|
55
52
|
name,
|
|
56
53
|
postman_configuration=(Optional[PostmanConfiguration], Field(description="Postman Configuration",
|
|
57
54
|
json_schema_extra={'configuration_types': ['postman']})),
|
|
58
|
-
collection_id=(str, Field(description="Default collection ID",
|
|
59
|
-
'toolkit_name': True, 'max_toolkit_length': PostmanToolkit.toolkit_max_length})),
|
|
55
|
+
collection_id=(str, Field(description="Default collection ID")),
|
|
60
56
|
environment_config=(dict, Field(
|
|
61
57
|
description="JSON configuration for request execution (auth headers, project IDs, base URLs, etc.)",
|
|
62
58
|
default={})),
|
|
@@ -90,19 +86,21 @@ class PostmanToolkit(BaseToolkit):
|
|
|
90
86
|
**kwargs['postman_configuration'],
|
|
91
87
|
}
|
|
92
88
|
postman_api_wrapper = PostmanApiWrapper(**wrapper_payload)
|
|
93
|
-
prefix = clean_string(str(toolkit_name), cls.toolkit_max_length) + \
|
|
94
|
-
TOOLKIT_SPLITTER if toolkit_name else ''
|
|
95
89
|
available_tools = postman_api_wrapper.get_available_tools()
|
|
96
90
|
tools = []
|
|
97
91
|
for tool in available_tools:
|
|
98
92
|
if selected_tools:
|
|
99
93
|
if tool["name"] not in selected_tools:
|
|
100
94
|
continue
|
|
95
|
+
description = f"{tool['description']}\nAPI URL: {postman_api_wrapper.base_url}"
|
|
96
|
+
if toolkit_name:
|
|
97
|
+
description = f"{description}\nToolkit: {toolkit_name}"
|
|
98
|
+
description = description[:1000]
|
|
101
99
|
tools.append(PostmanAction(
|
|
102
100
|
api_wrapper=postman_api_wrapper,
|
|
103
|
-
name=
|
|
101
|
+
name=tool["name"],
|
|
104
102
|
mode=tool["mode"],
|
|
105
|
-
description=
|
|
103
|
+
description=description,
|
|
106
104
|
args_schema=tool["args_schema"]
|
|
107
105
|
))
|
|
108
106
|
return cls(tools=tools)
|
|
@@ -340,7 +340,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
340
340
|
raise ToolException(
|
|
341
341
|
f"Invalid JSON response from Postman API: {str(e)}")
|
|
342
342
|
|
|
343
|
-
def _apply_authentication(self, headers, params, all_variables, resolve_variables):
|
|
343
|
+
def _apply_authentication(self, headers, params, all_variables, native_auth, resolve_variables):
|
|
344
344
|
"""Apply authentication based on environment_config auth settings.
|
|
345
345
|
|
|
346
346
|
Supports multiple authentication types:
|
|
@@ -363,14 +363,15 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
363
363
|
import base64
|
|
364
364
|
|
|
365
365
|
# Handle structured auth configuration only - no backward compatibility
|
|
366
|
-
auth_config = self.environment_config.get('auth')
|
|
366
|
+
auth_config = self.environment_config.get('auth', native_auth)
|
|
367
367
|
if auth_config and isinstance(auth_config, dict):
|
|
368
368
|
auth_type = auth_config.get('type', '').lower()
|
|
369
369
|
auth_params = auth_config.get('params', {})
|
|
370
370
|
|
|
371
371
|
if auth_type == 'bearer':
|
|
372
372
|
# Bearer token authentication
|
|
373
|
-
|
|
373
|
+
tokent_raw = auth_config.get('bearer', [{}])[0].get('value', '')
|
|
374
|
+
token = resolve_variables(str(tokent_raw))
|
|
374
375
|
if token:
|
|
375
376
|
headers['Authorization'] = f'Bearer {token}'
|
|
376
377
|
|
|
@@ -739,7 +740,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
739
740
|
all_variables = {}
|
|
740
741
|
|
|
741
742
|
# 1. Start with environment_config variables (lowest priority)
|
|
742
|
-
all_variables.update(self.
|
|
743
|
+
all_variables.update(self._get_variables_from_env_config())
|
|
743
744
|
|
|
744
745
|
# 2. Add collection variables
|
|
745
746
|
collection_variables = collection_data.get('variable', [])
|
|
@@ -760,8 +761,9 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
760
761
|
import re
|
|
761
762
|
def replace_var(match):
|
|
762
763
|
var_name = match.group(1)
|
|
763
|
-
|
|
764
|
-
|
|
764
|
+
value = all_variables.get(var_name, None)
|
|
765
|
+
return resolve_variables(str(value)) if value else match.group(0)
|
|
766
|
+
|
|
765
767
|
return re.sub(r'\{\{([^}]+)\}\}', replace_var, text)
|
|
766
768
|
|
|
767
769
|
# Prepare the request
|
|
@@ -791,7 +793,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
791
793
|
headers = {}
|
|
792
794
|
|
|
793
795
|
# Handle authentication from environment_config
|
|
794
|
-
self._apply_authentication(headers, params, all_variables, resolve_variables)
|
|
796
|
+
self._apply_authentication(headers, params, all_variables, request_data.get('auth', None), resolve_variables)
|
|
795
797
|
|
|
796
798
|
# Add headers from request
|
|
797
799
|
request_headers = request_data.get('header', [])
|
|
@@ -1640,7 +1642,7 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
1640
1642
|
|
|
1641
1643
|
# Find the request
|
|
1642
1644
|
request_item = self.analyzer.find_request_by_path(
|
|
1643
|
-
collection_data["item"], request_path)
|
|
1645
|
+
collection_data["item"], request_path, collection_data.get("auth", None))
|
|
1644
1646
|
if not request_item:
|
|
1645
1647
|
raise ToolException(f"Request '{request_path}' not found")
|
|
1646
1648
|
|
|
@@ -2161,3 +2163,12 @@ class PostmanApiWrapper(BaseToolApiWrapper):
|
|
|
2161
2163
|
parse_items(items)
|
|
2162
2164
|
|
|
2163
2165
|
return result
|
|
2166
|
+
|
|
2167
|
+
def _get_variables_from_env_config(self):
|
|
2168
|
+
"""Extracts all enabled variables from the 'values' field in environment_config."""
|
|
2169
|
+
result = {}
|
|
2170
|
+
values = self.environment_config.get("values", [])
|
|
2171
|
+
for var in values:
|
|
2172
|
+
if var.get("enabled", True) and "key" in var and "value" in var:
|
|
2173
|
+
result[var["key"]] = var["value"]
|
|
2174
|
+
return result
|
|
@@ -1049,13 +1049,14 @@ class PostmanAnalyzer:
|
|
|
1049
1049
|
find_in_items(items, path_parts)
|
|
1050
1050
|
return results
|
|
1051
1051
|
|
|
1052
|
-
def find_request_by_path(self, items: List[Dict], request_path: str) -> Optional[Dict]:
|
|
1052
|
+
def find_request_by_path(self, items: List[Dict], request_path: str, auth = None) -> Optional[Dict]:
|
|
1053
1053
|
"""Find a request by its path."""
|
|
1054
1054
|
path_parts = [part.strip() for part in request_path.split('/') if part.strip()]
|
|
1055
1055
|
if not path_parts:
|
|
1056
1056
|
return None
|
|
1057
1057
|
|
|
1058
1058
|
current_items = items
|
|
1059
|
+
current_auth = auth
|
|
1059
1060
|
|
|
1060
1061
|
# Navigate through folders to the request
|
|
1061
1062
|
for i, part in enumerate(path_parts):
|
|
@@ -1065,6 +1066,9 @@ class PostmanAnalyzer:
|
|
|
1065
1066
|
if i == len(path_parts) - 1:
|
|
1066
1067
|
# This should be the request
|
|
1067
1068
|
if item.get('request'):
|
|
1069
|
+
# if request has no auth, inherit from parent
|
|
1070
|
+
if not item['request'].get('auth') and current_auth:
|
|
1071
|
+
item['request']['auth'] = current_auth
|
|
1068
1072
|
return item
|
|
1069
1073
|
else:
|
|
1070
1074
|
return None
|
|
@@ -1072,6 +1076,9 @@ class PostmanAnalyzer:
|
|
|
1072
1076
|
# This should be a folder
|
|
1073
1077
|
if item.get('item'):
|
|
1074
1078
|
current_items = item['item']
|
|
1079
|
+
# Update current_auth if folder has auth
|
|
1080
|
+
if item.get('auth'):
|
|
1081
|
+
current_auth = item['auth']
|
|
1075
1082
|
found = True
|
|
1076
1083
|
break
|
|
1077
1084
|
else:
|