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
|
@@ -20,8 +20,9 @@ from .prompt import AlitaPrompt
|
|
|
20
20
|
from .datasource import AlitaDataSource
|
|
21
21
|
from .artifact import Artifact
|
|
22
22
|
from ..langchain.chat_message_template import Jinja2TemplatedChatMessagesTemplate
|
|
23
|
-
from ..utils.
|
|
23
|
+
from ..utils.mcp_oauth import McpAuthorizationRequired
|
|
24
24
|
from ...tools import get_available_toolkit_models
|
|
25
|
+
from ...tools.base_indexer_toolkit import IndexTools
|
|
25
26
|
|
|
26
27
|
logger = logging.getLogger(__name__)
|
|
27
28
|
|
|
@@ -68,7 +69,11 @@ class AlitaClient:
|
|
|
68
69
|
self.bucket_url = f"{self.base_url}{self.api_path}/artifacts/buckets/{self.project_id}"
|
|
69
70
|
self.configurations_url = f'{self.base_url}{self.api_path}/integrations/integrations/default/{self.project_id}?section=configurations&unsecret=true'
|
|
70
71
|
self.ai_section_url = f'{self.base_url}{self.api_path}/integrations/integrations/default/{self.project_id}?section=ai'
|
|
72
|
+
self.models_url = f'{self.base_url}{self.api_path}/configurations/models/{self.project_id}?include_shared=true'
|
|
73
|
+
self.image_generation_url = f"{self.base_url}{self.llm_path}/images/generations"
|
|
71
74
|
self.configurations: list = configurations or []
|
|
75
|
+
self.model_timeout = kwargs.get('model_timeout', 120)
|
|
76
|
+
self.model_image_generation = kwargs.get('model_image_generation')
|
|
72
77
|
|
|
73
78
|
def get_mcp_toolkits(self):
|
|
74
79
|
if user_id := self._get_real_user_id():
|
|
@@ -81,8 +86,23 @@ class AlitaClient:
|
|
|
81
86
|
def mcp_tool_call(self, params: dict[str, Any]):
|
|
82
87
|
if user_id := self._get_real_user_id():
|
|
83
88
|
url = f"{self.mcp_tools_call}/{user_id}"
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
#
|
|
90
|
+
# This loop iterates over each key-value pair in the arguments dictionary,
|
|
91
|
+
# and if a value is a Pydantic object, it replaces it with its dictionary representation using .dict().
|
|
92
|
+
for arg_name, arg_value in params.get('params', {}).get('arguments', {}).items():
|
|
93
|
+
if isinstance(arg_value, list):
|
|
94
|
+
params['params']['arguments'][arg_name] = [
|
|
95
|
+
item.dict() if hasattr(item, "dict") and callable(item.dict) else item
|
|
96
|
+
for item in arg_value
|
|
97
|
+
]
|
|
98
|
+
elif hasattr(arg_value, "dict") and callable(arg_value.dict):
|
|
99
|
+
params['params']['arguments'][arg_name] = arg_value.dict()
|
|
100
|
+
#
|
|
101
|
+
response = requests.post(url, headers=self.headers, json=params, verify=False)
|
|
102
|
+
try:
|
|
103
|
+
return response.json()
|
|
104
|
+
except (ValueError, TypeError):
|
|
105
|
+
return response.text
|
|
86
106
|
else:
|
|
87
107
|
return f"Error: Could not determine user ID for MCP tool call"
|
|
88
108
|
|
|
@@ -157,6 +177,20 @@ class AlitaClient:
|
|
|
157
177
|
return resp.json()
|
|
158
178
|
return []
|
|
159
179
|
|
|
180
|
+
def get_available_models(self):
|
|
181
|
+
"""Get list of available models from the configurations API.
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
List of model dictionaries with 'name' and other properties,
|
|
185
|
+
or empty list if request fails.
|
|
186
|
+
"""
|
|
187
|
+
resp = requests.get(self.models_url, headers=self.headers, verify=False)
|
|
188
|
+
if resp.ok:
|
|
189
|
+
data = resp.json()
|
|
190
|
+
# API returns {"items": [...], ...}
|
|
191
|
+
return data.get('items', [])
|
|
192
|
+
return []
|
|
193
|
+
|
|
160
194
|
def get_embeddings(self, embedding_model: str) -> OpenAIEmbeddings:
|
|
161
195
|
"""
|
|
162
196
|
Get an instance of OpenAIEmbeddings configured with the project ID and auth token.
|
|
@@ -169,6 +203,7 @@ class AlitaClient:
|
|
|
169
203
|
model=embedding_model,
|
|
170
204
|
api_key=self.auth_token,
|
|
171
205
|
openai_organization=str(self.project_id),
|
|
206
|
+
request_timeout=self.model_timeout
|
|
172
207
|
)
|
|
173
208
|
|
|
174
209
|
def get_llm(self, model_name: str, model_config: dict) -> ChatOpenAI:
|
|
@@ -187,20 +222,99 @@ class AlitaClient:
|
|
|
187
222
|
|
|
188
223
|
logger.info(f"Creating ChatOpenAI model: {model_name} with config: {model_config}")
|
|
189
224
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
225
|
+
try:
|
|
226
|
+
from tools import this # pylint: disable=E0401,C0415
|
|
227
|
+
worker_config = this.for_module("indexer_worker").descriptor.config
|
|
228
|
+
except: # pylint: disable=W0702
|
|
229
|
+
worker_config = {}
|
|
230
|
+
|
|
231
|
+
use_responses_api = False
|
|
232
|
+
|
|
233
|
+
if worker_config and isinstance(worker_config, dict):
|
|
234
|
+
for target_name_tag in worker_config.get("use_responses_api_for", []):
|
|
235
|
+
if target_name_tag in model_name:
|
|
236
|
+
use_responses_api = True
|
|
237
|
+
break
|
|
238
|
+
|
|
239
|
+
# handle case when max_tokens are auto-configurable == -1
|
|
240
|
+
llm_max_tokens = model_config.get("max_tokens", None)
|
|
241
|
+
if llm_max_tokens and llm_max_tokens == -1:
|
|
242
|
+
logger.warning(f'User selected `MAX COMPLETION TOKENS` as `auto`')
|
|
243
|
+
# default nuber for a case when auto is selected for an agent
|
|
244
|
+
llm_max_tokens = 4000
|
|
245
|
+
|
|
246
|
+
target_kwargs = {
|
|
247
|
+
"base_url": f"{self.base_url}{self.llm_path}",
|
|
248
|
+
"model": model_name,
|
|
249
|
+
"api_key": self.auth_token,
|
|
250
|
+
"streaming": model_config.get("streaming", True),
|
|
251
|
+
"stream_usage": model_config.get("stream_usage", True),
|
|
252
|
+
"max_tokens": llm_max_tokens,
|
|
253
|
+
"temperature": model_config.get("temperature"),
|
|
254
|
+
"reasoning_effort": model_config.get("reasoning_effort"),
|
|
255
|
+
"max_retries": model_config.get("max_retries", 3),
|
|
256
|
+
"seed": model_config.get("seed", None),
|
|
257
|
+
"openai_organization": str(self.project_id),
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if use_responses_api:
|
|
261
|
+
target_kwargs["use_responses_api"] = True
|
|
262
|
+
|
|
263
|
+
return ChatOpenAI(**target_kwargs)
|
|
264
|
+
|
|
265
|
+
def generate_image(self,
|
|
266
|
+
prompt: str,
|
|
267
|
+
n: int = 1,
|
|
268
|
+
size: str = "auto",
|
|
269
|
+
quality: str = "auto",
|
|
270
|
+
response_format: str = "b64_json",
|
|
271
|
+
style: Optional[str] = None) -> dict:
|
|
272
|
+
|
|
273
|
+
if not self.model_image_generation:
|
|
274
|
+
raise ValueError("Image generation model is not configured for this client")
|
|
275
|
+
|
|
276
|
+
image_generation_data = {
|
|
277
|
+
"prompt": prompt,
|
|
278
|
+
"model": self.model_image_generation,
|
|
279
|
+
"n": n,
|
|
280
|
+
"response_format": response_format,
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Only add optional parameters if they have meaningful values
|
|
284
|
+
if size and size.lower() != "auto":
|
|
285
|
+
image_generation_data["size"] = size
|
|
286
|
+
|
|
287
|
+
if quality and quality.lower() != "auto":
|
|
288
|
+
image_generation_data["quality"] = quality
|
|
289
|
+
|
|
290
|
+
if style:
|
|
291
|
+
image_generation_data["style"] = style
|
|
292
|
+
|
|
293
|
+
# Standard headers for image generation
|
|
294
|
+
image_headers = self.headers.copy()
|
|
295
|
+
image_headers.update({
|
|
296
|
+
"Content-Type": "application/json",
|
|
297
|
+
})
|
|
203
298
|
|
|
299
|
+
logger.info(f"Generating image with model: {self.model_image_generation}, prompt: {prompt[:50]}...")
|
|
300
|
+
|
|
301
|
+
try:
|
|
302
|
+
response = requests.post(
|
|
303
|
+
self.image_generation_url,
|
|
304
|
+
headers=image_headers,
|
|
305
|
+
json=image_generation_data,
|
|
306
|
+
verify=False,
|
|
307
|
+
timeout=self.model_timeout
|
|
308
|
+
)
|
|
309
|
+
response.raise_for_status()
|
|
310
|
+
return response.json()
|
|
311
|
+
|
|
312
|
+
except requests.exceptions.HTTPError as e:
|
|
313
|
+
logger.error(f"Image generation failed: {e.response.status_code} - {e.response.text}")
|
|
314
|
+
raise
|
|
315
|
+
except requests.exceptions.RequestException as e:
|
|
316
|
+
logger.error(f"Image generation request failed: {e}")
|
|
317
|
+
raise
|
|
204
318
|
|
|
205
319
|
def get_app_version_details(self, application_id: int, application_version_id: int) -> dict:
|
|
206
320
|
url = f"{self.application_versions}/{application_id}/{application_version_id}"
|
|
@@ -232,7 +346,8 @@ class AlitaClient:
|
|
|
232
346
|
app_type=None, memory=None, runtime='langchain',
|
|
233
347
|
application_variables: Optional[dict] = None,
|
|
234
348
|
version_details: Optional[dict] = None, store: Optional[BaseStore] = None,
|
|
235
|
-
llm: Optional[ChatOpenAI] = None
|
|
349
|
+
llm: Optional[ChatOpenAI] = None, mcp_tokens: Optional[dict] = None,
|
|
350
|
+
conversation_id: Optional[str] = None):
|
|
236
351
|
if tools is None:
|
|
237
352
|
tools = []
|
|
238
353
|
if chat_history is None:
|
|
@@ -252,11 +367,15 @@ class AlitaClient:
|
|
|
252
367
|
if var['name'] in application_variables:
|
|
253
368
|
var.update(application_variables[var['name']])
|
|
254
369
|
if llm is None:
|
|
370
|
+
max_tokens = data['llm_settings'].get('max_tokens', 4000)
|
|
371
|
+
if max_tokens == -1:
|
|
372
|
+
# default nuber for case when auto is selected for agent
|
|
373
|
+
max_tokens = 4000
|
|
255
374
|
llm = self.get_llm(
|
|
256
375
|
model_name=data['llm_settings']['model_name'],
|
|
257
376
|
model_config={
|
|
258
|
-
"max_tokens":
|
|
259
|
-
"
|
|
377
|
+
"max_tokens": max_tokens,
|
|
378
|
+
"reasoning_effort": data['llm_settings'].get('reasoning_effort'),
|
|
260
379
|
"temperature": data['llm_settings']['temperature'],
|
|
261
380
|
"model_project_id": data['llm_settings'].get('model_project_id'),
|
|
262
381
|
}
|
|
@@ -271,13 +390,18 @@ class AlitaClient:
|
|
|
271
390
|
app_type = "react"
|
|
272
391
|
elif app_type == 'autogen':
|
|
273
392
|
app_type = "react"
|
|
393
|
+
|
|
394
|
+
# LangChainAssistant constructor calls get_tools() which may raise McpAuthorizationRequired
|
|
395
|
+
# The exception will propagate naturally to the indexer worker's outer handler
|
|
274
396
|
if runtime == 'nonrunnable':
|
|
275
397
|
return LangChainAssistant(self, data, llm, chat_history, app_type,
|
|
276
|
-
tools=tools, memory=memory, store=store
|
|
398
|
+
tools=tools, memory=memory, store=store, mcp_tokens=mcp_tokens,
|
|
399
|
+
conversation_id=conversation_id)
|
|
277
400
|
if runtime == 'langchain':
|
|
278
401
|
return LangChainAssistant(self, data, llm,
|
|
279
402
|
chat_history, app_type,
|
|
280
|
-
tools=tools, memory=memory, store=store
|
|
403
|
+
tools=tools, memory=memory, store=store, mcp_tokens=mcp_tokens,
|
|
404
|
+
conversation_id=conversation_id).runnable()
|
|
281
405
|
elif runtime == 'llama':
|
|
282
406
|
raise NotImplementedError("LLama runtime is not supported")
|
|
283
407
|
|
|
@@ -339,16 +463,50 @@ class AlitaClient:
|
|
|
339
463
|
return self._process_requst(resp)
|
|
340
464
|
|
|
341
465
|
def list_artifacts(self, bucket_name: str):
|
|
342
|
-
|
|
466
|
+
# Ensure bucket name is lowercase as required by the API
|
|
467
|
+
url = f'{self.artifacts_url}/{bucket_name.lower()}'
|
|
343
468
|
data = requests.get(url, headers=self.headers, verify=False)
|
|
344
469
|
return self._process_requst(data)
|
|
345
470
|
|
|
346
471
|
def create_artifact(self, bucket_name, artifact_name, artifact_data):
|
|
472
|
+
# Sanitize filename to prevent regex errors during indexing
|
|
473
|
+
sanitized_name, was_modified = self._sanitize_artifact_name(artifact_name)
|
|
474
|
+
if was_modified:
|
|
475
|
+
logger.warning(f"Artifact filename sanitized: '{artifact_name}' -> '{sanitized_name}'")
|
|
476
|
+
|
|
347
477
|
url = f'{self.artifacts_url}/{bucket_name.lower()}'
|
|
348
478
|
data = requests.post(url, headers=self.headers, files={
|
|
349
|
-
'file': (
|
|
479
|
+
'file': (sanitized_name, artifact_data)
|
|
350
480
|
}, verify=False)
|
|
351
481
|
return self._process_requst(data)
|
|
482
|
+
|
|
483
|
+
@staticmethod
|
|
484
|
+
def _sanitize_artifact_name(filename: str) -> tuple:
|
|
485
|
+
"""Sanitize filename for safe storage and regex pattern matching."""
|
|
486
|
+
import re
|
|
487
|
+
from pathlib import Path
|
|
488
|
+
|
|
489
|
+
if not filename or not filename.strip():
|
|
490
|
+
return "unnamed_file", True
|
|
491
|
+
|
|
492
|
+
original = filename
|
|
493
|
+
path_obj = Path(filename)
|
|
494
|
+
name = path_obj.stem
|
|
495
|
+
extension = path_obj.suffix
|
|
496
|
+
|
|
497
|
+
# Whitelist: alphanumeric, underscore, hyphen, space, Unicode letters/digits
|
|
498
|
+
sanitized_name = re.sub(r'[^\w\s-]', '', name, flags=re.UNICODE)
|
|
499
|
+
sanitized_name = re.sub(r'[-\s]+', '-', sanitized_name)
|
|
500
|
+
sanitized_name = sanitized_name.strip('-').strip()
|
|
501
|
+
|
|
502
|
+
if not sanitized_name:
|
|
503
|
+
sanitized_name = "file"
|
|
504
|
+
|
|
505
|
+
if extension:
|
|
506
|
+
extension = re.sub(r'[^\w.-]', '', extension, flags=re.UNICODE)
|
|
507
|
+
|
|
508
|
+
sanitized = sanitized_name + extension
|
|
509
|
+
return sanitized, (sanitized != original)
|
|
352
510
|
|
|
353
511
|
def download_artifact(self, bucket_name, artifact_name):
|
|
354
512
|
url = f'{self.artifact_url}/{bucket_name.lower()}/{artifact_name}'
|
|
@@ -490,25 +648,29 @@ class AlitaClient:
|
|
|
490
648
|
monitoring_meta = tasknode_task.meta.get("monitoring", {})
|
|
491
649
|
return monitoring_meta["user_id"]
|
|
492
650
|
except Exception as e:
|
|
493
|
-
logger.
|
|
651
|
+
logger.debug(f"Error: Could not determine user ID for MCP tool: {e}")
|
|
494
652
|
return None
|
|
495
653
|
|
|
496
654
|
def predict_agent(self, llm: ChatOpenAI, instructions: str = "You are a helpful assistant.",
|
|
497
655
|
tools: Optional[list] = None, chat_history: Optional[List[Any]] = None,
|
|
498
656
|
memory=None, runtime='langchain', variables: Optional[list] = None,
|
|
499
|
-
store: Optional[BaseStore] = None
|
|
657
|
+
store: Optional[BaseStore] = None, debug_mode: Optional[bool] = False,
|
|
658
|
+
mcp_tokens: Optional[dict] = None, conversation_id: Optional[str] = None):
|
|
500
659
|
"""
|
|
501
660
|
Create a predict-type agent with minimal configuration.
|
|
502
661
|
|
|
503
662
|
Args:
|
|
504
663
|
llm: The LLM to use
|
|
505
664
|
instructions: System instructions for the agent
|
|
506
|
-
tools: Optional list of
|
|
665
|
+
tools: Optional list of tool configurations (not tool instances) to provide to the agent.
|
|
666
|
+
Tool configs will be processed through get_tools() to create tool instances.
|
|
667
|
+
Each tool config should have 'type', 'settings', etc.
|
|
507
668
|
chat_history: Optional chat history
|
|
508
669
|
memory: Optional memory/checkpointer
|
|
509
670
|
runtime: Runtime type (default: 'langchain')
|
|
510
671
|
variables: Optional list of variables for the agent
|
|
511
672
|
store: Optional store for memory
|
|
673
|
+
debug_mode: Enable debug mode for cases when assistant can be initialized without tools
|
|
512
674
|
|
|
513
675
|
Returns:
|
|
514
676
|
Runnable agent ready for execution
|
|
@@ -522,17 +684,32 @@ class AlitaClient:
|
|
|
522
684
|
|
|
523
685
|
# Create a minimal data structure for predict agent
|
|
524
686
|
# All LLM settings are taken from the passed client instance
|
|
687
|
+
# Note: 'tools' here are tool CONFIGURATIONS, not tool instances
|
|
688
|
+
# They will be converted to tool instances by LangChainAssistant via get_tools()
|
|
525
689
|
agent_data = {
|
|
526
690
|
'instructions': instructions,
|
|
527
|
-
'tools': tools, #
|
|
691
|
+
'tools': tools, # Tool configs that will be processed by get_tools()
|
|
528
692
|
'variables': variables
|
|
529
693
|
}
|
|
530
|
-
|
|
531
|
-
|
|
694
|
+
|
|
695
|
+
# LangChainAssistant constructor calls get_tools() which may raise McpAuthorizationRequired
|
|
696
|
+
# The exception will propagate naturally to the indexer worker's outer handler
|
|
697
|
+
return LangChainAssistant(
|
|
698
|
+
self,
|
|
699
|
+
agent_data,
|
|
700
|
+
llm,
|
|
701
|
+
chat_history,
|
|
702
|
+
"predict",
|
|
703
|
+
memory=memory,
|
|
704
|
+
store=store,
|
|
705
|
+
debug_mode=debug_mode,
|
|
706
|
+
mcp_tokens=mcp_tokens,
|
|
707
|
+
conversation_id=conversation_id
|
|
708
|
+
).runnable()
|
|
532
709
|
|
|
533
710
|
def test_toolkit_tool(self, toolkit_config: dict, tool_name: str, tool_params: dict = None,
|
|
534
711
|
runtime_config: dict = None, llm_model: str = None,
|
|
535
|
-
llm_config: dict = None) -> dict:
|
|
712
|
+
llm_config: dict = None, mcp_tokens: dict = None) -> dict:
|
|
536
713
|
"""
|
|
537
714
|
Test a single tool from a toolkit with given parameters and runtime callbacks.
|
|
538
715
|
|
|
@@ -551,6 +728,7 @@ class AlitaClient:
|
|
|
551
728
|
- configurable: Additional configuration parameters
|
|
552
729
|
- tags: Tags for the execution
|
|
553
730
|
llm_model: Name of the LLM model to use (default: 'gpt-4o-mini')
|
|
731
|
+
mcp_tokens: Optional dictionary of MCP OAuth tokens by server URL
|
|
554
732
|
llm_config: Configuration for the LLM containing:
|
|
555
733
|
- max_tokens: Maximum tokens for response (default: 1000)
|
|
556
734
|
- temperature: Temperature for response generation (default: 0.1)
|
|
@@ -598,7 +776,6 @@ class AlitaClient:
|
|
|
598
776
|
llm_config = {
|
|
599
777
|
'max_tokens': 1024,
|
|
600
778
|
'temperature': 0.1,
|
|
601
|
-
'top_p': 1.0
|
|
602
779
|
}
|
|
603
780
|
import logging
|
|
604
781
|
logger = logging.getLogger(__name__)
|
|
@@ -669,7 +846,23 @@ class AlitaClient:
|
|
|
669
846
|
}
|
|
670
847
|
|
|
671
848
|
# Instantiate the toolkit with client and LLM support
|
|
672
|
-
|
|
849
|
+
try:
|
|
850
|
+
tools = instantiate_toolkit_with_client(toolkit_config, llm, self, mcp_tokens=mcp_tokens, use_prefix=False)
|
|
851
|
+
except McpAuthorizationRequired:
|
|
852
|
+
# Re-raise McpAuthorizationRequired to allow proper handling upstream
|
|
853
|
+
logger.info(f"McpAuthorizationRequired detected, re-raising")
|
|
854
|
+
raise
|
|
855
|
+
except Exception as toolkit_error:
|
|
856
|
+
# For other errors, return error response
|
|
857
|
+
return {
|
|
858
|
+
"success": False,
|
|
859
|
+
"error": f"Failed to instantiate toolkit '{toolkit_config.get('toolkit_name')}': {str(toolkit_error)}",
|
|
860
|
+
"tool_name": tool_name,
|
|
861
|
+
"toolkit_config": toolkit_config_parsed_json,
|
|
862
|
+
"llm_model": llm_model,
|
|
863
|
+
"events_dispatched": events_dispatched,
|
|
864
|
+
"execution_time_seconds": 0.0
|
|
865
|
+
}
|
|
673
866
|
|
|
674
867
|
if not tools:
|
|
675
868
|
return {
|
|
@@ -745,7 +938,6 @@ class AlitaClient:
|
|
|
745
938
|
if target_tool is None:
|
|
746
939
|
available_tools = []
|
|
747
940
|
base_available_tools = []
|
|
748
|
-
full_available_tools = []
|
|
749
941
|
|
|
750
942
|
for tool in tools:
|
|
751
943
|
tool_name_attr = None
|
|
@@ -762,16 +954,14 @@ class AlitaClient:
|
|
|
762
954
|
if base_name not in base_available_tools:
|
|
763
955
|
base_available_tools.append(base_name)
|
|
764
956
|
|
|
765
|
-
# Track full names separately
|
|
766
|
-
if TOOLKIT_SPLITTER in tool_name_attr:
|
|
767
|
-
full_available_tools.append(tool_name_attr)
|
|
768
|
-
|
|
769
957
|
# Create comprehensive error message
|
|
770
|
-
error_msg = f"Tool '{tool_name}' not found in toolkit '{toolkit_config.get('toolkit_name')}'
|
|
958
|
+
error_msg = f"Tool '{tool_name}' not found in toolkit '{toolkit_config.get('toolkit_name')}'.\n"
|
|
959
|
+
|
|
960
|
+
# Custom error for index tools
|
|
961
|
+
if toolkit_name in [tool.value for tool in IndexTools]:
|
|
962
|
+
error_msg += f" Please make sure proper PGVector configuration and embedding model are set in the platform.\n"
|
|
771
963
|
|
|
772
|
-
if base_available_tools
|
|
773
|
-
error_msg += f" Available tools: {base_available_tools} (base names) or {full_available_tools} (full names)"
|
|
774
|
-
elif base_available_tools:
|
|
964
|
+
if base_available_tools:
|
|
775
965
|
error_msg += f" Available tools: {base_available_tools}"
|
|
776
966
|
elif available_tools:
|
|
777
967
|
error_msg += f" Available tools: {available_tools}"
|
|
@@ -780,10 +970,7 @@ class AlitaClient:
|
|
|
780
970
|
|
|
781
971
|
# Add helpful hint about naming conventions
|
|
782
972
|
if '___' in tool_name:
|
|
783
|
-
error_msg += f" Note:
|
|
784
|
-
elif full_available_tools:
|
|
785
|
-
possible_full_name = create_full_tool_name(tool_name, toolkit_name)
|
|
786
|
-
error_msg += f" Note: You provided a base name '{tool_name}'. The full name might be '{possible_full_name}'."
|
|
973
|
+
error_msg += f" Note: Tool names no longer use '___' prefixes. Try using just the base name '{extract_base_tool_name(tool_name)}'."
|
|
787
974
|
|
|
788
975
|
return {
|
|
789
976
|
"success": False,
|
|
@@ -889,6 +1076,9 @@ class AlitaClient:
|
|
|
889
1076
|
}
|
|
890
1077
|
|
|
891
1078
|
except Exception as e:
|
|
1079
|
+
# Re-raise McpAuthorizationRequired to allow proper handling upstream
|
|
1080
|
+
if isinstance(e, McpAuthorizationRequired):
|
|
1081
|
+
raise
|
|
892
1082
|
logger = logging.getLogger(__name__)
|
|
893
1083
|
logger.error(f"Error in test_toolkit_tool: {str(e)}")
|
|
894
1084
|
return {
|
|
@@ -900,24 +1090,3 @@ class AlitaClient:
|
|
|
900
1090
|
"events_dispatched": [],
|
|
901
1091
|
"execution_time_seconds": 0.0
|
|
902
1092
|
}
|
|
903
|
-
|
|
904
|
-
def _get_real_user_id(self) -> str:
|
|
905
|
-
"""Extract the real user ID from the auth token for MCP tool calls."""
|
|
906
|
-
try:
|
|
907
|
-
import base64
|
|
908
|
-
import json
|
|
909
|
-
# Assuming JWT token, extract user ID from payload
|
|
910
|
-
# This is a basic implementation - adjust based on your token format
|
|
911
|
-
token_parts = self.auth_token.split('.')
|
|
912
|
-
if len(token_parts) >= 2:
|
|
913
|
-
payload_part = token_parts[1]
|
|
914
|
-
# Add padding if needed
|
|
915
|
-
padding = len(payload_part) % 4
|
|
916
|
-
if padding:
|
|
917
|
-
payload_part += '=' * (4 - padding)
|
|
918
|
-
payload = json.loads(base64.b64decode(payload_part))
|
|
919
|
-
return payload.get('user_id') or payload.get('sub') or payload.get('uid')
|
|
920
|
-
except Exception as e:
|
|
921
|
-
logger.error(f"Error extracting user ID from token: {e}")
|
|
922
|
-
return None
|
|
923
|
-
|