aiecs 1.0.1__py3-none-any.whl → 1.7.6__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 aiecs might be problematic. Click here for more details.
- aiecs/__init__.py +13 -16
- aiecs/__main__.py +7 -7
- aiecs/aiecs_client.py +269 -75
- aiecs/application/executors/operation_executor.py +79 -54
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/data_quality.py +302 -0
- aiecs/application/knowledge_graph/builder/data_reshaping.py +293 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +369 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +490 -0
- aiecs/application/knowledge_graph/builder/import_optimizer.py +396 -0
- aiecs/application/knowledge_graph/builder/schema_inference.py +462 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +563 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +1384 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +317 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +98 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +422 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +347 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +241 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +78 -0
- aiecs/application/knowledge_graph/fusion/ab_testing.py +395 -0
- aiecs/application/knowledge_graph/fusion/abbreviation_expander.py +327 -0
- aiecs/application/knowledge_graph/fusion/alias_index.py +597 -0
- aiecs/application/knowledge_graph/fusion/alias_matcher.py +384 -0
- aiecs/application/knowledge_graph/fusion/cache_coordinator.py +343 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +433 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +511 -0
- aiecs/application/knowledge_graph/fusion/evaluation_dataset.py +240 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +632 -0
- aiecs/application/knowledge_graph/fusion/matching_config.py +489 -0
- aiecs/application/knowledge_graph/fusion/name_normalizer.py +352 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +183 -0
- aiecs/application/knowledge_graph/fusion/semantic_name_matcher.py +464 -0
- aiecs/application/knowledge_graph/fusion/similarity_pipeline.py +534 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +342 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +366 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +195 -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 +341 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +500 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +163 -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 +913 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +866 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +475 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +396 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +208 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +170 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +855 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +518 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +27 -0
- aiecs/application/knowledge_graph/retrieval/query_intent_classifier.py +211 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +592 -0
- aiecs/application/knowledge_graph/retrieval/strategy_types.py +23 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +457 -0
- aiecs/application/knowledge_graph/search/reranker.py +293 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +535 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +392 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +305 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +271 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +239 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +313 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +471 -0
- aiecs/config/__init__.py +20 -5
- aiecs/config/config.py +762 -31
- aiecs/config/graph_config.py +131 -0
- aiecs/config/tool_config.py +399 -0
- aiecs/core/__init__.py +29 -13
- aiecs/core/interface/__init__.py +2 -2
- aiecs/core/interface/execution_interface.py +22 -22
- aiecs/core/interface/storage_interface.py +37 -88
- aiecs/core/registry/__init__.py +31 -0
- aiecs/core/registry/service_registry.py +92 -0
- aiecs/domain/__init__.py +270 -1
- aiecs/domain/agent/__init__.py +191 -0
- aiecs/domain/agent/base_agent.py +3870 -0
- aiecs/domain/agent/exceptions.py +99 -0
- aiecs/domain/agent/graph_aware_mixin.py +569 -0
- aiecs/domain/agent/hybrid_agent.py +1435 -0
- aiecs/domain/agent/integration/__init__.py +29 -0
- aiecs/domain/agent/integration/context_compressor.py +216 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +587 -0
- aiecs/domain/agent/integration/protocols.py +281 -0
- aiecs/domain/agent/integration/retry_policy.py +218 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +1892 -0
- aiecs/domain/agent/lifecycle.py +291 -0
- aiecs/domain/agent/llm_agent.py +692 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +1124 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +163 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +86 -0
- aiecs/domain/agent/models.py +884 -0
- aiecs/domain/agent/observability.py +479 -0
- aiecs/domain/agent/persistence.py +449 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +159 -0
- aiecs/domain/agent/prompts/formatters.py +187 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +253 -0
- aiecs/domain/agent/tool_agent.py +444 -0
- aiecs/domain/agent/tools/__init__.py +15 -0
- aiecs/domain/agent/tools/schema_generator.py +364 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +469 -0
- aiecs/domain/community/analytics.py +432 -0
- aiecs/domain/community/collaborative_workflow.py +648 -0
- aiecs/domain/community/communication_hub.py +634 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +796 -0
- aiecs/domain/community/community_manager.py +803 -0
- aiecs/domain/community/decision_engine.py +849 -0
- aiecs/domain/community/exceptions.py +231 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +234 -0
- aiecs/domain/community/resource_manager.py +461 -0
- aiecs/domain/community/shared_context_manager.py +589 -0
- aiecs/domain/context/__init__.py +40 -10
- aiecs/domain/context/context_engine.py +1910 -0
- aiecs/domain/context/conversation_models.py +87 -53
- aiecs/domain/context/graph_memory.py +582 -0
- aiecs/domain/execution/model.py +12 -4
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +148 -0
- aiecs/domain/knowledge_graph/models/evidence.py +178 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +184 -0
- aiecs/domain/knowledge_graph/models/path.py +171 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +171 -0
- aiecs/domain/knowledge_graph/models/query.py +261 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +181 -0
- aiecs/domain/knowledge_graph/models/relation.py +202 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +131 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +253 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +143 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +163 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +691 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +209 -0
- aiecs/domain/task/dsl_processor.py +172 -56
- aiecs/domain/task/model.py +20 -8
- aiecs/domain/task/task_context.py +27 -24
- aiecs/infrastructure/__init__.py +0 -2
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +837 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +458 -0
- aiecs/infrastructure/graph_storage/cache.py +424 -0
- aiecs/infrastructure/graph_storage/distributed.py +223 -0
- aiecs/infrastructure/graph_storage/error_handling.py +380 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +294 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +1197 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +446 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +431 -0
- aiecs/infrastructure/graph_storage/metrics.py +344 -0
- aiecs/infrastructure/graph_storage/migration.py +400 -0
- aiecs/infrastructure/graph_storage/pagination.py +483 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +456 -0
- aiecs/infrastructure/graph_storage/postgres.py +1563 -0
- aiecs/infrastructure/graph_storage/property_storage.py +353 -0
- aiecs/infrastructure/graph_storage/protocols.py +76 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +642 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +1373 -0
- aiecs/infrastructure/graph_storage/streaming.py +487 -0
- aiecs/infrastructure/graph_storage/tenant.py +412 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +92 -54
- aiecs/infrastructure/messaging/websocket_manager.py +51 -35
- aiecs/infrastructure/monitoring/__init__.py +22 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +45 -11
- aiecs/infrastructure/monitoring/global_metrics_manager.py +212 -0
- aiecs/infrastructure/monitoring/structured_logger.py +3 -7
- aiecs/infrastructure/monitoring/tracing_manager.py +63 -35
- aiecs/infrastructure/persistence/__init__.py +14 -1
- aiecs/infrastructure/persistence/context_engine_client.py +184 -0
- aiecs/infrastructure/persistence/database_manager.py +67 -43
- aiecs/infrastructure/persistence/file_storage.py +180 -103
- aiecs/infrastructure/persistence/redis_client.py +74 -21
- aiecs/llm/__init__.py +73 -25
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/{custom_callbacks.py → callbacks/custom_callbacks.py} +26 -19
- aiecs/llm/client_factory.py +224 -36
- aiecs/llm/client_resolver.py +155 -0
- aiecs/llm/clients/__init__.py +38 -0
- aiecs/llm/clients/base_client.py +324 -0
- aiecs/llm/clients/google_function_calling_mixin.py +457 -0
- aiecs/llm/clients/googleai_client.py +241 -0
- aiecs/llm/clients/openai_client.py +158 -0
- aiecs/llm/clients/openai_compatible_mixin.py +367 -0
- aiecs/llm/clients/vertex_client.py +897 -0
- aiecs/llm/clients/xai_client.py +201 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +272 -0
- aiecs/llm/config/config_validator.py +206 -0
- aiecs/llm/config/model_config.py +143 -0
- aiecs/llm/protocols.py +149 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +89 -0
- aiecs/main.py +140 -121
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +138 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/module_checker.py +499 -0
- aiecs/scripts/aid/version_manager.py +235 -0
- aiecs/scripts/{DEPENDENCY_SYSTEM_SUMMARY.md → dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md} +1 -0
- aiecs/scripts/{README_DEPENDENCY_CHECKER.md → dependance_check/README_DEPENDENCY_CHECKER.md} +1 -0
- aiecs/scripts/dependance_check/__init__.py +15 -0
- aiecs/scripts/dependance_check/dependency_checker.py +1835 -0
- aiecs/scripts/{dependency_fixer.py → dependance_check/dependency_fixer.py} +192 -90
- aiecs/scripts/{download_nlp_data.py → dependance_check/download_nlp_data.py} +203 -71
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/{fix_weasel_validator.py → dependance_patch/fix_weasel/fix_weasel_validator.py} +21 -14
- aiecs/scripts/{patch_weasel_library.sh → dependance_patch/fix_weasel/patch_weasel_library.sh} +1 -1
- aiecs/scripts/knowledge_graph/__init__.py +3 -0
- aiecs/scripts/knowledge_graph/run_threshold_experiments.py +212 -0
- aiecs/scripts/migrations/multi_tenancy/README.md +142 -0
- aiecs/scripts/tools_develop/README.md +671 -0
- aiecs/scripts/tools_develop/README_CONFIG_CHECKER.md +273 -0
- aiecs/scripts/tools_develop/TOOLS_CONFIG_GUIDE.md +1287 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_all_tools_config.py +548 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +257 -0
- aiecs/scripts/tools_develop/pre-commit-schema-coverage.sh +66 -0
- aiecs/scripts/tools_develop/schema_coverage.py +511 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +475 -0
- aiecs/scripts/tools_develop/verify_executor_config_fix.py +98 -0
- aiecs/scripts/tools_develop/verify_tools.py +352 -0
- aiecs/tasks/__init__.py +0 -1
- aiecs/tasks/worker.py +115 -47
- aiecs/tools/__init__.py +194 -72
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +632 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +417 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +385 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +330 -0
- aiecs/tools/apisource/providers/__init__.py +112 -0
- aiecs/tools/apisource/providers/base.py +671 -0
- aiecs/tools/apisource/providers/census.py +397 -0
- aiecs/tools/apisource/providers/fred.py +535 -0
- aiecs/tools/apisource/providers/newsapi.py +409 -0
- aiecs/tools/apisource/providers/worldbank.py +352 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +363 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +376 -0
- aiecs/tools/apisource/tool.py +832 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +334 -0
- aiecs/tools/base_tool.py +415 -21
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +607 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2350 -0
- aiecs/tools/docs/content_insertion_tool.py +1320 -0
- aiecs/tools/docs/document_creator_tool.py +1323 -0
- aiecs/tools/docs/document_layout_tool.py +1160 -0
- aiecs/tools/docs/document_parser_tool.py +1011 -0
- aiecs/tools/docs/document_writer_tool.py +1829 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +807 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +944 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +524 -0
- aiecs/tools/langchain_adapter.py +300 -138
- aiecs/tools/schema_generator.py +455 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +581 -0
- aiecs/tools/search_tool/cache.py +264 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +224 -0
- aiecs/tools/search_tool/core.py +778 -0
- aiecs/tools/search_tool/deduplicator.py +119 -0
- aiecs/tools/search_tool/error_handler.py +242 -0
- aiecs/tools/search_tool/metrics.py +343 -0
- aiecs/tools/search_tool/rate_limiter.py +172 -0
- aiecs/tools/search_tool/schemas.py +275 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +646 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +508 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +684 -0
- aiecs/tools/statistics/data_loader_tool.py +555 -0
- aiecs/tools/statistics/data_profiler_tool.py +638 -0
- aiecs/tools/statistics/data_transformer_tool.py +580 -0
- aiecs/tools/statistics/data_visualizer_tool.py +498 -0
- aiecs/tools/statistics/model_trainer_tool.py +507 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +472 -0
- aiecs/tools/task_tools/__init__.py +49 -36
- aiecs/tools/task_tools/chart_tool.py +200 -184
- aiecs/tools/task_tools/classfire_tool.py +268 -267
- aiecs/tools/task_tools/image_tool.py +175 -131
- aiecs/tools/task_tools/office_tool.py +226 -146
- aiecs/tools/task_tools/pandas_tool.py +477 -121
- aiecs/tools/task_tools/report_tool.py +390 -142
- aiecs/tools/task_tools/research_tool.py +149 -79
- aiecs/tools/task_tools/scraper_tool.py +339 -145
- aiecs/tools/task_tools/stats_tool.py +448 -209
- aiecs/tools/temp_file_manager.py +26 -24
- aiecs/tools/tool_executor/__init__.py +18 -16
- aiecs/tools/tool_executor/tool_executor.py +364 -52
- aiecs/utils/LLM_output_structor.py +74 -48
- aiecs/utils/__init__.py +14 -3
- aiecs/utils/base_callback.py +0 -3
- aiecs/utils/cache_provider.py +696 -0
- aiecs/utils/execution_utils.py +50 -31
- aiecs/utils/prompt_loader.py +1 -0
- aiecs/utils/token_usage_repository.py +37 -11
- aiecs/ws/socket_server.py +14 -4
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/METADATA +52 -15
- aiecs-1.7.6.dist-info/RECORD +337 -0
- aiecs-1.7.6.dist-info/entry_points.txt +13 -0
- aiecs/config/registry.py +0 -19
- aiecs/domain/context/content_engine.py +0 -982
- aiecs/llm/base_client.py +0 -99
- aiecs/llm/openai_client.py +0 -125
- aiecs/llm/vertex_client.py +0 -186
- aiecs/llm/xai_client.py +0 -184
- aiecs/scripts/dependency_checker.py +0 -857
- aiecs/scripts/quick_dependency_check.py +0 -269
- aiecs/tools/task_tools/search_api.py +0 -7
- aiecs-1.0.1.dist-info/RECORD +0 -90
- aiecs-1.0.1.dist-info/entry_points.txt +0 -7
- /aiecs/scripts/{setup_nlp_data.sh → dependance_check/setup_nlp_data.sh} +0 -0
- /aiecs/scripts/{README_WEASEL_PATCH.md → dependance_patch/fix_weasel/README_WEASEL_PATCH.md} +0 -0
- /aiecs/scripts/{fix_weasel_validator.sh → dependance_patch/fix_weasel/fix_weasel_validator.sh} +0 -0
- /aiecs/scripts/{run_weasel_patch.sh → dependance_patch/fix_weasel/run_weasel_patch.sh} +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/WHEEL +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/licenses/LICENSE +0 -0
- {aiecs-1.0.1.dist-info → aiecs-1.7.6.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cache Coordinator for Knowledge Graph Entity Fusion.
|
|
3
|
+
|
|
4
|
+
Coordinates cache invalidation between alias index and embedding cache
|
|
5
|
+
to prevent stale data after entity operations.
|
|
6
|
+
|
|
7
|
+
Invariant: No alias index update should complete without corresponding
|
|
8
|
+
embedding cache invalidation.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import asyncio
|
|
12
|
+
import logging
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
from typing import List, Optional, Set, TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
from aiecs.domain.knowledge_graph.models.entity import Entity
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from .alias_index import AliasIndex
|
|
20
|
+
from .semantic_name_matcher import SemanticNameMatcher, LRUEmbeddingCache
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class InvalidationResult:
|
|
27
|
+
"""Result of cache invalidation operation."""
|
|
28
|
+
affected_names: Set[str]
|
|
29
|
+
alias_entries_removed: int
|
|
30
|
+
embeddings_invalidated: int
|
|
31
|
+
success: bool
|
|
32
|
+
error: Optional[str] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class CacheCoordinator:
|
|
36
|
+
"""
|
|
37
|
+
Coordinates cache invalidation between alias index and embedding cache.
|
|
38
|
+
|
|
39
|
+
Ensures that when the alias index is updated, the embedding cache is
|
|
40
|
+
also invalidated to prevent stale embeddings from being used.
|
|
41
|
+
|
|
42
|
+
Key invariant: No alias index update completes without corresponding
|
|
43
|
+
embedding cache invalidation.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
```python
|
|
47
|
+
coordinator = CacheCoordinator(alias_index, semantic_matcher)
|
|
48
|
+
|
|
49
|
+
# On entity merge
|
|
50
|
+
await coordinator.on_entity_merge(old_entities, new_entity)
|
|
51
|
+
|
|
52
|
+
# On entity delete
|
|
53
|
+
await coordinator.on_entity_delete(entity)
|
|
54
|
+
|
|
55
|
+
# On alias update
|
|
56
|
+
await coordinator.on_alias_update(entity_id, old_aliases, new_aliases)
|
|
57
|
+
```
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
alias_index: Optional["AliasIndex"] = None,
|
|
63
|
+
semantic_matcher: Optional["SemanticNameMatcher"] = None,
|
|
64
|
+
embedding_cache: Optional["LRUEmbeddingCache"] = None,
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
Initialize cache coordinator.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
alias_index: Alias index to coordinate (optional)
|
|
71
|
+
semantic_matcher: Semantic matcher with embedding cache (optional)
|
|
72
|
+
embedding_cache: Direct embedding cache reference (optional,
|
|
73
|
+
uses semantic_matcher.cache if not provided)
|
|
74
|
+
"""
|
|
75
|
+
self._alias_index = alias_index
|
|
76
|
+
self._semantic_matcher = semantic_matcher
|
|
77
|
+
self._embedding_cache = embedding_cache
|
|
78
|
+
self._lock = asyncio.Lock()
|
|
79
|
+
|
|
80
|
+
# Statistics
|
|
81
|
+
self._invalidation_count = 0
|
|
82
|
+
self._names_invalidated = 0
|
|
83
|
+
|
|
84
|
+
def set_alias_index(self, alias_index: "AliasIndex") -> None:
|
|
85
|
+
"""Set the alias index reference."""
|
|
86
|
+
self._alias_index = alias_index
|
|
87
|
+
|
|
88
|
+
def set_semantic_matcher(self, semantic_matcher: "SemanticNameMatcher") -> None:
|
|
89
|
+
"""Set the semantic matcher reference."""
|
|
90
|
+
self._semantic_matcher = semantic_matcher
|
|
91
|
+
|
|
92
|
+
def set_embedding_cache(self, cache: "LRUEmbeddingCache") -> None:
|
|
93
|
+
"""Set the embedding cache reference directly."""
|
|
94
|
+
self._embedding_cache = cache
|
|
95
|
+
|
|
96
|
+
def _get_embedding_cache(self) -> Optional["LRUEmbeddingCache"]:
|
|
97
|
+
"""Get the embedding cache from matcher or direct reference."""
|
|
98
|
+
if self._embedding_cache is not None:
|
|
99
|
+
return self._embedding_cache
|
|
100
|
+
if self._semantic_matcher is not None:
|
|
101
|
+
return self._semantic_matcher.cache
|
|
102
|
+
return None
|
|
103
|
+
|
|
104
|
+
def _get_entity_name(self, entity: Entity) -> str:
|
|
105
|
+
"""Get the primary name of an entity."""
|
|
106
|
+
# Entity stores name in properties, not as a direct attribute
|
|
107
|
+
return entity.properties.get("name", "")
|
|
108
|
+
|
|
109
|
+
def _get_entity_aliases(self, entity: Entity) -> Set[str]:
|
|
110
|
+
"""Get all aliases for an entity."""
|
|
111
|
+
aliases: Set[str] = set()
|
|
112
|
+
|
|
113
|
+
# Add primary name
|
|
114
|
+
name = self._get_entity_name(entity)
|
|
115
|
+
if name:
|
|
116
|
+
aliases.add(name)
|
|
117
|
+
|
|
118
|
+
# Add known aliases
|
|
119
|
+
known_aliases = entity.properties.get("_known_aliases", [])
|
|
120
|
+
if isinstance(known_aliases, list):
|
|
121
|
+
aliases.update(known_aliases)
|
|
122
|
+
|
|
123
|
+
# Add historical aliases (from previous merges)
|
|
124
|
+
historical = entity.properties.get("_aliases", [])
|
|
125
|
+
if isinstance(historical, list):
|
|
126
|
+
aliases.update(historical)
|
|
127
|
+
|
|
128
|
+
return aliases
|
|
129
|
+
|
|
130
|
+
async def on_entity_merge(
|
|
131
|
+
self,
|
|
132
|
+
old_entities: List[Entity],
|
|
133
|
+
new_entity: Entity,
|
|
134
|
+
) -> InvalidationResult:
|
|
135
|
+
"""
|
|
136
|
+
Handle cache invalidation on entity merge.
|
|
137
|
+
|
|
138
|
+
Collects all names from old entities and invalidates both
|
|
139
|
+
alias index entries and embedding cache entries.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
old_entities: Entities being merged (will be deleted)
|
|
143
|
+
new_entity: Resulting merged entity
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
InvalidationResult with details
|
|
147
|
+
"""
|
|
148
|
+
async with self._lock:
|
|
149
|
+
affected_names: Set[str] = set()
|
|
150
|
+
|
|
151
|
+
# Collect all names from old entities
|
|
152
|
+
for entity in old_entities:
|
|
153
|
+
affected_names.add(self._get_entity_name(entity))
|
|
154
|
+
affected_names.update(self._get_entity_aliases(entity))
|
|
155
|
+
|
|
156
|
+
# Also include new entity names (in case they changed)
|
|
157
|
+
affected_names.add(self._get_entity_name(new_entity))
|
|
158
|
+
affected_names.update(self._get_entity_aliases(new_entity))
|
|
159
|
+
|
|
160
|
+
# Remove empty strings
|
|
161
|
+
affected_names.discard("")
|
|
162
|
+
|
|
163
|
+
return await self._invalidate_names(affected_names)
|
|
164
|
+
|
|
165
|
+
async def on_entity_delete(self, entity: Entity) -> InvalidationResult:
|
|
166
|
+
"""
|
|
167
|
+
Handle cache invalidation on entity delete.
|
|
168
|
+
|
|
169
|
+
Invalidates all names associated with the deleted entity.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
entity: Entity being deleted
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
InvalidationResult with details
|
|
176
|
+
"""
|
|
177
|
+
async with self._lock:
|
|
178
|
+
affected_names: Set[str] = set()
|
|
179
|
+
|
|
180
|
+
# Collect all names from entity
|
|
181
|
+
affected_names.add(self._get_entity_name(entity))
|
|
182
|
+
affected_names.update(self._get_entity_aliases(entity))
|
|
183
|
+
|
|
184
|
+
# Remove empty strings
|
|
185
|
+
affected_names.discard("")
|
|
186
|
+
|
|
187
|
+
return await self._invalidate_names(affected_names)
|
|
188
|
+
|
|
189
|
+
async def on_alias_update(
|
|
190
|
+
self,
|
|
191
|
+
entity_id: str,
|
|
192
|
+
old_aliases: List[str],
|
|
193
|
+
new_aliases: List[str],
|
|
194
|
+
) -> InvalidationResult:
|
|
195
|
+
"""
|
|
196
|
+
Handle cache invalidation on alias update.
|
|
197
|
+
|
|
198
|
+
Invalidates embeddings for both old and new aliases.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
entity_id: Entity whose aliases changed
|
|
202
|
+
old_aliases: Previous aliases
|
|
203
|
+
new_aliases: New aliases
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
InvalidationResult with details
|
|
207
|
+
"""
|
|
208
|
+
async with self._lock:
|
|
209
|
+
affected_names: Set[str] = set(old_aliases) | set(new_aliases)
|
|
210
|
+
affected_names.discard("")
|
|
211
|
+
|
|
212
|
+
return await self._invalidate_names(affected_names)
|
|
213
|
+
|
|
214
|
+
async def invalidate_for_names(
|
|
215
|
+
self, names: List[str]
|
|
216
|
+
) -> InvalidationResult:
|
|
217
|
+
"""
|
|
218
|
+
Directly invalidate cache entries for given names.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
names: Names to invalidate
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
InvalidationResult with details
|
|
225
|
+
"""
|
|
226
|
+
async with self._lock:
|
|
227
|
+
affected_names = set(names)
|
|
228
|
+
affected_names.discard("")
|
|
229
|
+
return await self._invalidate_names(affected_names)
|
|
230
|
+
|
|
231
|
+
async def _invalidate_names(
|
|
232
|
+
self, names: Set[str]
|
|
233
|
+
) -> InvalidationResult:
|
|
234
|
+
"""
|
|
235
|
+
Internal method to invalidate cache entries for names.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
names: Set of names to invalidate
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
InvalidationResult with details
|
|
242
|
+
"""
|
|
243
|
+
if not names:
|
|
244
|
+
return InvalidationResult(
|
|
245
|
+
affected_names=set(),
|
|
246
|
+
alias_entries_removed=0,
|
|
247
|
+
embeddings_invalidated=0,
|
|
248
|
+
success=True,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
alias_removed = 0
|
|
252
|
+
embeddings_invalidated = 0
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
# Invalidate alias index entries
|
|
256
|
+
# Each remove_alias() call removes exactly one alias entry (if it exists)
|
|
257
|
+
# and returns True on success, so we count each successful removal
|
|
258
|
+
if self._alias_index is not None:
|
|
259
|
+
for name in names:
|
|
260
|
+
removed = await self._alias_index.remove_alias(name)
|
|
261
|
+
if removed:
|
|
262
|
+
alias_removed += 1
|
|
263
|
+
|
|
264
|
+
# Invalidate embedding cache
|
|
265
|
+
cache = self._get_embedding_cache()
|
|
266
|
+
if cache is not None:
|
|
267
|
+
embeddings_invalidated = cache.invalidate_many(list(names))
|
|
268
|
+
|
|
269
|
+
# Update statistics
|
|
270
|
+
self._invalidation_count += 1
|
|
271
|
+
self._names_invalidated += len(names)
|
|
272
|
+
|
|
273
|
+
logger.debug(
|
|
274
|
+
f"Cache invalidation: {len(names)} names, "
|
|
275
|
+
f"{alias_removed} alias entries removed, "
|
|
276
|
+
f"{embeddings_invalidated} embeddings invalidated"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
return InvalidationResult(
|
|
280
|
+
affected_names=names,
|
|
281
|
+
alias_entries_removed=alias_removed,
|
|
282
|
+
embeddings_invalidated=embeddings_invalidated,
|
|
283
|
+
success=True,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logger.error(f"Cache invalidation failed: {e}")
|
|
288
|
+
return InvalidationResult(
|
|
289
|
+
affected_names=names,
|
|
290
|
+
alias_entries_removed=0,
|
|
291
|
+
embeddings_invalidated=0,
|
|
292
|
+
success=False,
|
|
293
|
+
error=str(e),
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
def verify_invariant(self, operation: str, affected_names: Set[str]) -> bool:
|
|
297
|
+
"""
|
|
298
|
+
Verify the cache coordination invariant.
|
|
299
|
+
|
|
300
|
+
Checks that all affected names have been properly invalidated
|
|
301
|
+
from the embedding cache.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
operation: Name of the operation for logging
|
|
305
|
+
affected_names: Names that should have been invalidated
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
True if invariant holds, False otherwise
|
|
309
|
+
"""
|
|
310
|
+
cache = self._get_embedding_cache()
|
|
311
|
+
if cache is None:
|
|
312
|
+
# No cache to check
|
|
313
|
+
return True
|
|
314
|
+
|
|
315
|
+
# Check if any affected names are still in cache
|
|
316
|
+
still_cached = []
|
|
317
|
+
for name in affected_names:
|
|
318
|
+
if cache.contains(name):
|
|
319
|
+
still_cached.append(name)
|
|
320
|
+
|
|
321
|
+
if still_cached:
|
|
322
|
+
logger.error(
|
|
323
|
+
f"INVARIANT VIOLATION in {operation}: "
|
|
324
|
+
f"{len(still_cached)} names still in embedding cache: {still_cached[:5]}"
|
|
325
|
+
)
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
return True
|
|
329
|
+
|
|
330
|
+
def get_stats(self) -> dict:
|
|
331
|
+
"""Get coordination statistics."""
|
|
332
|
+
return {
|
|
333
|
+
"invalidation_count": self._invalidation_count,
|
|
334
|
+
"names_invalidated": self._names_invalidated,
|
|
335
|
+
"has_alias_index": self._alias_index is not None,
|
|
336
|
+
"has_semantic_matcher": self._semantic_matcher is not None,
|
|
337
|
+
"has_embedding_cache": self._get_embedding_cache() is not None,
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
def reset_stats(self) -> None:
|
|
341
|
+
"""Reset coordination statistics."""
|
|
342
|
+
self._invalidation_count = 0
|
|
343
|
+
self._names_invalidated = 0
|