aiecs 1.5.1__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.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from typing import Dict, Any, Optional
|
|
5
|
+
import jaeger_client
|
|
6
|
+
import jaeger_client.config
|
|
7
|
+
from opentracing import Span
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TracingManager:
|
|
13
|
+
"""
|
|
14
|
+
Specialized handler for distributed tracing and link tracking
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
service_name: str = "service_executor",
|
|
20
|
+
jaeger_host: Optional[str] = None,
|
|
21
|
+
jaeger_port: Optional[int] = None,
|
|
22
|
+
enable_tracing: Optional[bool] = None,
|
|
23
|
+
):
|
|
24
|
+
self.service_name = service_name
|
|
25
|
+
# Get configuration from environment variables, use defaults if not
|
|
26
|
+
# available
|
|
27
|
+
self.jaeger_host = jaeger_host or os.getenv("JAEGER_AGENT_HOST", "jaeger")
|
|
28
|
+
self.jaeger_port = jaeger_port or int(os.getenv("JAEGER_AGENT_PORT", "6831"))
|
|
29
|
+
self.enable_tracing = (
|
|
30
|
+
enable_tracing
|
|
31
|
+
if enable_tracing is not None
|
|
32
|
+
else os.getenv("JAEGER_ENABLE_TRACING", "true").lower() == "true"
|
|
33
|
+
)
|
|
34
|
+
self.tracer = None
|
|
35
|
+
|
|
36
|
+
if self.enable_tracing:
|
|
37
|
+
self._init_tracer()
|
|
38
|
+
|
|
39
|
+
def _init_tracer(self):
|
|
40
|
+
"""Initialize Jaeger tracer"""
|
|
41
|
+
try:
|
|
42
|
+
config = jaeger_client.config.Config(
|
|
43
|
+
config={
|
|
44
|
+
"sampler": {
|
|
45
|
+
"type": "const",
|
|
46
|
+
"param": 1,
|
|
47
|
+
},
|
|
48
|
+
"local_agent": {
|
|
49
|
+
"reporting_host": self.jaeger_host,
|
|
50
|
+
"reporting_port": self.jaeger_port,
|
|
51
|
+
},
|
|
52
|
+
"logging": True,
|
|
53
|
+
},
|
|
54
|
+
service_name=self.service_name,
|
|
55
|
+
validate=True,
|
|
56
|
+
)
|
|
57
|
+
self.tracer = config.initialize_tracer()
|
|
58
|
+
logger.info(
|
|
59
|
+
f"Jaeger tracer initialized for service '{self.service_name}' at {self.jaeger_host}:{self.jaeger_port}"
|
|
60
|
+
)
|
|
61
|
+
except Exception as e:
|
|
62
|
+
logger.warning(f"Failed to initialize Jaeger tracer: {e}")
|
|
63
|
+
self.tracer = None
|
|
64
|
+
self.enable_tracing = False
|
|
65
|
+
|
|
66
|
+
def start_span(
|
|
67
|
+
self,
|
|
68
|
+
operation_name: str,
|
|
69
|
+
parent_span: Optional[Span] = None,
|
|
70
|
+
tags: Optional[Dict[str, Any]] = None,
|
|
71
|
+
) -> Optional[Span]:
|
|
72
|
+
"""
|
|
73
|
+
Start a tracing span
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
operation_name: Operation name
|
|
77
|
+
parent_span: Parent span
|
|
78
|
+
tags: Initial tags
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
Span object or None (if tracing is not enabled)
|
|
82
|
+
"""
|
|
83
|
+
if not self.enable_tracing or not self.tracer:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
span = self.tracer.start_span(operation_name=operation_name, child_of=parent_span)
|
|
88
|
+
|
|
89
|
+
# Set initial tags
|
|
90
|
+
if tags:
|
|
91
|
+
for key, value in tags.items():
|
|
92
|
+
span.set_tag(key, value)
|
|
93
|
+
|
|
94
|
+
# Set service information
|
|
95
|
+
span.set_tag("service.name", self.service_name)
|
|
96
|
+
span.set_tag("span.kind", "server")
|
|
97
|
+
|
|
98
|
+
return span
|
|
99
|
+
except Exception as e:
|
|
100
|
+
logger.error(f"Error starting span '{operation_name}': {e}")
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
def finish_span(
|
|
104
|
+
self,
|
|
105
|
+
span: Optional[Span],
|
|
106
|
+
tags: Optional[Dict[str, Any]] = None,
|
|
107
|
+
logs: Optional[Dict[str, Any]] = None,
|
|
108
|
+
error: Optional[Exception] = None,
|
|
109
|
+
):
|
|
110
|
+
"""
|
|
111
|
+
Finish tracing span
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
span: Span to finish
|
|
115
|
+
tags: Additional tags
|
|
116
|
+
logs: Log information
|
|
117
|
+
error: Error information
|
|
118
|
+
"""
|
|
119
|
+
if not span or not self.enable_tracing:
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
# Add additional tags
|
|
124
|
+
if tags:
|
|
125
|
+
for key, value in tags.items():
|
|
126
|
+
span.set_tag(key, value)
|
|
127
|
+
|
|
128
|
+
# Record error
|
|
129
|
+
if error:
|
|
130
|
+
span.set_tag("error", True)
|
|
131
|
+
span.set_tag("error.kind", type(error).__name__)
|
|
132
|
+
span.set_tag("error.message", str(error))
|
|
133
|
+
span.log_kv({"event": "error", "error.object": error})
|
|
134
|
+
|
|
135
|
+
# Add logs
|
|
136
|
+
if logs:
|
|
137
|
+
span.log_kv(logs)
|
|
138
|
+
|
|
139
|
+
span.finish()
|
|
140
|
+
except Exception as e:
|
|
141
|
+
logger.error(f"Error finishing span: {e}")
|
|
142
|
+
|
|
143
|
+
def with_tracing(self, operation_name: str, tags: Optional[Dict[str, Any]] = None):
|
|
144
|
+
"""
|
|
145
|
+
Tracing decorator
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
operation_name: Operation name
|
|
149
|
+
tags: Initial tags
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def decorator(func):
|
|
153
|
+
@functools.wraps(func)
|
|
154
|
+
async def async_wrapper(*args, **kwargs):
|
|
155
|
+
if not self.enable_tracing or not self.tracer:
|
|
156
|
+
return await func(*args, **kwargs)
|
|
157
|
+
|
|
158
|
+
span = self.start_span(operation_name, tags=tags)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
# Add function arguments as tags
|
|
162
|
+
self._add_function_args_to_span(span, args, kwargs)
|
|
163
|
+
|
|
164
|
+
result = await func(*args, **kwargs)
|
|
165
|
+
|
|
166
|
+
# Record success
|
|
167
|
+
if span:
|
|
168
|
+
span.set_tag("success", True)
|
|
169
|
+
|
|
170
|
+
return result
|
|
171
|
+
except Exception as e:
|
|
172
|
+
self.finish_span(span, error=e)
|
|
173
|
+
raise
|
|
174
|
+
finally:
|
|
175
|
+
if span and not span.finished:
|
|
176
|
+
self.finish_span(span)
|
|
177
|
+
|
|
178
|
+
@functools.wraps(func)
|
|
179
|
+
def sync_wrapper(*args, **kwargs):
|
|
180
|
+
if not self.enable_tracing or not self.tracer:
|
|
181
|
+
return func(*args, **kwargs)
|
|
182
|
+
|
|
183
|
+
span = self.start_span(operation_name, tags=tags)
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
# Add function arguments as tags
|
|
187
|
+
self._add_function_args_to_span(span, args, kwargs)
|
|
188
|
+
|
|
189
|
+
result = func(*args, **kwargs)
|
|
190
|
+
|
|
191
|
+
# Record success
|
|
192
|
+
if span:
|
|
193
|
+
span.set_tag("success", True)
|
|
194
|
+
|
|
195
|
+
return result
|
|
196
|
+
except Exception as e:
|
|
197
|
+
self.finish_span(span, error=e)
|
|
198
|
+
raise
|
|
199
|
+
finally:
|
|
200
|
+
if span and not span.finished:
|
|
201
|
+
self.finish_span(span)
|
|
202
|
+
|
|
203
|
+
# Return appropriate wrapper based on function type
|
|
204
|
+
import asyncio
|
|
205
|
+
|
|
206
|
+
if asyncio.iscoroutinefunction(func):
|
|
207
|
+
return async_wrapper
|
|
208
|
+
else:
|
|
209
|
+
return sync_wrapper
|
|
210
|
+
|
|
211
|
+
return decorator
|
|
212
|
+
|
|
213
|
+
def _add_function_args_to_span(self, span: Optional[Span], args: tuple, kwargs: Dict[str, Any]):
|
|
214
|
+
"""Add function arguments to span tags"""
|
|
215
|
+
if not span:
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
# Add positional arguments
|
|
220
|
+
for i, arg in enumerate(args):
|
|
221
|
+
if isinstance(arg, (str, int, float, bool)):
|
|
222
|
+
span.set_tag(f"arg_{i}", arg)
|
|
223
|
+
elif hasattr(arg, "__class__"):
|
|
224
|
+
span.set_tag(f"arg_{i}_type", arg.__class__.__name__)
|
|
225
|
+
|
|
226
|
+
# Add keyword arguments
|
|
227
|
+
for key, value in kwargs.items():
|
|
228
|
+
if isinstance(value, (str, int, float, bool)):
|
|
229
|
+
span.set_tag(key, value)
|
|
230
|
+
# Avoid overly large dictionaries
|
|
231
|
+
elif isinstance(value, dict) and len(str(value)) < 1000:
|
|
232
|
+
span.set_tag(f"{key}_json", str(value))
|
|
233
|
+
elif hasattr(value, "__class__"):
|
|
234
|
+
span.set_tag(f"{key}_type", value.__class__.__name__)
|
|
235
|
+
except Exception as e:
|
|
236
|
+
logger.debug(f"Error adding function args to span: {e}")
|
|
237
|
+
|
|
238
|
+
def trace_database_operation(self, operation: str, table: str = None, query: str = None):
|
|
239
|
+
"""Database operation tracing decorator"""
|
|
240
|
+
|
|
241
|
+
def decorator(func):
|
|
242
|
+
@functools.wraps(func)
|
|
243
|
+
async def wrapper(*args, **kwargs):
|
|
244
|
+
tags = {
|
|
245
|
+
"component": "database",
|
|
246
|
+
"db.type": "postgresql",
|
|
247
|
+
"db.statement.type": operation,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if table:
|
|
251
|
+
tags["db.table"] = table
|
|
252
|
+
if query:
|
|
253
|
+
tags["db.statement"] = query[:500] # Limit query length
|
|
254
|
+
|
|
255
|
+
span = self.start_span(f"db.{operation}", tags=tags)
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
result = await func(*args, **kwargs)
|
|
259
|
+
if span:
|
|
260
|
+
span.set_tag(
|
|
261
|
+
"db.rows_affected",
|
|
262
|
+
len(result) if isinstance(result, list) else 1,
|
|
263
|
+
)
|
|
264
|
+
return result
|
|
265
|
+
except Exception as e:
|
|
266
|
+
self.finish_span(span, error=e)
|
|
267
|
+
raise
|
|
268
|
+
finally:
|
|
269
|
+
if span and not span.finished:
|
|
270
|
+
self.finish_span(span)
|
|
271
|
+
|
|
272
|
+
return wrapper
|
|
273
|
+
|
|
274
|
+
return decorator
|
|
275
|
+
|
|
276
|
+
def trace_external_call(self, service_name: str, endpoint: str = None):
|
|
277
|
+
"""External service call tracing decorator"""
|
|
278
|
+
|
|
279
|
+
def decorator(func):
|
|
280
|
+
@functools.wraps(func)
|
|
281
|
+
async def wrapper(*args, **kwargs):
|
|
282
|
+
tags = {
|
|
283
|
+
"component": "http",
|
|
284
|
+
"span.kind": "client",
|
|
285
|
+
"peer.service": service_name,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if endpoint:
|
|
289
|
+
tags["http.url"] = endpoint
|
|
290
|
+
|
|
291
|
+
span = self.start_span(f"http.{service_name}", tags=tags)
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
result = await func(*args, **kwargs)
|
|
295
|
+
if span:
|
|
296
|
+
span.set_tag("http.status_code", 200)
|
|
297
|
+
return result
|
|
298
|
+
except Exception as e:
|
|
299
|
+
if span:
|
|
300
|
+
span.set_tag("http.status_code", 500)
|
|
301
|
+
self.finish_span(span, error=e)
|
|
302
|
+
raise
|
|
303
|
+
finally:
|
|
304
|
+
if span and not span.finished:
|
|
305
|
+
self.finish_span(span)
|
|
306
|
+
|
|
307
|
+
return wrapper
|
|
308
|
+
|
|
309
|
+
return decorator
|
|
310
|
+
|
|
311
|
+
def trace_tool_execution(self, tool_name: str, operation: str):
|
|
312
|
+
"""Tool execution tracing decorator"""
|
|
313
|
+
|
|
314
|
+
def decorator(func):
|
|
315
|
+
@functools.wraps(func)
|
|
316
|
+
async def wrapper(*args, **kwargs):
|
|
317
|
+
tags = {
|
|
318
|
+
"component": "tool",
|
|
319
|
+
"tool.name": tool_name,
|
|
320
|
+
"tool.operation": operation,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
span = self.start_span(f"tool.{tool_name}.{operation}", tags=tags)
|
|
324
|
+
|
|
325
|
+
try:
|
|
326
|
+
result = await func(*args, **kwargs)
|
|
327
|
+
if span:
|
|
328
|
+
span.set_tag("tool.success", True)
|
|
329
|
+
if hasattr(result, "__len__"):
|
|
330
|
+
span.set_tag("tool.result_size", len(result))
|
|
331
|
+
return result
|
|
332
|
+
except Exception as e:
|
|
333
|
+
if span:
|
|
334
|
+
span.set_tag("tool.success", False)
|
|
335
|
+
self.finish_span(span, error=e)
|
|
336
|
+
raise
|
|
337
|
+
finally:
|
|
338
|
+
if span and not span.finished:
|
|
339
|
+
self.finish_span(span)
|
|
340
|
+
|
|
341
|
+
return wrapper
|
|
342
|
+
|
|
343
|
+
return decorator
|
|
344
|
+
|
|
345
|
+
def create_child_span(
|
|
346
|
+
self,
|
|
347
|
+
parent_span: Optional[Span],
|
|
348
|
+
operation_name: str,
|
|
349
|
+
tags: Optional[Dict[str, Any]] = None,
|
|
350
|
+
) -> Optional[Span]:
|
|
351
|
+
"""Create child span"""
|
|
352
|
+
if not self.enable_tracing or not parent_span:
|
|
353
|
+
return None
|
|
354
|
+
|
|
355
|
+
return self.start_span(operation_name, parent_span=parent_span, tags=tags)
|
|
356
|
+
|
|
357
|
+
def inject_span_context(self, span: Optional[Span], carrier: Dict[str, str]):
|
|
358
|
+
"""Inject span context into carrier (for cross-service propagation)"""
|
|
359
|
+
if not self.enable_tracing or not span or not self.tracer:
|
|
360
|
+
return
|
|
361
|
+
|
|
362
|
+
try:
|
|
363
|
+
from opentracing.propagation import Format
|
|
364
|
+
|
|
365
|
+
self.tracer.inject(span.context, Format.TEXT_MAP, carrier)
|
|
366
|
+
except Exception as e:
|
|
367
|
+
logger.error(f"Error injecting span context: {e}")
|
|
368
|
+
|
|
369
|
+
def extract_span_context(self, carrier: Dict[str, str]) -> Optional[Any]:
|
|
370
|
+
"""Extract span context from carrier"""
|
|
371
|
+
if not self.enable_tracing or not self.tracer:
|
|
372
|
+
return None
|
|
373
|
+
|
|
374
|
+
try:
|
|
375
|
+
from opentracing.propagation import Format
|
|
376
|
+
|
|
377
|
+
return self.tracer.extract(Format.TEXT_MAP, carrier)
|
|
378
|
+
except Exception as e:
|
|
379
|
+
logger.error(f"Error extracting span context: {e}")
|
|
380
|
+
return None
|
|
381
|
+
|
|
382
|
+
def get_active_span(self) -> Optional[Span]:
|
|
383
|
+
"""Get current active span"""
|
|
384
|
+
if not self.enable_tracing or not self.tracer:
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
try:
|
|
388
|
+
return self.tracer.active_span
|
|
389
|
+
except Exception as e:
|
|
390
|
+
logger.error(f"Error getting active span: {e}")
|
|
391
|
+
return None
|
|
392
|
+
|
|
393
|
+
def close_tracer(self):
|
|
394
|
+
"""Close tracer"""
|
|
395
|
+
if self.tracer:
|
|
396
|
+
try:
|
|
397
|
+
self.tracer.close()
|
|
398
|
+
logger.info("Tracer closed successfully")
|
|
399
|
+
except Exception as e:
|
|
400
|
+
logger.error(f"Error closing tracer: {e}")
|
|
401
|
+
|
|
402
|
+
def get_tracer_info(self) -> Dict[str, Any]:
|
|
403
|
+
"""Get tracer information"""
|
|
404
|
+
return {
|
|
405
|
+
"enabled": self.enable_tracing,
|
|
406
|
+
"service_name": self.service_name,
|
|
407
|
+
"jaeger_host": self.jaeger_host,
|
|
408
|
+
"jaeger_port": self.jaeger_port,
|
|
409
|
+
"tracer_initialized": self.tracer is not None,
|
|
410
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Infrastructure persistence module
|
|
2
|
+
|
|
3
|
+
Contains data persistence and storage infrastructure.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .database_manager import DatabaseManager
|
|
7
|
+
from .redis_client import RedisClient
|
|
8
|
+
from .context_engine_client import (
|
|
9
|
+
initialize_context_engine,
|
|
10
|
+
get_context_engine,
|
|
11
|
+
close_context_engine,
|
|
12
|
+
is_context_engine_initialized,
|
|
13
|
+
reset_context_engine,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"DatabaseManager",
|
|
18
|
+
"RedisClient",
|
|
19
|
+
"initialize_context_engine",
|
|
20
|
+
"get_context_engine",
|
|
21
|
+
"close_context_engine",
|
|
22
|
+
"is_context_engine_initialized",
|
|
23
|
+
"reset_context_engine",
|
|
24
|
+
]
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Global ContextEngine Manager
|
|
3
|
+
|
|
4
|
+
This module provides a singleton ContextEngine instance that can be shared
|
|
5
|
+
across all components in the application. It follows the same pattern as
|
|
6
|
+
the Redis client initialization in aiecs.infrastructure.persistence.redis_client.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
# In main.py startup:
|
|
10
|
+
await initialize_context_engine()
|
|
11
|
+
|
|
12
|
+
# In any component:
|
|
13
|
+
from aiecs.infrastructure.persistence.context_engine_client import get_context_engine
|
|
14
|
+
context_engine = get_context_engine()
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import logging
|
|
18
|
+
from typing import Optional, TYPE_CHECKING
|
|
19
|
+
import asyncio
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from aiecs.domain.context.context_engine import ContextEngine
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
# Global singleton instance
|
|
27
|
+
_global_context_engine: Optional["ContextEngine"] = None
|
|
28
|
+
_initialization_lock = asyncio.Lock()
|
|
29
|
+
_initialized = False
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _get_context_engine_class():
|
|
33
|
+
"""Lazy import of ContextEngine to avoid circular dependencies."""
|
|
34
|
+
try:
|
|
35
|
+
from aiecs.domain.context.context_engine import ContextEngine
|
|
36
|
+
|
|
37
|
+
return ContextEngine
|
|
38
|
+
except ImportError as e:
|
|
39
|
+
logger.warning(f"ContextEngine not available - {e}")
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def initialize_context_engine(
|
|
44
|
+
use_existing_redis: bool = True,
|
|
45
|
+
) -> Optional["ContextEngine"]:
|
|
46
|
+
"""
|
|
47
|
+
Initialize the global ContextEngine instance.
|
|
48
|
+
|
|
49
|
+
This should be called once during application startup (in main.py lifespan).
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
use_existing_redis: Whether to use existing Redis client (default: True)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The initialized ContextEngine instance or None if initialization fails
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
@asynccontextmanager
|
|
59
|
+
async def lifespan(app: FastAPI):
|
|
60
|
+
# Startup
|
|
61
|
+
await initialize_redis_client()
|
|
62
|
+
await initialize_context_engine() # Initialize after Redis
|
|
63
|
+
yield
|
|
64
|
+
# Shutdown
|
|
65
|
+
await close_context_engine()
|
|
66
|
+
await close_redis_client()
|
|
67
|
+
"""
|
|
68
|
+
global _global_context_engine, _initialized
|
|
69
|
+
|
|
70
|
+
if _initialized and _global_context_engine:
|
|
71
|
+
logger.info("ContextEngine already initialized")
|
|
72
|
+
return _global_context_engine
|
|
73
|
+
|
|
74
|
+
async with _initialization_lock:
|
|
75
|
+
# Double-check after acquiring lock
|
|
76
|
+
if _initialized and _global_context_engine:
|
|
77
|
+
return _global_context_engine
|
|
78
|
+
|
|
79
|
+
ContextEngine = _get_context_engine_class()
|
|
80
|
+
if not ContextEngine:
|
|
81
|
+
logger.error("ContextEngine class not available - cannot initialize")
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
logger.info("Initializing global ContextEngine...")
|
|
86
|
+
_global_context_engine = ContextEngine(use_existing_redis=use_existing_redis)
|
|
87
|
+
await _global_context_engine.initialize()
|
|
88
|
+
_initialized = True
|
|
89
|
+
logger.info("✅ Global ContextEngine initialized successfully")
|
|
90
|
+
return _global_context_engine
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"❌ Failed to initialize global ContextEngine: {e}")
|
|
94
|
+
logger.warning("Application will continue without ContextEngine (degraded mode)")
|
|
95
|
+
_global_context_engine = None
|
|
96
|
+
_initialized = False
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_context_engine() -> Optional["ContextEngine"]:
|
|
101
|
+
"""
|
|
102
|
+
Get the global ContextEngine instance.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The global ContextEngine instance or None if not initialized
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
from aiecs.infrastructure.persistence.context_engine_client import get_context_engine
|
|
109
|
+
|
|
110
|
+
context_engine = get_context_engine()
|
|
111
|
+
if context_engine:
|
|
112
|
+
await context_engine.add_conversation_message(...)
|
|
113
|
+
else:
|
|
114
|
+
# Fallback to local storage
|
|
115
|
+
logger.warning("ContextEngine not available")
|
|
116
|
+
"""
|
|
117
|
+
if not _initialized:
|
|
118
|
+
logger.warning(
|
|
119
|
+
"ContextEngine not initialized. Call initialize_context_engine() "
|
|
120
|
+
"during application startup."
|
|
121
|
+
)
|
|
122
|
+
return _global_context_engine
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
async def close_context_engine() -> None:
|
|
126
|
+
"""
|
|
127
|
+
Close and cleanup the global ContextEngine instance.
|
|
128
|
+
|
|
129
|
+
This should be called during application shutdown (in main.py lifespan).
|
|
130
|
+
|
|
131
|
+
Example:
|
|
132
|
+
@asynccontextmanager
|
|
133
|
+
async def lifespan(app: FastAPI):
|
|
134
|
+
# Startup
|
|
135
|
+
await initialize_context_engine()
|
|
136
|
+
yield
|
|
137
|
+
# Shutdown
|
|
138
|
+
await close_context_engine()
|
|
139
|
+
"""
|
|
140
|
+
global _global_context_engine, _initialized
|
|
141
|
+
|
|
142
|
+
async with _initialization_lock:
|
|
143
|
+
if _global_context_engine:
|
|
144
|
+
try:
|
|
145
|
+
logger.info("Closing global ContextEngine...")
|
|
146
|
+
# ContextEngine cleanup if needed
|
|
147
|
+
if hasattr(_global_context_engine, "close"):
|
|
148
|
+
await _global_context_engine.close()
|
|
149
|
+
logger.info("✅ Global ContextEngine closed successfully")
|
|
150
|
+
except Exception as e:
|
|
151
|
+
logger.error(f"Error closing ContextEngine: {e}")
|
|
152
|
+
finally:
|
|
153
|
+
_global_context_engine = None
|
|
154
|
+
_initialized = False
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def is_context_engine_initialized() -> bool:
|
|
158
|
+
"""
|
|
159
|
+
Check if the global ContextEngine is initialized.
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
True if ContextEngine is initialized and available, False otherwise
|
|
163
|
+
"""
|
|
164
|
+
return _initialized and _global_context_engine is not None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Convenience function for testing
|
|
168
|
+
async def reset_context_engine() -> None:
|
|
169
|
+
"""
|
|
170
|
+
Reset the global ContextEngine instance.
|
|
171
|
+
|
|
172
|
+
This is primarily for testing purposes to allow re-initialization.
|
|
173
|
+
Should NOT be used in production code.
|
|
174
|
+
"""
|
|
175
|
+
global _global_context_engine, _initialized
|
|
176
|
+
|
|
177
|
+
async with _initialization_lock:
|
|
178
|
+
if _global_context_engine:
|
|
179
|
+
try:
|
|
180
|
+
if hasattr(_global_context_engine, "close"):
|
|
181
|
+
await _global_context_engine.close()
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.warning(f"Error during ContextEngine reset: {e}")
|
|
184
|
+
|
|
185
|
+
_global_context_engine = None
|
|
186
|
+
_initialized = False
|
|
187
|
+
logger.info("ContextEngine reset completed")
|