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,449 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Persistence
|
|
3
|
+
|
|
4
|
+
Interfaces and implementations for saving/loading agent state.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import json
|
|
9
|
+
from typing import Dict, Any, Optional, Protocol
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from collections import ChainMap
|
|
12
|
+
import asyncio
|
|
13
|
+
import queue
|
|
14
|
+
import dataclasses
|
|
15
|
+
|
|
16
|
+
from .base_agent import BaseAIAgent
|
|
17
|
+
from .exceptions import SerializationError
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AgentPersistence(Protocol):
|
|
23
|
+
"""Protocol for agent persistence implementations."""
|
|
24
|
+
|
|
25
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
26
|
+
"""
|
|
27
|
+
Save agent state.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
agent: Agent to save
|
|
31
|
+
"""
|
|
32
|
+
...
|
|
33
|
+
|
|
34
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
35
|
+
"""
|
|
36
|
+
Load agent state.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
agent_id: Agent identifier
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Agent state dictionary
|
|
43
|
+
"""
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
async def exists(self, agent_id: str) -> bool:
|
|
47
|
+
"""
|
|
48
|
+
Check if agent state exists.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
agent_id: Agent identifier
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
True if exists
|
|
55
|
+
"""
|
|
56
|
+
...
|
|
57
|
+
|
|
58
|
+
async def delete(self, agent_id: str) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Delete agent state.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
agent_id: Agent identifier
|
|
64
|
+
"""
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class InMemoryPersistence:
|
|
69
|
+
"""In-memory agent persistence (for testing/development)."""
|
|
70
|
+
|
|
71
|
+
def __init__(self) -> None:
|
|
72
|
+
"""Initialize in-memory storage."""
|
|
73
|
+
self._storage: Dict[str, Dict[str, Any]] = {}
|
|
74
|
+
logger.info("InMemoryPersistence initialized")
|
|
75
|
+
|
|
76
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
77
|
+
"""Save agent state to memory."""
|
|
78
|
+
try:
|
|
79
|
+
state = agent.to_dict()
|
|
80
|
+
# Convert any remaining datetime objects to ISO strings
|
|
81
|
+
state = self._serialize_datetimes(state)
|
|
82
|
+
self._storage[agent.agent_id] = {
|
|
83
|
+
"state": state,
|
|
84
|
+
"saved_at": datetime.utcnow().isoformat(),
|
|
85
|
+
}
|
|
86
|
+
logger.debug(f"Agent {agent.agent_id} saved to memory")
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logger.error(f"Failed to save agent {agent.agent_id}: {e}")
|
|
89
|
+
raise SerializationError(f"Failed to save agent: {str(e)}")
|
|
90
|
+
|
|
91
|
+
def _serialize_datetimes(self, obj: Any) -> Any:
|
|
92
|
+
"""Recursively serialize datetime objects to ISO strings."""
|
|
93
|
+
if isinstance(obj, dict):
|
|
94
|
+
return {k: self._serialize_datetimes(v) for k, v in obj.items()}
|
|
95
|
+
elif isinstance(obj, list):
|
|
96
|
+
return [self._serialize_datetimes(item) for item in obj]
|
|
97
|
+
elif isinstance(obj, datetime):
|
|
98
|
+
return obj.isoformat()
|
|
99
|
+
else:
|
|
100
|
+
return obj
|
|
101
|
+
|
|
102
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
103
|
+
"""Load agent state from memory."""
|
|
104
|
+
if agent_id not in self._storage:
|
|
105
|
+
raise KeyError(f"Agent {agent_id} not found in storage")
|
|
106
|
+
|
|
107
|
+
data = self._storage[agent_id]
|
|
108
|
+
logger.debug(f"Agent {agent_id} loaded from memory")
|
|
109
|
+
return data["state"]
|
|
110
|
+
|
|
111
|
+
async def exists(self, agent_id: str) -> bool:
|
|
112
|
+
"""Check if agent exists in memory."""
|
|
113
|
+
return agent_id in self._storage
|
|
114
|
+
|
|
115
|
+
async def delete(self, agent_id: str) -> None:
|
|
116
|
+
"""Delete agent from memory."""
|
|
117
|
+
if agent_id in self._storage:
|
|
118
|
+
del self._storage[agent_id]
|
|
119
|
+
logger.debug(f"Agent {agent_id} deleted from memory")
|
|
120
|
+
|
|
121
|
+
def clear(self) -> None:
|
|
122
|
+
"""Clear all stored agents."""
|
|
123
|
+
self._storage.clear()
|
|
124
|
+
logger.info("InMemoryPersistence cleared")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class FilePersistence:
|
|
128
|
+
"""File-based agent persistence."""
|
|
129
|
+
|
|
130
|
+
def __init__(self, base_path: str = "./agent_states"):
|
|
131
|
+
"""
|
|
132
|
+
Initialize file-based storage.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
base_path: Base directory for agent states
|
|
136
|
+
"""
|
|
137
|
+
import os
|
|
138
|
+
|
|
139
|
+
self.base_path = base_path
|
|
140
|
+
os.makedirs(base_path, exist_ok=True)
|
|
141
|
+
logger.info(f"FilePersistence initialized with base_path: {base_path}")
|
|
142
|
+
|
|
143
|
+
def _get_file_path(self, agent_id: str) -> str:
|
|
144
|
+
"""Get file path for agent."""
|
|
145
|
+
import os
|
|
146
|
+
|
|
147
|
+
# Sanitize agent_id for filesystem
|
|
148
|
+
safe_id = agent_id.replace("/", "_").replace("\\", "_")
|
|
149
|
+
return os.path.join(self.base_path, f"{safe_id}.json")
|
|
150
|
+
|
|
151
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
152
|
+
"""Save agent state to file."""
|
|
153
|
+
try:
|
|
154
|
+
state = agent.to_dict()
|
|
155
|
+
# Convert any remaining datetime objects to ISO strings for JSON
|
|
156
|
+
# serialization
|
|
157
|
+
state = self._serialize_datetimes(state)
|
|
158
|
+
file_path = self._get_file_path(agent.agent_id)
|
|
159
|
+
|
|
160
|
+
data = {
|
|
161
|
+
"state": state,
|
|
162
|
+
"saved_at": datetime.utcnow().isoformat(),
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
with open(file_path, "w") as f:
|
|
166
|
+
# default=str handles any remaining non-serializable objects
|
|
167
|
+
json.dump(data, f, indent=2, default=str)
|
|
168
|
+
|
|
169
|
+
logger.debug(f"Agent {agent.agent_id} saved to {file_path}")
|
|
170
|
+
except Exception as e:
|
|
171
|
+
logger.error(f"Failed to save agent {agent.agent_id}: {e}")
|
|
172
|
+
raise SerializationError(f"Failed to save agent: {str(e)}")
|
|
173
|
+
|
|
174
|
+
def _serialize_datetimes(self, obj: Any) -> Any:
|
|
175
|
+
"""Recursively serialize datetime objects to ISO strings."""
|
|
176
|
+
if isinstance(obj, dict):
|
|
177
|
+
return {k: self._serialize_datetimes(v) for k, v in obj.items()}
|
|
178
|
+
elif isinstance(obj, list):
|
|
179
|
+
return [self._serialize_datetimes(item) for item in obj]
|
|
180
|
+
elif isinstance(obj, datetime):
|
|
181
|
+
return obj.isoformat()
|
|
182
|
+
else:
|
|
183
|
+
return obj
|
|
184
|
+
|
|
185
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
186
|
+
"""Load agent state from file."""
|
|
187
|
+
file_path = self._get_file_path(agent_id)
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
with open(file_path, "r") as f:
|
|
191
|
+
data = json.load(f)
|
|
192
|
+
|
|
193
|
+
logger.debug(f"Agent {agent_id} loaded from {file_path}")
|
|
194
|
+
return data["state"]
|
|
195
|
+
except FileNotFoundError:
|
|
196
|
+
raise KeyError(f"Agent {agent_id} not found in storage")
|
|
197
|
+
except Exception as e:
|
|
198
|
+
logger.error(f"Failed to load agent {agent_id}: {e}")
|
|
199
|
+
raise SerializationError(f"Failed to load agent: {str(e)}")
|
|
200
|
+
|
|
201
|
+
async def exists(self, agent_id: str) -> bool:
|
|
202
|
+
"""Check if agent file exists."""
|
|
203
|
+
import os
|
|
204
|
+
|
|
205
|
+
file_path = self._get_file_path(agent_id)
|
|
206
|
+
return os.path.exists(file_path)
|
|
207
|
+
|
|
208
|
+
async def delete(self, agent_id: str) -> None:
|
|
209
|
+
"""Delete agent file."""
|
|
210
|
+
import os
|
|
211
|
+
|
|
212
|
+
file_path = self._get_file_path(agent_id)
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
if os.path.exists(file_path):
|
|
216
|
+
os.remove(file_path)
|
|
217
|
+
logger.debug(f"Agent {agent_id} deleted from {file_path}")
|
|
218
|
+
except Exception as e:
|
|
219
|
+
logger.error(f"Failed to delete agent {agent_id}: {e}")
|
|
220
|
+
raise
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class AgentStateSerializer:
|
|
224
|
+
"""
|
|
225
|
+
Helper class for serializing/deserializing agent state.
|
|
226
|
+
|
|
227
|
+
Handles complex types that need special serialization, including:
|
|
228
|
+
- datetime objects
|
|
229
|
+
- asyncio.Queue and queue.Queue
|
|
230
|
+
- ChainMap
|
|
231
|
+
- dataclasses
|
|
232
|
+
- Other non-JSON-serializable types
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def serialize(agent: BaseAIAgent) -> Dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
Serialize agent to dictionary with sanitization.
|
|
239
|
+
|
|
240
|
+
This method gets the agent state and sanitizes it to ensure
|
|
241
|
+
all values are JSON-serializable.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
agent: Agent to serialize
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
Serialized state dictionary (JSON-safe)
|
|
248
|
+
"""
|
|
249
|
+
state = agent.to_dict()
|
|
250
|
+
return AgentStateSerializer._sanitize_checkpoint(state)
|
|
251
|
+
|
|
252
|
+
@staticmethod
|
|
253
|
+
def deserialize(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
254
|
+
"""
|
|
255
|
+
Deserialize agent state.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
data: Serialized state
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Deserialized state dictionary
|
|
262
|
+
|
|
263
|
+
Note: This returns a state dictionary, not an agent instance.
|
|
264
|
+
Agent reconstruction requires the appropriate agent class.
|
|
265
|
+
"""
|
|
266
|
+
# In the future, this could handle type conversion, validation, etc.
|
|
267
|
+
return data
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def _sanitize_checkpoint(checkpoint_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
271
|
+
"""
|
|
272
|
+
Sanitize checkpoint data to ensure JSON serializability.
|
|
273
|
+
|
|
274
|
+
This method recursively processes checkpoint data to convert
|
|
275
|
+
non-serializable types to serializable representations.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
checkpoint_data: Checkpoint data to sanitize
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Sanitized checkpoint data (JSON-safe)
|
|
282
|
+
|
|
283
|
+
Example:
|
|
284
|
+
data = {
|
|
285
|
+
"timestamp": datetime.utcnow(),
|
|
286
|
+
"queue": asyncio.Queue(),
|
|
287
|
+
"config": {"nested": datetime.utcnow()}
|
|
288
|
+
}
|
|
289
|
+
sanitized = AgentStateSerializer._sanitize_checkpoint(data)
|
|
290
|
+
# All datetime objects converted to ISO strings
|
|
291
|
+
# Queue converted to placeholder
|
|
292
|
+
"""
|
|
293
|
+
return AgentStateSerializer._sanitize_dict(checkpoint_data)
|
|
294
|
+
|
|
295
|
+
@staticmethod
|
|
296
|
+
def _sanitize_dict(obj: Dict[str, Any]) -> Dict[str, Any]:
|
|
297
|
+
"""
|
|
298
|
+
Sanitize dictionary recursively.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
obj: Dictionary to sanitize
|
|
302
|
+
|
|
303
|
+
Returns:
|
|
304
|
+
Sanitized dictionary
|
|
305
|
+
"""
|
|
306
|
+
result = {}
|
|
307
|
+
for key, value in obj.items():
|
|
308
|
+
try:
|
|
309
|
+
result[key] = AgentStateSerializer._make_json_serializable(value)
|
|
310
|
+
except Exception as e:
|
|
311
|
+
logger.warning(f"Failed to sanitize key '{key}': {e}. Using placeholder.")
|
|
312
|
+
result[key] = f"<non-serializable: {type(value).__name__}>"
|
|
313
|
+
return result
|
|
314
|
+
|
|
315
|
+
@staticmethod
|
|
316
|
+
def _sanitize_list(obj: list) -> list:
|
|
317
|
+
"""
|
|
318
|
+
Sanitize list recursively.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
obj: List to sanitize
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
Sanitized list
|
|
325
|
+
"""
|
|
326
|
+
result = []
|
|
327
|
+
for i, item in enumerate(obj):
|
|
328
|
+
try:
|
|
329
|
+
result.append(AgentStateSerializer._make_json_serializable(item))
|
|
330
|
+
except Exception as e:
|
|
331
|
+
logger.warning(f"Failed to sanitize list item at index {i}: {e}. Using placeholder.")
|
|
332
|
+
result.append(f"<non-serializable: {type(item).__name__}>")
|
|
333
|
+
return result
|
|
334
|
+
|
|
335
|
+
@staticmethod
|
|
336
|
+
def _make_json_serializable(obj: Any) -> Any:
|
|
337
|
+
"""
|
|
338
|
+
Convert object to JSON-serializable form.
|
|
339
|
+
|
|
340
|
+
Handles common non-serializable types:
|
|
341
|
+
- datetime -> ISO string
|
|
342
|
+
- asyncio.Queue -> placeholder
|
|
343
|
+
- queue.Queue -> placeholder
|
|
344
|
+
- ChainMap -> dict
|
|
345
|
+
- dataclasses -> dict
|
|
346
|
+
- dict -> recursive sanitization
|
|
347
|
+
- list -> recursive sanitization
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
obj: Object to convert
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
JSON-serializable representation
|
|
354
|
+
|
|
355
|
+
Raises:
|
|
356
|
+
TypeError: If object cannot be made serializable
|
|
357
|
+
"""
|
|
358
|
+
# Handle None, bool, int, float, str (already serializable)
|
|
359
|
+
if obj is None or isinstance(obj, (bool, int, float, str)):
|
|
360
|
+
return obj
|
|
361
|
+
|
|
362
|
+
# Handle datetime
|
|
363
|
+
if isinstance(obj, datetime):
|
|
364
|
+
return obj.isoformat()
|
|
365
|
+
|
|
366
|
+
# Handle asyncio.Queue
|
|
367
|
+
if isinstance(obj, asyncio.Queue):
|
|
368
|
+
logger.warning("asyncio.Queue detected in checkpoint data. " "Queues cannot be serialized. Using placeholder.")
|
|
369
|
+
return "<asyncio.Queue: not serializable>"
|
|
370
|
+
|
|
371
|
+
# Handle queue.Queue
|
|
372
|
+
if isinstance(obj, queue.Queue):
|
|
373
|
+
logger.warning("queue.Queue detected in checkpoint data. " "Queues cannot be serialized. Using placeholder.")
|
|
374
|
+
return "<queue.Queue: not serializable>"
|
|
375
|
+
|
|
376
|
+
# Handle ChainMap
|
|
377
|
+
if isinstance(obj, ChainMap):
|
|
378
|
+
logger.debug("Converting ChainMap to dict for serialization")
|
|
379
|
+
return AgentStateSerializer._sanitize_dict(dict(obj))
|
|
380
|
+
|
|
381
|
+
# Handle dataclasses
|
|
382
|
+
if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
|
|
383
|
+
logger.debug(f"Converting dataclass {type(obj).__name__} to dict for serialization")
|
|
384
|
+
return AgentStateSerializer._sanitize_dict(dataclasses.asdict(obj))
|
|
385
|
+
|
|
386
|
+
# Handle dictionaries
|
|
387
|
+
if isinstance(obj, dict):
|
|
388
|
+
return AgentStateSerializer._sanitize_dict(obj)
|
|
389
|
+
|
|
390
|
+
# Handle lists and tuples
|
|
391
|
+
if isinstance(obj, (list, tuple)):
|
|
392
|
+
sanitized_list = AgentStateSerializer._sanitize_list(list(obj))
|
|
393
|
+
return sanitized_list if isinstance(obj, list) else tuple(sanitized_list)
|
|
394
|
+
|
|
395
|
+
# Handle sets
|
|
396
|
+
if isinstance(obj, set):
|
|
397
|
+
logger.debug("Converting set to list for serialization")
|
|
398
|
+
return AgentStateSerializer._sanitize_list(list(obj))
|
|
399
|
+
|
|
400
|
+
# Handle bytes
|
|
401
|
+
if isinstance(obj, bytes):
|
|
402
|
+
logger.debug("Converting bytes to base64 string for serialization")
|
|
403
|
+
import base64
|
|
404
|
+
|
|
405
|
+
return base64.b64encode(obj).decode("utf-8")
|
|
406
|
+
|
|
407
|
+
# Try to convert using __dict__ for custom objects
|
|
408
|
+
if hasattr(obj, "__dict__"):
|
|
409
|
+
logger.warning(f"Converting custom object {type(obj).__name__} using __dict__. " "This may not preserve all state.")
|
|
410
|
+
return AgentStateSerializer._sanitize_dict(obj.__dict__)
|
|
411
|
+
|
|
412
|
+
# Last resort: convert to string
|
|
413
|
+
logger.warning(f"Object of type {type(obj).__name__} is not directly serializable. " "Converting to string representation.")
|
|
414
|
+
return str(obj)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
# Global persistence instance
|
|
418
|
+
_global_persistence: Optional[AgentPersistence] = None
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def get_global_persistence() -> AgentPersistence:
|
|
422
|
+
"""
|
|
423
|
+
Get or create global persistence instance.
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Global persistence instance (defaults to InMemoryPersistence)
|
|
427
|
+
"""
|
|
428
|
+
global _global_persistence
|
|
429
|
+
if _global_persistence is None:
|
|
430
|
+
_global_persistence = InMemoryPersistence()
|
|
431
|
+
return _global_persistence
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def set_global_persistence(persistence: AgentPersistence) -> None:
|
|
435
|
+
"""
|
|
436
|
+
Set global persistence instance.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
persistence: Persistence implementation to use
|
|
440
|
+
"""
|
|
441
|
+
global _global_persistence
|
|
442
|
+
_global_persistence = persistence
|
|
443
|
+
logger.info(f"Global persistence set to {type(persistence).__name__}")
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def reset_global_persistence() -> None:
|
|
447
|
+
"""Reset global persistence (primarily for testing)."""
|
|
448
|
+
global _global_persistence
|
|
449
|
+
_global_persistence = None
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prompt Templates Module
|
|
3
|
+
|
|
4
|
+
Native prompt template system replacing LangChain templates.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .template import (
|
|
8
|
+
PromptTemplate,
|
|
9
|
+
ChatPromptTemplate,
|
|
10
|
+
MessageTemplate,
|
|
11
|
+
TemplateMissingVariableError,
|
|
12
|
+
)
|
|
13
|
+
from .builder import MessageBuilder
|
|
14
|
+
from .formatters import (
|
|
15
|
+
format_conversation_history,
|
|
16
|
+
format_tool_result,
|
|
17
|
+
truncate_context,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"PromptTemplate",
|
|
22
|
+
"ChatPromptTemplate",
|
|
23
|
+
"MessageTemplate",
|
|
24
|
+
"TemplateMissingVariableError",
|
|
25
|
+
"MessageBuilder",
|
|
26
|
+
"format_conversation_history",
|
|
27
|
+
"format_tool_result",
|
|
28
|
+
"truncate_context",
|
|
29
|
+
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Message Builder
|
|
3
|
+
|
|
4
|
+
Helper for constructing LLMMessage lists.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Dict, Any, Optional
|
|
8
|
+
from aiecs.llm import LLMMessage
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MessageBuilder:
|
|
12
|
+
"""
|
|
13
|
+
Builder for constructing LLM message sequences.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
builder = MessageBuilder()
|
|
17
|
+
builder.add_system("You are a helpful assistant")
|
|
18
|
+
builder.add_user("What is AI?")
|
|
19
|
+
messages = builder.build()
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self) -> None:
|
|
23
|
+
"""Initialize message builder."""
|
|
24
|
+
self.messages: List[LLMMessage] = []
|
|
25
|
+
|
|
26
|
+
def add_system(self, content: str) -> "MessageBuilder":
|
|
27
|
+
"""
|
|
28
|
+
Add system message.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
content: Message content
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Self for chaining
|
|
35
|
+
"""
|
|
36
|
+
self.messages.append(LLMMessage(role="system", content=content))
|
|
37
|
+
return self
|
|
38
|
+
|
|
39
|
+
def add_user(self, content: str) -> "MessageBuilder":
|
|
40
|
+
"""
|
|
41
|
+
Add user message.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
content: Message content
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Self for chaining
|
|
48
|
+
"""
|
|
49
|
+
self.messages.append(LLMMessage(role="user", content=content))
|
|
50
|
+
return self
|
|
51
|
+
|
|
52
|
+
def add_assistant(self, content: str) -> "MessageBuilder":
|
|
53
|
+
"""
|
|
54
|
+
Add assistant message.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
content: Message content
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Self for chaining
|
|
61
|
+
"""
|
|
62
|
+
self.messages.append(LLMMessage(role="assistant", content=content))
|
|
63
|
+
return self
|
|
64
|
+
|
|
65
|
+
def add_message(self, role: str, content: str) -> "MessageBuilder":
|
|
66
|
+
"""
|
|
67
|
+
Add message with custom role.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
role: Message role
|
|
71
|
+
content: Message content
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
Self for chaining
|
|
75
|
+
"""
|
|
76
|
+
self.messages.append(LLMMessage(role=role, content=content))
|
|
77
|
+
return self
|
|
78
|
+
|
|
79
|
+
def add_messages(self, messages: List[LLMMessage]) -> "MessageBuilder":
|
|
80
|
+
"""
|
|
81
|
+
Add multiple messages.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
messages: List of messages to add
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Self for chaining
|
|
88
|
+
"""
|
|
89
|
+
self.messages.extend(messages)
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def add_context(self, context: Dict[str, Any], prefix: str = "Context:") -> "MessageBuilder":
|
|
93
|
+
"""
|
|
94
|
+
Add context as a system message.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
context: Context dictionary
|
|
98
|
+
prefix: Prefix for context message
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Self for chaining
|
|
102
|
+
"""
|
|
103
|
+
context_str = self._format_context(context)
|
|
104
|
+
if context_str:
|
|
105
|
+
self.add_system(f"{prefix}\n{context_str}")
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
def add_conversation_history(self, history: List[Dict[str, str]], max_messages: Optional[int] = None) -> "MessageBuilder":
|
|
109
|
+
"""
|
|
110
|
+
Add conversation history.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
history: List of {role, content} dicts
|
|
114
|
+
max_messages: Optional limit on number of messages
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Self for chaining
|
|
118
|
+
"""
|
|
119
|
+
if max_messages:
|
|
120
|
+
history = history[-max_messages:]
|
|
121
|
+
|
|
122
|
+
for msg in history:
|
|
123
|
+
self.add_message(msg.get("role", "user"), msg.get("content", ""))
|
|
124
|
+
|
|
125
|
+
return self
|
|
126
|
+
|
|
127
|
+
def clear(self) -> "MessageBuilder":
|
|
128
|
+
"""
|
|
129
|
+
Clear all messages.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Self for chaining
|
|
133
|
+
"""
|
|
134
|
+
self.messages.clear()
|
|
135
|
+
return self
|
|
136
|
+
|
|
137
|
+
def build(self) -> List[LLMMessage]:
|
|
138
|
+
"""
|
|
139
|
+
Build and return message list.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
List of LLMMessage instances
|
|
143
|
+
"""
|
|
144
|
+
return self.messages.copy()
|
|
145
|
+
|
|
146
|
+
def _format_context(self, context: Dict[str, Any]) -> str:
|
|
147
|
+
"""Format context dictionary as string."""
|
|
148
|
+
lines = []
|
|
149
|
+
for key, value in context.items():
|
|
150
|
+
if not key.startswith("_") and value is not None:
|
|
151
|
+
lines.append(f"{key}: {value}")
|
|
152
|
+
return "\n".join(lines) if lines else ""
|
|
153
|
+
|
|
154
|
+
def __len__(self) -> int:
|
|
155
|
+
"""Get number of messages."""
|
|
156
|
+
return len(self.messages)
|
|
157
|
+
|
|
158
|
+
def __repr__(self) -> str:
|
|
159
|
+
return f"MessageBuilder(messages={len(self.messages)})"
|