alita-sdk 0.3.257__py3-none-any.whl → 0.3.584__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of alita-sdk might be problematic. Click here for more details.
- alita_sdk/cli/__init__.py +10 -0
- alita_sdk/cli/__main__.py +17 -0
- alita_sdk/cli/agent/__init__.py +5 -0
- alita_sdk/cli/agent/default.py +258 -0
- alita_sdk/cli/agent_executor.py +155 -0
- alita_sdk/cli/agent_loader.py +215 -0
- alita_sdk/cli/agent_ui.py +228 -0
- alita_sdk/cli/agents.py +3794 -0
- alita_sdk/cli/callbacks.py +647 -0
- alita_sdk/cli/cli.py +168 -0
- alita_sdk/cli/config.py +306 -0
- alita_sdk/cli/context/__init__.py +30 -0
- alita_sdk/cli/context/cleanup.py +198 -0
- alita_sdk/cli/context/manager.py +731 -0
- alita_sdk/cli/context/message.py +285 -0
- alita_sdk/cli/context/strategies.py +289 -0
- alita_sdk/cli/context/token_estimation.py +127 -0
- alita_sdk/cli/formatting.py +182 -0
- alita_sdk/cli/input_handler.py +419 -0
- alita_sdk/cli/inventory.py +1073 -0
- alita_sdk/cli/mcp_loader.py +315 -0
- alita_sdk/cli/toolkit.py +327 -0
- alita_sdk/cli/toolkit_loader.py +85 -0
- alita_sdk/cli/tools/__init__.py +43 -0
- alita_sdk/cli/tools/approval.py +224 -0
- alita_sdk/cli/tools/filesystem.py +1751 -0
- alita_sdk/cli/tools/planning.py +389 -0
- alita_sdk/cli/tools/terminal.py +414 -0
- alita_sdk/community/__init__.py +72 -12
- alita_sdk/community/inventory/__init__.py +236 -0
- alita_sdk/community/inventory/config.py +257 -0
- alita_sdk/community/inventory/enrichment.py +2137 -0
- alita_sdk/community/inventory/extractors.py +1469 -0
- alita_sdk/community/inventory/ingestion.py +3172 -0
- alita_sdk/community/inventory/knowledge_graph.py +1457 -0
- alita_sdk/community/inventory/parsers/__init__.py +218 -0
- alita_sdk/community/inventory/parsers/base.py +295 -0
- alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
- alita_sdk/community/inventory/parsers/go_parser.py +851 -0
- alita_sdk/community/inventory/parsers/html_parser.py +389 -0
- alita_sdk/community/inventory/parsers/java_parser.py +593 -0
- alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
- alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
- alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
- alita_sdk/community/inventory/parsers/python_parser.py +604 -0
- alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
- alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
- alita_sdk/community/inventory/parsers/text_parser.py +322 -0
- alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
- alita_sdk/community/inventory/patterns/__init__.py +61 -0
- alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
- alita_sdk/community/inventory/patterns/loader.py +348 -0
- alita_sdk/community/inventory/patterns/registry.py +198 -0
- alita_sdk/community/inventory/presets.py +535 -0
- alita_sdk/community/inventory/retrieval.py +1403 -0
- alita_sdk/community/inventory/toolkit.py +173 -0
- alita_sdk/community/inventory/toolkit_utils.py +176 -0
- alita_sdk/community/inventory/visualize.py +1370 -0
- alita_sdk/configurations/__init__.py +11 -0
- alita_sdk/configurations/ado.py +148 -2
- alita_sdk/configurations/azure_search.py +1 -1
- alita_sdk/configurations/bigquery.py +1 -1
- alita_sdk/configurations/bitbucket.py +94 -2
- alita_sdk/configurations/browser.py +18 -0
- alita_sdk/configurations/carrier.py +19 -0
- alita_sdk/configurations/confluence.py +130 -1
- alita_sdk/configurations/delta_lake.py +1 -1
- alita_sdk/configurations/figma.py +76 -5
- alita_sdk/configurations/github.py +65 -1
- alita_sdk/configurations/gitlab.py +81 -0
- alita_sdk/configurations/google_places.py +17 -0
- alita_sdk/configurations/jira.py +103 -0
- alita_sdk/configurations/openapi.py +323 -0
- alita_sdk/configurations/postman.py +1 -1
- alita_sdk/configurations/qtest.py +72 -3
- alita_sdk/configurations/report_portal.py +115 -0
- alita_sdk/configurations/salesforce.py +19 -0
- alita_sdk/configurations/service_now.py +1 -12
- alita_sdk/configurations/sharepoint.py +167 -0
- alita_sdk/configurations/sonar.py +18 -0
- alita_sdk/configurations/sql.py +20 -0
- alita_sdk/configurations/testio.py +101 -0
- alita_sdk/configurations/testrail.py +88 -0
- alita_sdk/configurations/xray.py +94 -1
- alita_sdk/configurations/zephyr_enterprise.py +94 -1
- alita_sdk/configurations/zephyr_essential.py +95 -0
- alita_sdk/runtime/clients/artifact.py +21 -4
- alita_sdk/runtime/clients/client.py +458 -67
- alita_sdk/runtime/clients/mcp_discovery.py +342 -0
- alita_sdk/runtime/clients/mcp_manager.py +262 -0
- alita_sdk/runtime/clients/sandbox_client.py +352 -0
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +183 -43
- alita_sdk/runtime/langchain/constants.py +647 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaDocxMammothLoader.py +315 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +209 -31
- alita_sdk/runtime/langchain/document_loaders/AlitaImageLoader.py +1 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +10 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaMarkdownLoader.py +66 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaPDFLoader.py +79 -10
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +52 -15
- alita_sdk/runtime/langchain/document_loaders/AlitaPythonLoader.py +9 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaTableLoader.py +1 -4
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +15 -2
- alita_sdk/runtime/langchain/document_loaders/ImageParser.py +30 -0
- alita_sdk/runtime/langchain/document_loaders/constants.py +189 -41
- alita_sdk/runtime/langchain/interfaces/llm_processor.py +4 -2
- alita_sdk/runtime/langchain/langraph_agent.py +493 -105
- alita_sdk/runtime/langchain/utils.py +118 -8
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/models/mcp_models.py +61 -0
- alita_sdk/runtime/skills/__init__.py +91 -0
- alita_sdk/runtime/skills/callbacks.py +498 -0
- alita_sdk/runtime/skills/discovery.py +540 -0
- alita_sdk/runtime/skills/executor.py +610 -0
- alita_sdk/runtime/skills/input_builder.py +371 -0
- alita_sdk/runtime/skills/models.py +330 -0
- alita_sdk/runtime/skills/registry.py +355 -0
- alita_sdk/runtime/skills/skill_runner.py +330 -0
- alita_sdk/runtime/toolkits/__init__.py +28 -0
- alita_sdk/runtime/toolkits/application.py +14 -4
- alita_sdk/runtime/toolkits/artifact.py +25 -9
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +782 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +11 -6
- alita_sdk/runtime/toolkits/tools.py +314 -70
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +24 -0
- alita_sdk/runtime/tools/application.py +16 -4
- alita_sdk/runtime/tools/artifact.py +367 -33
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +100 -4
- alita_sdk/runtime/tools/graph.py +81 -0
- alita_sdk/runtime/tools/image_generation.py +218 -0
- alita_sdk/runtime/tools/llm.py +1032 -177
- alita_sdk/runtime/tools/loop.py +3 -1
- alita_sdk/runtime/tools/loop_output.py +3 -1
- alita_sdk/runtime/tools/mcp_inspect_tool.py +284 -0
- alita_sdk/runtime/tools/mcp_remote_tool.py +181 -0
- alita_sdk/runtime/tools/mcp_server_tool.py +3 -1
- alita_sdk/runtime/tools/planning/__init__.py +36 -0
- alita_sdk/runtime/tools/planning/models.py +246 -0
- alita_sdk/runtime/tools/planning/wrapper.py +607 -0
- alita_sdk/runtime/tools/router.py +2 -1
- alita_sdk/runtime/tools/sandbox.py +375 -0
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +69 -65
- alita_sdk/runtime/tools/vectorstore_base.py +163 -90
- alita_sdk/runtime/utils/AlitaCallback.py +137 -21
- alita_sdk/runtime/utils/constants.py +5 -1
- alita_sdk/runtime/utils/mcp_client.py +492 -0
- alita_sdk/runtime/utils/mcp_oauth.py +361 -0
- alita_sdk/runtime/utils/mcp_sse_client.py +434 -0
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/streamlit.py +41 -14
- alita_sdk/runtime/utils/toolkit_utils.py +28 -9
- alita_sdk/runtime/utils/utils.py +48 -0
- alita_sdk/tools/__init__.py +135 -37
- alita_sdk/tools/ado/__init__.py +2 -2
- alita_sdk/tools/ado/repos/__init__.py +16 -19
- alita_sdk/tools/ado/repos/repos_wrapper.py +12 -20
- alita_sdk/tools/ado/test_plan/__init__.py +27 -8
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +56 -28
- alita_sdk/tools/ado/wiki/__init__.py +28 -12
- alita_sdk/tools/ado/wiki/ado_wrapper.py +114 -40
- alita_sdk/tools/ado/work_item/__init__.py +28 -12
- alita_sdk/tools/ado/work_item/ado_wrapper.py +95 -11
- alita_sdk/tools/advanced_jira_mining/__init__.py +13 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +15 -11
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +14 -8
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +454 -110
- alita_sdk/tools/bitbucket/__init__.py +28 -19
- alita_sdk/tools/bitbucket/api_wrapper.py +285 -27
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +5 -5
- alita_sdk/tools/browser/__init__.py +41 -16
- alita_sdk/tools/browser/crawler.py +3 -1
- alita_sdk/tools/browser/utils.py +15 -6
- alita_sdk/tools/carrier/__init__.py +18 -17
- alita_sdk/tools/carrier/backend_reports_tool.py +8 -4
- alita_sdk/tools/carrier/excel_reporter.py +8 -4
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/codeparser.py +1 -1
- alita_sdk/tools/chunkers/sematic/json_chunker.py +2 -1
- alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
- alita_sdk/tools/chunkers/sematic/proposal_chunker.py +1 -1
- alita_sdk/tools/chunkers/universal_chunker.py +270 -0
- alita_sdk/tools/cloud/aws/__init__.py +12 -7
- alita_sdk/tools/cloud/azure/__init__.py +12 -7
- alita_sdk/tools/cloud/gcp/__init__.py +12 -7
- alita_sdk/tools/cloud/k8s/__init__.py +12 -7
- alita_sdk/tools/code/linter/__init__.py +10 -8
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +21 -13
- alita_sdk/tools/code_indexer_toolkit.py +199 -0
- alita_sdk/tools/confluence/__init__.py +22 -14
- alita_sdk/tools/confluence/api_wrapper.py +197 -58
- alita_sdk/tools/confluence/loader.py +14 -2
- alita_sdk/tools/custom_open_api/__init__.py +12 -5
- alita_sdk/tools/elastic/__init__.py +11 -8
- alita_sdk/tools/elitea_base.py +546 -64
- alita_sdk/tools/figma/__init__.py +60 -11
- alita_sdk/tools/figma/api_wrapper.py +1400 -167
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +18 -17
- alita_sdk/tools/github/api_wrapper.py +9 -26
- alita_sdk/tools/github/github_client.py +81 -12
- alita_sdk/tools/github/schemas.py +2 -1
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/gitlab/__init__.py +19 -13
- alita_sdk/tools/gitlab/api_wrapper.py +256 -80
- alita_sdk/tools/gitlab_org/__init__.py +14 -10
- alita_sdk/tools/google/bigquery/__init__.py +14 -13
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +21 -11
- alita_sdk/tools/jira/__init__.py +22 -11
- alita_sdk/tools/jira/api_wrapper.py +315 -168
- alita_sdk/tools/keycloak/__init__.py +11 -8
- alita_sdk/tools/localgit/__init__.py +9 -3
- alita_sdk/tools/localgit/local_git.py +62 -54
- alita_sdk/tools/localgit/tool.py +5 -1
- alita_sdk/tools/memory/__init__.py +38 -14
- alita_sdk/tools/non_code_indexer_toolkit.py +7 -2
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +491 -106
- alita_sdk/tools/openapi/api_wrapper.py +1357 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- alita_sdk/tools/pandas/api_wrapper.py +40 -45
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +11 -11
- alita_sdk/tools/postman/api_wrapper.py +19 -8
- alita_sdk/tools/postman/postman_analysis.py +8 -1
- alita_sdk/tools/pptx/__init__.py +11 -10
- alita_sdk/tools/qtest/__init__.py +22 -14
- alita_sdk/tools/qtest/api_wrapper.py +1784 -88
- alita_sdk/tools/rally/__init__.py +13 -10
- alita_sdk/tools/report_portal/__init__.py +23 -16
- alita_sdk/tools/salesforce/__init__.py +22 -16
- alita_sdk/tools/servicenow/__init__.py +21 -16
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +17 -14
- alita_sdk/tools/sharepoint/api_wrapper.py +179 -39
- alita_sdk/tools/sharepoint/authorization_helper.py +191 -1
- alita_sdk/tools/sharepoint/utils.py +8 -2
- alita_sdk/tools/slack/__init__.py +13 -8
- alita_sdk/tools/sql/__init__.py +22 -19
- alita_sdk/tools/sql/api_wrapper.py +71 -23
- alita_sdk/tools/testio/__init__.py +21 -13
- alita_sdk/tools/testrail/__init__.py +13 -11
- alita_sdk/tools/testrail/api_wrapper.py +214 -46
- alita_sdk/tools/utils/__init__.py +28 -4
- alita_sdk/tools/utils/content_parser.py +241 -55
- alita_sdk/tools/utils/text_operations.py +254 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +83 -27
- alita_sdk/tools/xray/__init__.py +18 -14
- alita_sdk/tools/xray/api_wrapper.py +58 -113
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +12 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +16 -9
- alita_sdk/tools/zephyr_enterprise/api_wrapper.py +30 -15
- alita_sdk/tools/zephyr_essential/__init__.py +16 -10
- alita_sdk/tools/zephyr_essential/api_wrapper.py +297 -54
- alita_sdk/tools/zephyr_essential/client.py +6 -4
- alita_sdk/tools/zephyr_scale/__init__.py +13 -8
- alita_sdk/tools/zephyr_scale/api_wrapper.py +39 -31
- alita_sdk/tools/zephyr_squad/__init__.py +12 -7
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/METADATA +184 -37
- alita_sdk-0.3.584.dist-info/RECORD +452 -0
- alita_sdk-0.3.584.dist-info/entry_points.txt +2 -0
- alita_sdk/tools/bitbucket/tools.py +0 -304
- alita_sdk-0.3.257.dist-info/RECORD +0 -343
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.257.dist-info → alita_sdk-0.3.584.dist-info}/top_level.txt +0 -0
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import json
|
|
2
|
-
import
|
|
2
|
+
from collections import OrderedDict
|
|
3
3
|
from logging import getLogger
|
|
4
4
|
from typing import Any, Optional, List, Dict, Generator
|
|
5
5
|
|
|
6
|
+
import math
|
|
6
7
|
from langchain_core.documents import Document
|
|
7
8
|
from langchain_core.messages import HumanMessage
|
|
9
|
+
from langchain_core.tools import ToolException
|
|
10
|
+
from psycopg.errors import DataException
|
|
8
11
|
from pydantic import BaseModel, model_validator, Field
|
|
9
12
|
|
|
10
13
|
from alita_sdk.tools.elitea_base import BaseToolApiWrapper
|
|
11
14
|
from alita_sdk.tools.vector_adapters.VectorStoreAdapter import VectorStoreAdapterFactory
|
|
12
|
-
from
|
|
13
|
-
from
|
|
15
|
+
from ...runtime.utils.utils import IndexerKeywords
|
|
16
|
+
from ...runtime.langchain.utils import extract_text_from_completion
|
|
14
17
|
|
|
15
18
|
logger = getLogger(__name__)
|
|
16
19
|
|
|
20
|
+
|
|
17
21
|
class IndexDocumentsModel(BaseModel):
|
|
18
22
|
documents: Any = Field(description="Generator of documents to index")
|
|
19
23
|
|
|
@@ -132,16 +136,12 @@ How did you come up with the answer?
|
|
|
132
136
|
|
|
133
137
|
class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
134
138
|
llm: Any
|
|
135
|
-
embedding_model: str
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
dataset: str = None
|
|
141
|
-
embedding: Any = None
|
|
139
|
+
embedding_model: Optional[str] = None
|
|
140
|
+
vectorstore_type: Optional[str] = None
|
|
141
|
+
vectorstore_params: Optional[dict] = None
|
|
142
|
+
max_docs_per_add: int = 20
|
|
143
|
+
dataset: Optional[str] = None
|
|
142
144
|
vectorstore: Any = None
|
|
143
|
-
# Review usage of old adapter
|
|
144
|
-
vectoradapter: Any = None
|
|
145
145
|
pg_helper: Any = None
|
|
146
146
|
embeddings: Any = None
|
|
147
147
|
# New adapter for vector database operations
|
|
@@ -150,34 +150,52 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
150
150
|
@model_validator(mode='before')
|
|
151
151
|
@classmethod
|
|
152
152
|
def validate_toolkit(cls, values):
|
|
153
|
-
from ..langchain.interfaces.llm_processor import
|
|
153
|
+
from ..langchain.interfaces.llm_processor import get_vectorstore
|
|
154
154
|
logger.debug(f"Validating toolkit: {values}")
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
raise ValueError("Embedding model parameters are required.")
|
|
163
|
-
values["dataset"] = values.get('vectorstore_params').get('collection_name')
|
|
164
|
-
if not values["dataset"]:
|
|
165
|
-
raise ValueError("Collection name is required.")
|
|
166
|
-
if not values.get('embeddings'):
|
|
167
|
-
values['embeddings'] = get_embeddings(values['embedding_model'], values['embedding_model_params'])
|
|
168
|
-
values['vectorstore'] = get_vectorstore(values['vectorstore_type'], values['vectorstore_params'], embedding_func=values['embeddings'])
|
|
169
|
-
values['vectoradapter'] = VectorAdapter(
|
|
170
|
-
vectorstore=values['vectorstore'],
|
|
171
|
-
embeddings=values['embeddings'],
|
|
172
|
-
quota_params=None,
|
|
173
|
-
)
|
|
174
|
-
# Initialize the new vector adapter
|
|
175
|
-
values['vector_adapter'] = VectorStoreAdapterFactory.create_adapter(values['vectorstore_type'])
|
|
176
|
-
logger.debug(f"Vectorstore wrapper initialized: {values}")
|
|
155
|
+
values["dataset"] = values.get('collection_name')
|
|
156
|
+
|
|
157
|
+
if values.get('alita') and values.get('embedding_model'):
|
|
158
|
+
values['embeddings'] = values.get('alita').get_embeddings(values.get('embedding_model'))
|
|
159
|
+
|
|
160
|
+
# Lazy initialization: vectorstore and vector_adapter are initialized on-demand
|
|
161
|
+
# This prevents errors when using non-index tools with broken/missing vector DB
|
|
177
162
|
return values
|
|
178
163
|
|
|
164
|
+
def _ensure_vectorstore_initialized(self):
|
|
165
|
+
"""Lazily initialize vectorstore and vector_adapter when needed for index operations."""
|
|
166
|
+
if self.vectorstore is None:
|
|
167
|
+
if not self.vectorstore_type or not self.vectorstore_params:
|
|
168
|
+
raise ToolException(
|
|
169
|
+
"Vector store is not configured. "
|
|
170
|
+
"Please ensure embedding_model and pgvector_configuration are provided."
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
from ..langchain.interfaces.llm_processor import get_vectorstore
|
|
174
|
+
try:
|
|
175
|
+
self.vectorstore = get_vectorstore(
|
|
176
|
+
self.vectorstore_type,
|
|
177
|
+
self.vectorstore_params,
|
|
178
|
+
embedding_func=self.embeddings
|
|
179
|
+
)
|
|
180
|
+
logger.debug(f"Vectorstore initialized: {self.vectorstore_type}")
|
|
181
|
+
except Exception as e:
|
|
182
|
+
raise ToolException(
|
|
183
|
+
f"Failed to initialize vector store: {str(e)}. "
|
|
184
|
+
"Check your vector database configuration and connection."
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if self.vector_adapter is None:
|
|
188
|
+
try:
|
|
189
|
+
self.vector_adapter = VectorStoreAdapterFactory.create_adapter(self.vectorstore_type)
|
|
190
|
+
logger.debug(f"Vector adapter initialized: {self.vectorstore_type}")
|
|
191
|
+
except Exception as e:
|
|
192
|
+
raise ToolException(
|
|
193
|
+
f"Failed to initialize vector adapter: {str(e)}"
|
|
194
|
+
)
|
|
195
|
+
|
|
179
196
|
def _init_pg_helper(self, language='english'):
|
|
180
197
|
"""Initialize PGVector helper if needed and not already initialized"""
|
|
198
|
+
self._ensure_vectorstore_initialized()
|
|
181
199
|
if self.pg_helper is None and hasattr(self.vectorstore, 'connection_string') and hasattr(self.vectorstore, 'collection_name'):
|
|
182
200
|
try:
|
|
183
201
|
from .pgvector_search import PGVectorSearch
|
|
@@ -191,26 +209,85 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
191
209
|
except Exception as e:
|
|
192
210
|
logger.error(f"Failed to initialize PGVectorSearch: {str(e)}")
|
|
193
211
|
|
|
212
|
+
def _similarity_search_with_score(self, query: str, filter: dict = None, k: int = 10):
|
|
213
|
+
"""
|
|
214
|
+
Perform similarity search with proper exception handling for DataException.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
query: Search query string
|
|
218
|
+
filter: Optional filter dictionary
|
|
219
|
+
k: Number of results to return
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
List of (Document, score) tuples
|
|
223
|
+
|
|
224
|
+
Raises:
|
|
225
|
+
ToolException: When DataException occurs or other search errors
|
|
226
|
+
"""
|
|
227
|
+
self._ensure_vectorstore_initialized()
|
|
228
|
+
try:
|
|
229
|
+
return self.vectorstore.similarity_search_with_score(
|
|
230
|
+
query, filter=filter, k=k
|
|
231
|
+
)
|
|
232
|
+
except DataException as dimException:
|
|
233
|
+
exception_str = str(dimException)
|
|
234
|
+
if 'different vector dimensions' in exception_str:
|
|
235
|
+
logger.error(f"Data exception: {exception_str}")
|
|
236
|
+
raise ToolException(f"Global search cannot be completed since collections were indexed using "
|
|
237
|
+
f"different embedding models. Use search within a single collection."
|
|
238
|
+
f"\nDetails: {exception_str}")
|
|
239
|
+
raise ToolException(f"Data exception during search. Possibly invalid filter: {exception_str}")
|
|
240
|
+
except Exception as e:
|
|
241
|
+
logger.error(f"Error during similarity search: {str(e)}")
|
|
242
|
+
raise ToolException(f"Search failed: {str(e)}")
|
|
243
|
+
|
|
194
244
|
def list_collections(self) -> List[str]:
|
|
195
245
|
"""List all collections in the vectorstore."""
|
|
246
|
+
self._ensure_vectorstore_initialized()
|
|
247
|
+
collections = self.vector_adapter.list_collections(self)
|
|
248
|
+
if not collections:
|
|
249
|
+
return "No indexed collections"
|
|
250
|
+
return collections
|
|
251
|
+
|
|
252
|
+
def get_index_meta(self, index_name: str):
|
|
253
|
+
self._ensure_vectorstore_initialized()
|
|
254
|
+
index_metas = self.vector_adapter.get_index_meta(self, index_name)
|
|
255
|
+
if len(index_metas) > 1:
|
|
256
|
+
raise RuntimeError(f"Multiple index_meta documents found: {index_metas}")
|
|
257
|
+
return index_metas[0] if index_metas else None
|
|
258
|
+
|
|
259
|
+
def get_indexed_count(self, index_name: str) -> int:
|
|
260
|
+
self._ensure_vectorstore_initialized()
|
|
261
|
+
from sqlalchemy.orm import Session
|
|
262
|
+
from sqlalchemy import func, or_
|
|
263
|
+
|
|
264
|
+
with Session(self.vectorstore.session_maker.bind) as session:
|
|
265
|
+
return session.query(
|
|
266
|
+
self.vectorstore.EmbeddingStore.id,
|
|
267
|
+
).filter(
|
|
268
|
+
func.jsonb_extract_path_text(self.vectorstore.EmbeddingStore.cmetadata, 'collection') == index_name,
|
|
269
|
+
or_(
|
|
270
|
+
func.jsonb_extract_path_text(self.vectorstore.EmbeddingStore.cmetadata, 'type').is_(None),
|
|
271
|
+
func.jsonb_extract_path_text(self.vectorstore.EmbeddingStore.cmetadata, 'type') != IndexerKeywords.INDEX_META_TYPE.value
|
|
272
|
+
)
|
|
273
|
+
).count()
|
|
196
274
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def _clean_collection(self, collection_suffix: str = ''):
|
|
275
|
+
def _clean_collection(self, index_name: str = '', including_index_meta: bool = False):
|
|
200
276
|
"""
|
|
201
277
|
Clean the vectorstore collection by deleting all indexed data.
|
|
202
278
|
"""
|
|
203
|
-
self.
|
|
279
|
+
self._ensure_vectorstore_initialized()
|
|
280
|
+
self._log_tool_event(
|
|
204
281
|
f"Cleaning collection '{self.dataset}'",
|
|
205
282
|
tool_name="_clean_collection"
|
|
206
283
|
)
|
|
207
|
-
self.vector_adapter.clean_collection(self,
|
|
208
|
-
self.
|
|
284
|
+
self.vector_adapter.clean_collection(self, index_name, including_index_meta)
|
|
285
|
+
self._log_tool_event(
|
|
209
286
|
f"Collection '{self.dataset}' has been cleaned. ",
|
|
210
287
|
tool_name="_clean_collection"
|
|
211
288
|
)
|
|
212
289
|
|
|
213
|
-
def index_documents(self, documents: Generator[Document, None, None],
|
|
290
|
+
def index_documents(self, documents: Generator[Document, None, None], index_name: str, progress_step: int = 20, clean_index: bool = True):
|
|
214
291
|
""" Index documents in the vectorstore.
|
|
215
292
|
|
|
216
293
|
Args:
|
|
@@ -218,24 +295,23 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
218
295
|
progress_step (int): Step for progress reporting, default is 20.
|
|
219
296
|
clean_index (bool): If True, clean the index before re-indexing all documents.
|
|
220
297
|
"""
|
|
298
|
+
self._ensure_vectorstore_initialized()
|
|
221
299
|
if clean_index:
|
|
222
|
-
self._clean_index(
|
|
300
|
+
self._clean_index(index_name)
|
|
223
301
|
|
|
224
|
-
return self._save_index(list(documents),
|
|
302
|
+
return self._save_index(list(documents), index_name, progress_step)
|
|
225
303
|
|
|
226
|
-
def _clean_index(self,
|
|
304
|
+
def _clean_index(self, index_name: str):
|
|
227
305
|
logger.info("Cleaning index before re-indexing all documents.")
|
|
228
|
-
self.
|
|
306
|
+
self._log_tool_event("Cleaning index before re-indexing all documents. Previous index will be removed", tool_name="index_documents")
|
|
229
307
|
try:
|
|
230
|
-
self._clean_collection(
|
|
231
|
-
self.
|
|
232
|
-
self.vectoradapter.vacuum()
|
|
233
|
-
self._log_data("Previous index has been removed",
|
|
308
|
+
self._clean_collection(index_name, including_index_meta=False)
|
|
309
|
+
self._log_tool_event("Previous index has been removed",
|
|
234
310
|
tool_name="index_documents")
|
|
235
311
|
except Exception as e:
|
|
236
312
|
logger.warning(f"Failed to clean index: {str(e)}. Continuing with re-indexing.")
|
|
237
313
|
|
|
238
|
-
def _save_index(self, documents: list[Document],
|
|
314
|
+
def _save_index(self, documents: list[Document], index_name: Optional[str] = None, progress_step: int = 20):
|
|
239
315
|
from ..langchain.interfaces.llm_processor import add_documents
|
|
240
316
|
#
|
|
241
317
|
for doc in documents:
|
|
@@ -243,15 +319,14 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
243
319
|
logger.warning(f"Document is missing required metadata field 'id' or 'updated_on': {doc.metadata}")
|
|
244
320
|
|
|
245
321
|
logger.debug(f"Indexing documents: {documents}")
|
|
246
|
-
logger.debug(self.vectoradapter)
|
|
247
322
|
|
|
248
|
-
# if
|
|
249
|
-
if
|
|
323
|
+
# if index_name is provided, add it to metadata of each document
|
|
324
|
+
if index_name:
|
|
250
325
|
for doc in documents:
|
|
251
326
|
if not doc.metadata.get('collection'):
|
|
252
|
-
doc.metadata['collection'] =
|
|
327
|
+
doc.metadata['collection'] = index_name
|
|
253
328
|
else:
|
|
254
|
-
doc.metadata['collection'] += f";{
|
|
329
|
+
doc.metadata['collection'] += f";{index_name}"
|
|
255
330
|
|
|
256
331
|
total_docs = len(documents)
|
|
257
332
|
documents_count = 0
|
|
@@ -261,6 +336,10 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
261
336
|
progress_step = 20 if progress_step not in range(0, 100) else progress_step
|
|
262
337
|
next_progress_point = progress_step
|
|
263
338
|
for document in documents:
|
|
339
|
+
if not document.page_content:
|
|
340
|
+
# To avoid case when all documents have empty content
|
|
341
|
+
# See llm_processor.add_documents which exclude metadata of docs with empty content
|
|
342
|
+
continue
|
|
264
343
|
documents_count += 1
|
|
265
344
|
# logger.debug(f"Indexing document: {document}")
|
|
266
345
|
try:
|
|
@@ -273,7 +352,7 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
273
352
|
if percent >= next_progress_point:
|
|
274
353
|
msg = f"Indexing progress: {percent}%. Processed {documents_count} of {total_docs} documents."
|
|
275
354
|
logger.debug(msg)
|
|
276
|
-
self.
|
|
355
|
+
self._log_tool_event(msg)
|
|
277
356
|
next_progress_point += progress_step
|
|
278
357
|
except Exception:
|
|
279
358
|
from traceback import format_exc
|
|
@@ -281,7 +360,8 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
281
360
|
return {"status": "error", "message": f"Error: {format_exc()}"}
|
|
282
361
|
if _documents:
|
|
283
362
|
add_documents(vectorstore=self.vectorstore, documents=_documents)
|
|
284
|
-
return {"status": "ok", "message": f"successfully indexed {documents_count} documents"
|
|
363
|
+
return {"status": "ok", "message": f"successfully indexed {documents_count} documents" if documents_count > 0
|
|
364
|
+
else "no documents to index"}
|
|
285
365
|
|
|
286
366
|
def search_documents(self, query:str, doctype: str = 'code',
|
|
287
367
|
filter:dict|str={}, cut_off: float=0.5,
|
|
@@ -315,7 +395,7 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
315
395
|
}
|
|
316
396
|
|
|
317
397
|
try:
|
|
318
|
-
document_items = self.
|
|
398
|
+
document_items = self._similarity_search_with_score(
|
|
319
399
|
query, filter=document_filter, k=search_top
|
|
320
400
|
)
|
|
321
401
|
# Add document results to unique docs
|
|
@@ -348,18 +428,16 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
348
428
|
}
|
|
349
429
|
|
|
350
430
|
try:
|
|
351
|
-
chunk_items = self.
|
|
431
|
+
chunk_items = self._similarity_search_with_score(
|
|
352
432
|
query, filter=chunk_filter, k=search_top
|
|
353
433
|
)
|
|
354
|
-
|
|
355
|
-
logger.debug(f"Chunk items for {chunk_type}: {chunk_items[0]}")
|
|
356
|
-
|
|
434
|
+
|
|
357
435
|
for doc, score in chunk_items:
|
|
358
436
|
# Create unique identifier for document
|
|
359
437
|
source = doc.metadata.get('source')
|
|
360
438
|
chunk_id = doc.metadata.get('chunk_id')
|
|
361
439
|
doc_id = f"{source}_{chunk_id}" if source and chunk_id else str(doc.metadata.get('id', id(doc)))
|
|
362
|
-
|
|
440
|
+
|
|
363
441
|
# Store document and its score
|
|
364
442
|
if doc_id not in unique_docs:
|
|
365
443
|
unique_docs[doc_id] = doc
|
|
@@ -379,9 +457,9 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
379
457
|
doc_filter = {
|
|
380
458
|
"$and": doc_filter_parts
|
|
381
459
|
}
|
|
382
|
-
|
|
460
|
+
|
|
383
461
|
try:
|
|
384
|
-
fetch_items = self.
|
|
462
|
+
fetch_items = self._similarity_search_with_score(
|
|
385
463
|
query, filter=doc_filter, k=1
|
|
386
464
|
)
|
|
387
465
|
if fetch_items:
|
|
@@ -395,18 +473,25 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
395
473
|
else:
|
|
396
474
|
# Default search behavior (unchanged)
|
|
397
475
|
max_search_results = 30 if search_top * 3 > 30 else search_top * 3
|
|
398
|
-
vector_items = self.
|
|
476
|
+
vector_items = self._similarity_search_with_score(
|
|
399
477
|
query, filter=filter, k=max_search_results
|
|
400
478
|
)
|
|
401
479
|
|
|
402
480
|
# Initialize document map for tracking by ID
|
|
403
481
|
doc_map = {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
482
|
+
(
|
|
483
|
+
f"{doc.metadata.get('id', f'idx_{i}')}_{doc.metadata['chunk_id']}"
|
|
484
|
+
if 'chunk_id' in doc.metadata
|
|
485
|
+
else doc.metadata.get('id', f"idx_{i}")
|
|
486
|
+
): (doc, 1 - score)
|
|
407
487
|
for i, (doc, score) in enumerate(vector_items)
|
|
408
488
|
}
|
|
409
|
-
|
|
489
|
+
|
|
490
|
+
# Sort the items by the new score in descending order
|
|
491
|
+
doc_map = OrderedDict(
|
|
492
|
+
sorted(doc_map.items(), key=lambda x: x[1][1], reverse=True)
|
|
493
|
+
)
|
|
494
|
+
|
|
410
495
|
# Process full-text search if configured
|
|
411
496
|
if full_text_search and full_text_search.get('enabled') and full_text_search.get('fields'):
|
|
412
497
|
language = full_text_search.get('language', 'english')
|
|
@@ -419,12 +504,12 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
419
504
|
for field_name in full_text_search.get('fields', []):
|
|
420
505
|
try:
|
|
421
506
|
text_results = self.pg_helper.full_text_search(field_name, query)
|
|
422
|
-
|
|
507
|
+
|
|
423
508
|
# Combine text search results with vector results
|
|
424
509
|
for result in text_results:
|
|
425
510
|
doc_id = result['id']
|
|
426
511
|
text_score = result['text_score']
|
|
427
|
-
|
|
512
|
+
|
|
428
513
|
if doc_id in doc_map:
|
|
429
514
|
# Document exists in vector results, combine scores
|
|
430
515
|
doc, vector_score = doc_map[doc_id]
|
|
@@ -542,8 +627,10 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
542
627
|
]
|
|
543
628
|
)
|
|
544
629
|
])
|
|
630
|
+
# Extract text content safely (handles both string and list content from thinking models)
|
|
631
|
+
search_query = extract_text_from_completion(result)
|
|
545
632
|
search_results = self.search_documents(
|
|
546
|
-
|
|
633
|
+
search_query, doctype, filter, cut_off, search_top,
|
|
547
634
|
full_text_search=full_text_search,
|
|
548
635
|
reranking_config=reranking_config,
|
|
549
636
|
extended_search=extended_search
|
|
@@ -572,22 +659,8 @@ class VectorStoreWrapperBase(BaseToolApiWrapper):
|
|
|
572
659
|
]
|
|
573
660
|
)
|
|
574
661
|
])
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
def _log_data(self, message: str, tool_name: str = "index_data"):
|
|
578
|
-
"""Log data and dispatch custom event for indexing progress"""
|
|
579
|
-
|
|
580
|
-
try:
|
|
581
|
-
dispatch_custom_event(
|
|
582
|
-
name="thinking_step",
|
|
583
|
-
data={
|
|
584
|
-
"message": message,
|
|
585
|
-
"tool_name": tool_name,
|
|
586
|
-
"toolkit": "vectorstore",
|
|
587
|
-
},
|
|
588
|
-
)
|
|
589
|
-
except Exception as e:
|
|
590
|
-
logger.warning(f"Failed to dispatch progress event: {str(e)}")
|
|
662
|
+
# Extract text content safely (handles both string and list content from thinking models)
|
|
663
|
+
return extract_text_from_completion(result)
|
|
591
664
|
|
|
592
665
|
def get_available_tools(self):
|
|
593
666
|
return [
|
|
@@ -23,9 +23,45 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
23
23
|
self.tokens_out = 0
|
|
24
24
|
self.pending_llm_requests = defaultdict(int)
|
|
25
25
|
self.current_model_name = 'gpt-4'
|
|
26
|
+
self._event_queue = [] # Queue for events when context is unavailable
|
|
26
27
|
#
|
|
27
28
|
super().__init__()
|
|
28
29
|
|
|
30
|
+
def _has_streamlit_context(self) -> bool:
|
|
31
|
+
"""Check if Streamlit context is available in the current thread."""
|
|
32
|
+
try:
|
|
33
|
+
# Try to import streamlit runtime context checker
|
|
34
|
+
from streamlit.runtime.scriptrunner import get_script_run_ctx
|
|
35
|
+
ctx = get_script_run_ctx()
|
|
36
|
+
return ctx is not None
|
|
37
|
+
except (ImportError, Exception) as e:
|
|
38
|
+
if self.debug:
|
|
39
|
+
log.debug(f"Streamlit context check failed: {e}")
|
|
40
|
+
return False
|
|
41
|
+
|
|
42
|
+
def _safe_streamlit_call(self, func, *args, **kwargs):
|
|
43
|
+
"""Safely execute a Streamlit UI operation, handling missing context gracefully."""
|
|
44
|
+
if not self._has_streamlit_context():
|
|
45
|
+
func_name = getattr(func, '__name__', str(func))
|
|
46
|
+
if self.debug:
|
|
47
|
+
log.warning(f"Streamlit context not available for {func_name}, queueing event")
|
|
48
|
+
# Store the event for potential replay when context is available
|
|
49
|
+
self._event_queue.append({
|
|
50
|
+
'func': func_name,
|
|
51
|
+
'args': args,
|
|
52
|
+
'kwargs': kwargs,
|
|
53
|
+
'timestamp': datetime.now(tz=timezone.utc)
|
|
54
|
+
})
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
return func(*args, **kwargs)
|
|
59
|
+
except Exception as e:
|
|
60
|
+
func_name = getattr(func, '__name__', str(func))
|
|
61
|
+
# Handle any Streamlit-specific exceptions gracefully
|
|
62
|
+
log.warning(f"Streamlit operation {func_name} failed: {e}")
|
|
63
|
+
return None
|
|
64
|
+
|
|
29
65
|
#
|
|
30
66
|
# Chain
|
|
31
67
|
#
|
|
@@ -76,10 +112,14 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
76
112
|
json.dumps(payload, ensure_ascii=False, default=lambda o: str(o))
|
|
77
113
|
)
|
|
78
114
|
|
|
79
|
-
|
|
80
|
-
|
|
115
|
+
status_widget = self._safe_streamlit_call(
|
|
116
|
+
self.st.status,
|
|
117
|
+
f"Running {payload.get('tool_name')}...",
|
|
118
|
+
expanded=True
|
|
81
119
|
)
|
|
82
|
-
|
|
120
|
+
if status_widget:
|
|
121
|
+
self.callback_state[str(run_id)] = status_widget
|
|
122
|
+
self._safe_streamlit_call(status_widget.write, f"Tool inputs: {payload}")
|
|
83
123
|
|
|
84
124
|
def on_tool_start(self, *args, run_id: UUID, **kwargs):
|
|
85
125
|
""" Callback """
|
|
@@ -88,15 +128,51 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
88
128
|
|
|
89
129
|
tool_name = args[0].get("name")
|
|
90
130
|
tool_run_id = str(run_id)
|
|
131
|
+
|
|
132
|
+
# Extract metadata from tool if available (from BaseAction.metadata)
|
|
133
|
+
# Try multiple sources for metadata with toolkit_name
|
|
134
|
+
tool_meta = args[0].copy()
|
|
135
|
+
|
|
136
|
+
# Source 1: kwargs['serialized']['metadata'] - LangChain's full tool serialization
|
|
137
|
+
if 'serialized' in kwargs and 'metadata' in kwargs['serialized']:
|
|
138
|
+
tool_meta['metadata'] = kwargs['serialized']['metadata']
|
|
139
|
+
log.info(f"[METADATA] Extracted from serialized: {kwargs['serialized']['metadata']}")
|
|
140
|
+
# Source 2: Check if metadata is directly in args[0] (some LangChain versions)
|
|
141
|
+
elif 'metadata' in args[0]:
|
|
142
|
+
tool_meta['metadata'] = args[0]['metadata']
|
|
143
|
+
log.info(f"[METADATA] Extracted from args[0]: {args[0]['metadata']}")
|
|
144
|
+
else:
|
|
145
|
+
log.info(f"[METADATA] No metadata found. args[0] keys: {list(args[0].keys())}, kwargs keys: {list(kwargs.keys())}")
|
|
146
|
+
# Fallback: Try to extract toolkit_name from description
|
|
147
|
+
description = args[0].get('description', '')
|
|
148
|
+
if description:
|
|
149
|
+
import re
|
|
150
|
+
# Try pattern 1: [Toolkit: name]
|
|
151
|
+
match = re.search(r'\[Toolkit:\s*([^\]]+)\]', description)
|
|
152
|
+
if not match:
|
|
153
|
+
# Try pattern 2: Toolkit: name at start or end
|
|
154
|
+
match = re.search(r'(?:^|\n)Toolkit:\s*([^\n]+)', description)
|
|
155
|
+
if match:
|
|
156
|
+
toolkit_name = match.group(1).strip()
|
|
157
|
+
tool_meta['metadata'] = {'toolkit_name': toolkit_name}
|
|
158
|
+
log.info(f"[METADATA] Extracted toolkit_name from description: {toolkit_name}")
|
|
159
|
+
|
|
91
160
|
payload = {
|
|
92
161
|
"tool_name": tool_name,
|
|
93
162
|
"tool_run_id": tool_run_id,
|
|
94
|
-
"tool_meta":
|
|
163
|
+
"tool_meta": tool_meta,
|
|
95
164
|
"tool_inputs": kwargs.get('inputs')
|
|
96
165
|
}
|
|
97
166
|
payload = json.loads(json.dumps(payload, ensure_ascii=False, default=lambda o: str(o)))
|
|
98
|
-
|
|
99
|
-
|
|
167
|
+
|
|
168
|
+
status_widget = self._safe_streamlit_call(
|
|
169
|
+
self.st.status,
|
|
170
|
+
f"Running {tool_name}...",
|
|
171
|
+
expanded=True
|
|
172
|
+
)
|
|
173
|
+
if status_widget:
|
|
174
|
+
self.callback_state[tool_run_id] = status_widget
|
|
175
|
+
self._safe_streamlit_call(status_widget.write, f"Tool inputs: {kwargs.get('inputs')}")
|
|
100
176
|
|
|
101
177
|
def on_tool_end(self, *args, run_id: UUID, **kwargs):
|
|
102
178
|
""" Callback """
|
|
@@ -104,11 +180,16 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
104
180
|
log.info("on_tool_end(%s, %s)", args, kwargs)
|
|
105
181
|
tool_run_id = str(run_id)
|
|
106
182
|
tool_output = args[0]
|
|
107
|
-
if self.callback_state
|
|
108
|
-
self.callback_state[tool_run_id]
|
|
109
|
-
self.
|
|
183
|
+
if self.callback_state.get(tool_run_id):
|
|
184
|
+
status_widget = self.callback_state[tool_run_id]
|
|
185
|
+
self._safe_streamlit_call(status_widget.write, f"Tool output: {tool_output}")
|
|
186
|
+
self._safe_streamlit_call(
|
|
187
|
+
status_widget.update,
|
|
188
|
+
label=f"Completed {kwargs.get('name')}",
|
|
189
|
+
state="complete",
|
|
190
|
+
expanded=False
|
|
191
|
+
)
|
|
110
192
|
self.callback_state.pop(tool_run_id, None)
|
|
111
|
-
del self.callback_state[run_id]
|
|
112
193
|
|
|
113
194
|
def on_tool_error(self, *args, run_id: UUID, **kwargs):
|
|
114
195
|
""" Callback """
|
|
@@ -116,9 +197,19 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
116
197
|
log.info("on_tool_error(%s, %s)", args, kwargs)
|
|
117
198
|
tool_run_id = str(run_id)
|
|
118
199
|
tool_exception = args[0]
|
|
119
|
-
self.callback_state
|
|
120
|
-
|
|
121
|
-
|
|
200
|
+
if self.callback_state.get(tool_run_id):
|
|
201
|
+
status_widget = self.callback_state[tool_run_id]
|
|
202
|
+
self._safe_streamlit_call(
|
|
203
|
+
status_widget.write,
|
|
204
|
+
f"{traceback.format_exception(tool_exception)}"
|
|
205
|
+
)
|
|
206
|
+
self._safe_streamlit_call(
|
|
207
|
+
status_widget.update,
|
|
208
|
+
label=f"Error {kwargs.get('name')}",
|
|
209
|
+
state="error",
|
|
210
|
+
expanded=False
|
|
211
|
+
)
|
|
212
|
+
self.callback_state.pop(tool_run_id, None)
|
|
122
213
|
|
|
123
214
|
#
|
|
124
215
|
# Agent
|
|
@@ -156,8 +247,14 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
156
247
|
self.current_model_name = metadata.get('ls_model_name', self.current_model_name)
|
|
157
248
|
llm_run_id = str(run_id)
|
|
158
249
|
|
|
159
|
-
|
|
160
|
-
|
|
250
|
+
status_widget = self._safe_streamlit_call(
|
|
251
|
+
self.st.status,
|
|
252
|
+
f"Running LLM ...",
|
|
253
|
+
expanded=True
|
|
254
|
+
)
|
|
255
|
+
if status_widget:
|
|
256
|
+
self.callback_state[llm_run_id] = status_widget
|
|
257
|
+
self._safe_streamlit_call(status_widget.write, f"LLM inputs: {messages}")
|
|
161
258
|
|
|
162
259
|
def on_llm_start(self, *args, **kwargs):
|
|
163
260
|
""" Callback """
|
|
@@ -178,16 +275,27 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
178
275
|
content = None
|
|
179
276
|
if chunk:
|
|
180
277
|
content = chunk.text
|
|
181
|
-
|
|
278
|
+
|
|
279
|
+
llm_run_id = str(run_id)
|
|
280
|
+
if self.callback_state.get(llm_run_id):
|
|
281
|
+
status_widget = self.callback_state[llm_run_id]
|
|
282
|
+
self._safe_streamlit_call(status_widget.write, content)
|
|
182
283
|
|
|
183
284
|
def on_llm_error(self, *args, run_id: UUID, **kwargs):
|
|
184
285
|
""" Callback """
|
|
185
286
|
if self.debug:
|
|
186
287
|
log.error("on_llm_error(%s, %s)", args, kwargs)
|
|
187
288
|
llm_run_id = str(run_id)
|
|
188
|
-
self.callback_state
|
|
189
|
-
|
|
190
|
-
|
|
289
|
+
if self.callback_state.get(llm_run_id):
|
|
290
|
+
status_widget = self.callback_state[llm_run_id]
|
|
291
|
+
self._safe_streamlit_call(status_widget.write, f"on_llm_error({args}, {kwargs})")
|
|
292
|
+
self._safe_streamlit_call(
|
|
293
|
+
status_widget.update,
|
|
294
|
+
label=f"Error {kwargs.get('name')}",
|
|
295
|
+
state="error",
|
|
296
|
+
expanded=False
|
|
297
|
+
)
|
|
298
|
+
self.callback_state.pop(llm_run_id, None)
|
|
191
299
|
#
|
|
192
300
|
# exception = args[0]
|
|
193
301
|
# FIXME: should we emit an error here too?
|
|
@@ -205,5 +313,13 @@ class AlitaStreamlitCallback(BaseCallbackHandler):
|
|
|
205
313
|
if self.debug:
|
|
206
314
|
log.debug("on_llm_end(%s, %s)", response, kwargs)
|
|
207
315
|
llm_run_id = str(run_id)
|
|
208
|
-
|
|
209
|
-
self.callback_state.
|
|
316
|
+
# Check if callback_state exists and is not None before accessing
|
|
317
|
+
if self.callback_state is not None and self.callback_state.get(llm_run_id):
|
|
318
|
+
status_widget = self.callback_state[llm_run_id]
|
|
319
|
+
self._safe_streamlit_call(
|
|
320
|
+
status_widget.update,
|
|
321
|
+
label=f"Completed LLM call",
|
|
322
|
+
state="complete",
|
|
323
|
+
expanded=False
|
|
324
|
+
)
|
|
325
|
+
self.callback_state.pop(llm_run_id, None)
|