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,330 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Detailed Metrics and Health Monitoring for API Providers
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive performance tracking including:
|
|
5
|
+
- Response time percentiles
|
|
6
|
+
- Data volume statistics
|
|
7
|
+
- Error type distribution
|
|
8
|
+
- Rate limiting events
|
|
9
|
+
- Cache hit rates
|
|
10
|
+
- Overall health scoring
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from collections import defaultdict
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from threading import Lock
|
|
17
|
+
from typing import Any, Dict, List, Optional, cast
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
# Type definitions for metrics structure
|
|
22
|
+
MetricsDict = Dict[str, Any]
|
|
23
|
+
RequestsMetrics = Dict[str, int]
|
|
24
|
+
PerformanceMetrics = Dict[str, Any]
|
|
25
|
+
DataVolumeMetrics = Dict[str, Any]
|
|
26
|
+
ErrorsMetrics = Dict[str, Any]
|
|
27
|
+
RateLimitingMetrics = Dict[str, Any]
|
|
28
|
+
TimestampsMetrics = Dict[str, Optional[str]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DetailedMetrics:
|
|
32
|
+
"""
|
|
33
|
+
Tracks detailed performance metrics for API providers.
|
|
34
|
+
|
|
35
|
+
Provides comprehensive monitoring including response times, data volumes,
|
|
36
|
+
error patterns, and overall health scoring.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, max_response_times: int = 100):
|
|
40
|
+
"""
|
|
41
|
+
Initialize metrics tracker.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
max_response_times: Maximum number of response times to keep in memory
|
|
45
|
+
"""
|
|
46
|
+
self.max_response_times = max_response_times
|
|
47
|
+
self.lock = Lock()
|
|
48
|
+
|
|
49
|
+
# Request metrics with proper type annotations
|
|
50
|
+
self.metrics: Dict[str, MetricsDict] = {
|
|
51
|
+
"requests": {
|
|
52
|
+
"total": 0,
|
|
53
|
+
"successful": 0,
|
|
54
|
+
"failed": 0,
|
|
55
|
+
"cached": 0,
|
|
56
|
+
},
|
|
57
|
+
"performance": {
|
|
58
|
+
"response_times": [], # Last N response times
|
|
59
|
+
"avg_response_time_ms": 0.0,
|
|
60
|
+
"p50_response_time_ms": 0.0,
|
|
61
|
+
"p95_response_time_ms": 0.0,
|
|
62
|
+
"p99_response_time_ms": 0.0,
|
|
63
|
+
"min_response_time_ms": 0.0,
|
|
64
|
+
"max_response_time_ms": 0.0,
|
|
65
|
+
},
|
|
66
|
+
"data_volume": {
|
|
67
|
+
"total_records_fetched": 0,
|
|
68
|
+
"total_bytes_transferred": 0,
|
|
69
|
+
"avg_records_per_request": 0.0,
|
|
70
|
+
"avg_bytes_per_request": 0.0,
|
|
71
|
+
},
|
|
72
|
+
"errors": {
|
|
73
|
+
"by_type": defaultdict(int), # {error_type: count}
|
|
74
|
+
"recent_errors": [], # Last 10 errors with details
|
|
75
|
+
},
|
|
76
|
+
"rate_limiting": {
|
|
77
|
+
"throttled_requests": 0,
|
|
78
|
+
"total_wait_time_ms": 0.0,
|
|
79
|
+
"avg_wait_time_ms": 0.0,
|
|
80
|
+
},
|
|
81
|
+
"timestamps": {
|
|
82
|
+
"first_request": None,
|
|
83
|
+
"last_request": None,
|
|
84
|
+
"last_success": None,
|
|
85
|
+
"last_failure": None,
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
def record_request(
|
|
90
|
+
self,
|
|
91
|
+
success: bool,
|
|
92
|
+
response_time_ms: float,
|
|
93
|
+
record_count: int = 0,
|
|
94
|
+
bytes_transferred: int = 0,
|
|
95
|
+
cached: bool = False,
|
|
96
|
+
error_type: Optional[str] = None,
|
|
97
|
+
error_message: Optional[str] = None,
|
|
98
|
+
):
|
|
99
|
+
"""
|
|
100
|
+
Record a request with its metrics.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
success: Whether the request was successful
|
|
104
|
+
response_time_ms: Response time in milliseconds
|
|
105
|
+
record_count: Number of records returned
|
|
106
|
+
bytes_transferred: Bytes transferred in the response
|
|
107
|
+
cached: Whether the response was cached
|
|
108
|
+
error_type: Type of error if failed (e.g., 'timeout', 'auth', 'rate_limit')
|
|
109
|
+
error_message: Error message if failed
|
|
110
|
+
"""
|
|
111
|
+
with self.lock:
|
|
112
|
+
now = datetime.utcnow().isoformat()
|
|
113
|
+
|
|
114
|
+
# Get typed references to nested dictionaries
|
|
115
|
+
requests = cast(RequestsMetrics, self.metrics["requests"])
|
|
116
|
+
timestamps = cast(TimestampsMetrics, self.metrics["timestamps"])
|
|
117
|
+
performance = cast(PerformanceMetrics, self.metrics["performance"])
|
|
118
|
+
data_volume = cast(DataVolumeMetrics, self.metrics["data_volume"])
|
|
119
|
+
errors = cast(ErrorsMetrics, self.metrics["errors"])
|
|
120
|
+
|
|
121
|
+
# Update request counts
|
|
122
|
+
requests["total"] += 1
|
|
123
|
+
if success:
|
|
124
|
+
requests["successful"] += 1
|
|
125
|
+
timestamps["last_success"] = now
|
|
126
|
+
else:
|
|
127
|
+
requests["failed"] += 1
|
|
128
|
+
timestamps["last_failure"] = now
|
|
129
|
+
|
|
130
|
+
if cached:
|
|
131
|
+
requests["cached"] += 1
|
|
132
|
+
|
|
133
|
+
# Update timestamps
|
|
134
|
+
if timestamps["first_request"] is None:
|
|
135
|
+
timestamps["first_request"] = now
|
|
136
|
+
timestamps["last_request"] = now
|
|
137
|
+
|
|
138
|
+
# Update performance metrics
|
|
139
|
+
response_times = cast(List[float], performance["response_times"])
|
|
140
|
+
response_times.append(response_time_ms)
|
|
141
|
+
if len(response_times) > self.max_response_times:
|
|
142
|
+
response_times.pop(0)
|
|
143
|
+
|
|
144
|
+
# Calculate percentiles
|
|
145
|
+
self._calculate_percentiles()
|
|
146
|
+
|
|
147
|
+
# Update data volume metrics
|
|
148
|
+
data_volume["total_records_fetched"] += record_count
|
|
149
|
+
data_volume["total_bytes_transferred"] += bytes_transferred
|
|
150
|
+
|
|
151
|
+
total_requests = requests["total"]
|
|
152
|
+
if total_requests > 0:
|
|
153
|
+
data_volume["avg_records_per_request"] = data_volume["total_records_fetched"] / total_requests
|
|
154
|
+
data_volume["avg_bytes_per_request"] = data_volume["total_bytes_transferred"] / total_requests
|
|
155
|
+
|
|
156
|
+
# Record errors
|
|
157
|
+
if not success and error_type:
|
|
158
|
+
by_type = cast(Dict[str, int], errors["by_type"])
|
|
159
|
+
by_type[error_type] += 1
|
|
160
|
+
|
|
161
|
+
error_entry = {
|
|
162
|
+
"type": error_type,
|
|
163
|
+
"message": error_message or "Unknown error",
|
|
164
|
+
"timestamp": now,
|
|
165
|
+
"response_time_ms": response_time_ms,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
recent_errors = cast(List[Dict[str, Any]], errors["recent_errors"])
|
|
169
|
+
recent_errors.append(error_entry)
|
|
170
|
+
if len(recent_errors) > 10:
|
|
171
|
+
recent_errors.pop(0)
|
|
172
|
+
|
|
173
|
+
def record_rate_limit_wait(self, wait_time_ms: float):
|
|
174
|
+
"""
|
|
175
|
+
Record a rate limit wait event.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
wait_time_ms: Time waited in milliseconds
|
|
179
|
+
"""
|
|
180
|
+
with self.lock:
|
|
181
|
+
rate_limiting = cast(RateLimitingMetrics, self.metrics["rate_limiting"])
|
|
182
|
+
rate_limiting["throttled_requests"] += 1
|
|
183
|
+
rate_limiting["total_wait_time_ms"] += wait_time_ms
|
|
184
|
+
|
|
185
|
+
throttled = rate_limiting["throttled_requests"]
|
|
186
|
+
if throttled > 0:
|
|
187
|
+
rate_limiting["avg_wait_time_ms"] = rate_limiting["total_wait_time_ms"] / throttled
|
|
188
|
+
|
|
189
|
+
def _calculate_percentiles(self):
|
|
190
|
+
"""Calculate response time percentiles"""
|
|
191
|
+
performance = cast(PerformanceMetrics, self.metrics["performance"])
|
|
192
|
+
response_times = cast(List[float], performance["response_times"])
|
|
193
|
+
times = sorted(response_times)
|
|
194
|
+
if not times:
|
|
195
|
+
return
|
|
196
|
+
|
|
197
|
+
n = len(times)
|
|
198
|
+
performance["avg_response_time_ms"] = sum(times) / n
|
|
199
|
+
performance["min_response_time_ms"] = times[0]
|
|
200
|
+
performance["max_response_time_ms"] = times[-1]
|
|
201
|
+
performance["p50_response_time_ms"] = times[n // 2]
|
|
202
|
+
performance["p95_response_time_ms"] = times[int(n * 0.95)]
|
|
203
|
+
performance["p99_response_time_ms"] = times[min(int(n * 0.99), n - 1)]
|
|
204
|
+
|
|
205
|
+
def _calculate_health_score_unlocked(self) -> float:
|
|
206
|
+
"""
|
|
207
|
+
Calculate health score without acquiring lock (internal use only).
|
|
208
|
+
Must be called while holding self.lock.
|
|
209
|
+
"""
|
|
210
|
+
requests = cast(RequestsMetrics, self.metrics["requests"])
|
|
211
|
+
performance = cast(PerformanceMetrics, self.metrics["performance"])
|
|
212
|
+
errors = cast(ErrorsMetrics, self.metrics["errors"])
|
|
213
|
+
|
|
214
|
+
total = requests["total"]
|
|
215
|
+
if total == 0:
|
|
216
|
+
return 1.0
|
|
217
|
+
|
|
218
|
+
# Success rate score (40%)
|
|
219
|
+
success_rate = requests["successful"] / total
|
|
220
|
+
success_score = success_rate * 0.4
|
|
221
|
+
|
|
222
|
+
# Performance score (30%)
|
|
223
|
+
avg_time = cast(float, performance["avg_response_time_ms"])
|
|
224
|
+
# Assume < 200ms is excellent, > 2000ms is poor
|
|
225
|
+
if avg_time < 200:
|
|
226
|
+
performance_score = 0.3
|
|
227
|
+
elif avg_time > 2000:
|
|
228
|
+
performance_score = 0.0
|
|
229
|
+
else:
|
|
230
|
+
performance_score = max(0, min(1, (2000 - avg_time) / 1800)) * 0.3
|
|
231
|
+
|
|
232
|
+
# Cache hit rate score (20%)
|
|
233
|
+
cache_rate = requests["cached"] / total
|
|
234
|
+
cache_score = cache_rate * 0.2
|
|
235
|
+
|
|
236
|
+
# Error diversity score (10%) - fewer error types is better
|
|
237
|
+
by_type = cast(Dict[str, int], errors["by_type"])
|
|
238
|
+
error_types = len(by_type)
|
|
239
|
+
error_score = max(0, (5 - error_types) / 5) * 0.1
|
|
240
|
+
|
|
241
|
+
return success_score + performance_score + cache_score + error_score
|
|
242
|
+
|
|
243
|
+
def get_health_score(self) -> float:
|
|
244
|
+
"""
|
|
245
|
+
Calculate overall health score (0-1).
|
|
246
|
+
|
|
247
|
+
The health score considers:
|
|
248
|
+
- Success rate (40%)
|
|
249
|
+
- Performance (30%)
|
|
250
|
+
- Cache hit rate (20%)
|
|
251
|
+
- Error diversity (10%)
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Health score between 0 and 1
|
|
255
|
+
"""
|
|
256
|
+
with self.lock:
|
|
257
|
+
return self._calculate_health_score_unlocked()
|
|
258
|
+
|
|
259
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
260
|
+
"""
|
|
261
|
+
Get all metrics as a dictionary.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Complete metrics dictionary
|
|
265
|
+
"""
|
|
266
|
+
with self.lock:
|
|
267
|
+
# Convert defaultdict to regular dict for JSON serialization
|
|
268
|
+
requests_dict: Dict[str, int] = dict(self.metrics["requests"]) # type: ignore[arg-type]
|
|
269
|
+
performance_dict: Dict[str, Any] = dict(self.metrics["performance"]) # type: ignore[arg-type]
|
|
270
|
+
data_volume_dict: Dict[str, Any] = dict(self.metrics["data_volume"]) # type: ignore[arg-type]
|
|
271
|
+
errors_by_type: Dict[str, int] = dict(self.metrics["errors"]["by_type"]) # type: ignore[arg-type]
|
|
272
|
+
recent_errors_list: List[Dict[str, Any]] = list(self.metrics["errors"]["recent_errors"]) # type: ignore[arg-type]
|
|
273
|
+
rate_limiting_dict: Dict[str, Any] = dict(self.metrics["rate_limiting"]) # type: ignore[arg-type]
|
|
274
|
+
timestamps_dict: Dict[str, Optional[str]] = dict(self.metrics["timestamps"]) # type: ignore[arg-type]
|
|
275
|
+
|
|
276
|
+
stats: Dict[str, Any] = {
|
|
277
|
+
"requests": requests_dict,
|
|
278
|
+
"performance": performance_dict,
|
|
279
|
+
"data_volume": data_volume_dict,
|
|
280
|
+
"errors": {
|
|
281
|
+
"by_type": errors_by_type,
|
|
282
|
+
"recent_errors": recent_errors_list,
|
|
283
|
+
},
|
|
284
|
+
"rate_limiting": rate_limiting_dict,
|
|
285
|
+
"timestamps": timestamps_dict,
|
|
286
|
+
"health_score": self.get_health_score(),
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
# Remove response_times array to keep output clean
|
|
290
|
+
stats["performance"] = {k: v for k, v in stats["performance"].items() if k != "response_times"}
|
|
291
|
+
|
|
292
|
+
return stats
|
|
293
|
+
|
|
294
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
295
|
+
"""
|
|
296
|
+
Get a concise summary of key metrics.
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Summary dictionary with key metrics
|
|
300
|
+
"""
|
|
301
|
+
with self.lock:
|
|
302
|
+
requests = cast(RequestsMetrics, self.metrics["requests"])
|
|
303
|
+
performance = cast(PerformanceMetrics, self.metrics["performance"])
|
|
304
|
+
errors = cast(ErrorsMetrics, self.metrics["errors"])
|
|
305
|
+
|
|
306
|
+
total = requests["total"]
|
|
307
|
+
if total == 0:
|
|
308
|
+
return {"status": "no_activity", "health_score": 1.0}
|
|
309
|
+
|
|
310
|
+
success_rate = requests["successful"] / total
|
|
311
|
+
cache_hit_rate = requests["cached"] / total
|
|
312
|
+
# Use unlocked version to avoid deadlock
|
|
313
|
+
health_score = self._calculate_health_score_unlocked()
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
"status": "healthy" if health_score > 0.7 else "degraded",
|
|
317
|
+
"health_score": round(health_score, 3),
|
|
318
|
+
"total_requests": total,
|
|
319
|
+
"success_rate": round(success_rate, 3),
|
|
320
|
+
"cache_hit_rate": round(cache_hit_rate, 3),
|
|
321
|
+
"avg_response_time_ms": round(cast(float, performance["avg_response_time_ms"]), 2),
|
|
322
|
+
"p95_response_time_ms": round(cast(float, performance["p95_response_time_ms"]), 2),
|
|
323
|
+
"total_errors": requests["failed"],
|
|
324
|
+
"error_types": len(cast(Dict[str, int], errors["by_type"])),
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
def reset(self):
|
|
328
|
+
"""Reset all metrics"""
|
|
329
|
+
with self.lock:
|
|
330
|
+
self.__init__(self.max_response_times)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API Providers Module
|
|
3
|
+
|
|
4
|
+
Contains all API provider implementations for the APISource tool.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from aiecs.tools.apisource.providers.base import BaseAPIProvider, RateLimiter
|
|
8
|
+
from aiecs.tools.apisource.providers.fred import FREDProvider
|
|
9
|
+
from aiecs.tools.apisource.providers.worldbank import WorldBankProvider
|
|
10
|
+
from aiecs.tools.apisource.providers.newsapi import NewsAPIProvider
|
|
11
|
+
from aiecs.tools.apisource.providers.census import CensusProvider
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from typing import Dict, List, Optional, Type, Any
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
# Global provider registry
|
|
19
|
+
PROVIDER_REGISTRY: Dict[str, Type[BaseAPIProvider]] = {}
|
|
20
|
+
PROVIDER_INSTANCES: Dict[str, BaseAPIProvider] = {}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def register_provider(provider_class: Type[BaseAPIProvider]):
|
|
24
|
+
"""
|
|
25
|
+
Register a provider class.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
provider_class: Provider class to register
|
|
29
|
+
"""
|
|
30
|
+
# Instantiate to get name
|
|
31
|
+
temp_instance = provider_class()
|
|
32
|
+
provider_name = temp_instance.name
|
|
33
|
+
|
|
34
|
+
PROVIDER_REGISTRY[provider_name] = provider_class
|
|
35
|
+
logger.debug(f"Registered provider: {provider_name}")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_provider(name: str, config: Optional[Dict] = None) -> BaseAPIProvider:
|
|
39
|
+
"""
|
|
40
|
+
Get a provider instance by name.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
name: Provider name
|
|
44
|
+
config: Optional configuration for the provider
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Provider instance
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
ValueError: If provider is not registered
|
|
51
|
+
"""
|
|
52
|
+
if name not in PROVIDER_REGISTRY:
|
|
53
|
+
raise ValueError(f"Provider '{name}' not found. " f"Available providers: {', '.join(PROVIDER_REGISTRY.keys())}")
|
|
54
|
+
|
|
55
|
+
# Return cached instance or create new one with config
|
|
56
|
+
if config is None and name in PROVIDER_INSTANCES:
|
|
57
|
+
return PROVIDER_INSTANCES[name]
|
|
58
|
+
|
|
59
|
+
provider_instance = PROVIDER_REGISTRY[name](config)
|
|
60
|
+
|
|
61
|
+
if config is None:
|
|
62
|
+
PROVIDER_INSTANCES[name] = provider_instance
|
|
63
|
+
|
|
64
|
+
return provider_instance
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def list_providers() -> List[Dict[str, Any]]:
|
|
68
|
+
"""
|
|
69
|
+
List all registered providers.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
List of provider metadata dictionaries
|
|
73
|
+
"""
|
|
74
|
+
providers = []
|
|
75
|
+
for name, provider_class in PROVIDER_REGISTRY.items():
|
|
76
|
+
try:
|
|
77
|
+
# Get or create instance to access metadata
|
|
78
|
+
provider = get_provider(name)
|
|
79
|
+
providers.append(provider.get_metadata())
|
|
80
|
+
except Exception as e:
|
|
81
|
+
logger.warning(f"Failed to get metadata for provider {name}: {e}")
|
|
82
|
+
providers.append(
|
|
83
|
+
{
|
|
84
|
+
"name": name,
|
|
85
|
+
"description": "Provider metadata unavailable",
|
|
86
|
+
"operations": [],
|
|
87
|
+
"error": str(e),
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return providers
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# Auto-register all providers
|
|
95
|
+
register_provider(FREDProvider)
|
|
96
|
+
register_provider(WorldBankProvider)
|
|
97
|
+
register_provider(NewsAPIProvider)
|
|
98
|
+
register_provider(CensusProvider)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
__all__ = [
|
|
102
|
+
"BaseAPIProvider",
|
|
103
|
+
"RateLimiter",
|
|
104
|
+
"FREDProvider",
|
|
105
|
+
"WorldBankProvider",
|
|
106
|
+
"NewsAPIProvider",
|
|
107
|
+
"CensusProvider",
|
|
108
|
+
"register_provider",
|
|
109
|
+
"get_provider",
|
|
110
|
+
"list_providers",
|
|
111
|
+
"PROVIDER_REGISTRY",
|
|
112
|
+
]
|