claude-mpm 4.1.0__py3-none-any.whl → 4.1.2__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.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +133 -58
- claude_mpm/agents/templates/web_ui.json +3 -3
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +271 -268
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +192 -141
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +120 -84
- claude_mpm/cli/commands/run_config_checker.py +4 -5
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +204 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +20 -23
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +581 -280
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -15
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +93 -38
- claude_mpm/hooks/claude_hooks/hook_handler.py +130 -76
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +136 -106
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +280 -160
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +10 -6
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +89 -80
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/METADATA +1 -1
- claude_mpm-4.1.2.dist-info/RECORD +498 -0
- claude_mpm-4.1.0.dist-info/RECORD +0 -494
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.0.dist-info → claude_mpm-4.1.2.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
|
|
4
5
|
"""
|
|
5
6
|
Agent Memory Manager Service
|
|
6
7
|
===========================
|
|
@@ -28,6 +29,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|
|
28
29
|
from claude_mpm.core.config import Config
|
|
29
30
|
from claude_mpm.core.interfaces import MemoryServiceInterface
|
|
30
31
|
from claude_mpm.core.unified_paths import get_path_manager
|
|
32
|
+
|
|
31
33
|
from .content_manager import MemoryContentManager
|
|
32
34
|
from .template_generator import MemoryTemplateGenerator
|
|
33
35
|
|
|
@@ -74,13 +76,13 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
74
76
|
self.project_root = get_path_manager().project_root
|
|
75
77
|
# Use current working directory by default, not project root
|
|
76
78
|
self.working_directory = working_directory or Path(os.getcwd())
|
|
77
|
-
|
|
79
|
+
|
|
78
80
|
# Use only project memory directory
|
|
79
81
|
self.project_memories_dir = self.working_directory / ".claude-mpm" / "memories"
|
|
80
|
-
|
|
82
|
+
|
|
81
83
|
# Primary memories_dir points to project
|
|
82
84
|
self.memories_dir = self.project_memories_dir
|
|
83
|
-
|
|
85
|
+
|
|
84
86
|
# Ensure project directory exists
|
|
85
87
|
self._ensure_memories_directory()
|
|
86
88
|
|
|
@@ -185,14 +187,14 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
185
187
|
|
|
186
188
|
def _get_memory_file_with_migration(self, directory: Path, agent_id: str) -> Path:
|
|
187
189
|
"""Get memory file path, migrating from old naming if needed.
|
|
188
|
-
|
|
190
|
+
|
|
189
191
|
WHY: Supports backward compatibility by automatically migrating from
|
|
190
192
|
the old {agent_id}_agent.md and {agent_id}.md formats to the new {agent_id}_memories.md format.
|
|
191
|
-
|
|
193
|
+
|
|
192
194
|
Args:
|
|
193
195
|
directory: Directory containing memory files
|
|
194
196
|
agent_id: The agent identifier
|
|
195
|
-
|
|
197
|
+
|
|
196
198
|
Returns:
|
|
197
199
|
Path: Path to the memory file (may not exist)
|
|
198
200
|
"""
|
|
@@ -200,7 +202,7 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
200
202
|
# Support migration from both old formats
|
|
201
203
|
old_file_agent = directory / f"{agent_id}_agent.md"
|
|
202
204
|
old_file_simple = directory / f"{agent_id}.md"
|
|
203
|
-
|
|
205
|
+
|
|
204
206
|
# Migrate from old formats if needed
|
|
205
207
|
if not new_file.exists():
|
|
206
208
|
# Try migrating from {agent_id}_agent.md first
|
|
@@ -208,26 +210,34 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
208
210
|
try:
|
|
209
211
|
content = old_file_agent.read_text(encoding="utf-8")
|
|
210
212
|
new_file.write_text(content, encoding="utf-8")
|
|
211
|
-
|
|
213
|
+
|
|
212
214
|
# Delete old file for all agents
|
|
213
215
|
old_file_agent.unlink()
|
|
214
|
-
self.logger.info(
|
|
216
|
+
self.logger.info(
|
|
217
|
+
f"Migrated memory file from {old_file_agent.name} to {new_file.name}"
|
|
218
|
+
)
|
|
215
219
|
except Exception as e:
|
|
216
|
-
self.logger.error(
|
|
220
|
+
self.logger.error(
|
|
221
|
+
f"Failed to migrate memory file for {agent_id}: {e}"
|
|
222
|
+
)
|
|
217
223
|
return old_file_agent
|
|
218
224
|
# Try migrating from {agent_id}.md
|
|
219
225
|
elif old_file_simple.exists():
|
|
220
226
|
try:
|
|
221
227
|
content = old_file_simple.read_text(encoding="utf-8")
|
|
222
228
|
new_file.write_text(content, encoding="utf-8")
|
|
223
|
-
|
|
229
|
+
|
|
224
230
|
# Delete old file for all agents
|
|
225
231
|
old_file_simple.unlink()
|
|
226
|
-
self.logger.info(
|
|
232
|
+
self.logger.info(
|
|
233
|
+
f"Migrated memory file from {old_file_simple.name} to {new_file.name}"
|
|
234
|
+
)
|
|
227
235
|
except Exception as e:
|
|
228
|
-
self.logger.error(
|
|
236
|
+
self.logger.error(
|
|
237
|
+
f"Failed to migrate memory file for {agent_id}: {e}"
|
|
238
|
+
)
|
|
229
239
|
return old_file_simple
|
|
230
|
-
|
|
240
|
+
|
|
231
241
|
return new_file
|
|
232
242
|
|
|
233
243
|
def load_agent_memory(self, agent_id: str) -> str:
|
|
@@ -244,18 +254,24 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
244
254
|
str: The memory file content, creating default if doesn't exist
|
|
245
255
|
"""
|
|
246
256
|
# All agents use project directory
|
|
247
|
-
project_memory_file = self._get_memory_file_with_migration(
|
|
248
|
-
|
|
257
|
+
project_memory_file = self._get_memory_file_with_migration(
|
|
258
|
+
self.project_memories_dir, agent_id
|
|
259
|
+
)
|
|
260
|
+
|
|
249
261
|
# Load project-level memory if exists
|
|
250
262
|
if project_memory_file.exists():
|
|
251
263
|
try:
|
|
252
264
|
project_memory = project_memory_file.read_text(encoding="utf-8")
|
|
253
|
-
project_memory = self.content_manager.validate_and_repair(
|
|
265
|
+
project_memory = self.content_manager.validate_and_repair(
|
|
266
|
+
project_memory, agent_id
|
|
267
|
+
)
|
|
254
268
|
self.logger.debug(f"Loaded project-level memory for {agent_id}")
|
|
255
269
|
return project_memory
|
|
256
270
|
except Exception as e:
|
|
257
|
-
self.logger.error(
|
|
258
|
-
|
|
271
|
+
self.logger.error(
|
|
272
|
+
f"Error reading project memory file for {agent_id}: {e}"
|
|
273
|
+
)
|
|
274
|
+
|
|
259
275
|
# Memory doesn't exist - create default in project directory
|
|
260
276
|
self.logger.info(f"Creating default memory for agent: {agent_id}")
|
|
261
277
|
return self._create_default_memory(agent_id)
|
|
@@ -343,14 +359,16 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
343
359
|
try:
|
|
344
360
|
# All agents save to project directory
|
|
345
361
|
target_dir = self.project_memories_dir
|
|
346
|
-
|
|
362
|
+
|
|
347
363
|
# Ensure directory exists
|
|
348
364
|
target_dir.mkdir(parents=True, exist_ok=True)
|
|
349
|
-
|
|
365
|
+
|
|
350
366
|
memory_file = target_dir / f"{agent_id}_memories.md"
|
|
351
367
|
memory_file.write_text(content, encoding="utf-8")
|
|
352
|
-
|
|
353
|
-
self.logger.info(
|
|
368
|
+
|
|
369
|
+
self.logger.info(
|
|
370
|
+
f"Saved {agent_id} memory to project directory: {memory_file}"
|
|
371
|
+
)
|
|
354
372
|
return True
|
|
355
373
|
except Exception as e:
|
|
356
374
|
self.logger.error(f"Error saving memory for {agent_id}: {e}")
|
|
@@ -459,25 +477,25 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
459
477
|
try:
|
|
460
478
|
import json
|
|
461
479
|
import re
|
|
462
|
-
|
|
480
|
+
|
|
463
481
|
# Log that we're processing memory for this agent
|
|
464
482
|
is_pm = agent_id.upper() == "PM"
|
|
465
483
|
self.logger.debug(f"Extracting memory for {agent_id} (is_pm={is_pm})")
|
|
466
|
-
|
|
484
|
+
|
|
467
485
|
# Look for JSON block in the response
|
|
468
486
|
# Pattern matches ```json ... ``` blocks
|
|
469
|
-
json_pattern = r
|
|
487
|
+
json_pattern = r"```json\s*(.*?)\s*```"
|
|
470
488
|
json_matches = re.findall(json_pattern, response, re.DOTALL)
|
|
471
|
-
|
|
489
|
+
|
|
472
490
|
if not json_matches:
|
|
473
491
|
# Also try to find inline JSON objects
|
|
474
492
|
json_pattern2 = r'\{[^{}]*"(?:remember|Remember|MEMORIES)"[^{}]*\}'
|
|
475
493
|
json_matches = re.findall(json_pattern2, response, re.DOTALL)
|
|
476
|
-
|
|
494
|
+
|
|
477
495
|
for json_str in json_matches:
|
|
478
496
|
try:
|
|
479
497
|
data = json.loads(json_str)
|
|
480
|
-
|
|
498
|
+
|
|
481
499
|
# Check for complete memory replacement in "MEMORIES" field
|
|
482
500
|
if "MEMORIES" in data and data["MEMORIES"] is not None:
|
|
483
501
|
memories = data["MEMORIES"]
|
|
@@ -491,26 +509,33 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
491
509
|
if not item_text.startswith("-"):
|
|
492
510
|
item_text = f"- {item_text}"
|
|
493
511
|
valid_items.append(item_text)
|
|
494
|
-
|
|
512
|
+
|
|
495
513
|
if valid_items:
|
|
496
|
-
self.logger.info(
|
|
497
|
-
|
|
514
|
+
self.logger.info(
|
|
515
|
+
f"Replacing all memories for {agent_id} with {len(valid_items)} items"
|
|
516
|
+
)
|
|
517
|
+
success = self.replace_agent_memory(
|
|
518
|
+
agent_id, valid_items
|
|
519
|
+
)
|
|
498
520
|
if success:
|
|
499
|
-
self.logger.info(
|
|
521
|
+
self.logger.info(
|
|
522
|
+
f"Successfully replaced memories for {agent_id}"
|
|
523
|
+
)
|
|
500
524
|
return True
|
|
501
|
-
|
|
502
|
-
|
|
525
|
+
self.logger.error(
|
|
526
|
+
f"Failed to replace memories for {agent_id}"
|
|
527
|
+
)
|
|
503
528
|
continue # Skip checking remember field if MEMORIES was processed
|
|
504
|
-
|
|
529
|
+
|
|
505
530
|
# Check for incremental memory updates in "remember" field
|
|
506
531
|
memory_items = None
|
|
507
|
-
|
|
532
|
+
|
|
508
533
|
# Check both "remember" and "Remember" fields
|
|
509
534
|
if "remember" in data:
|
|
510
535
|
memory_items = data["remember"]
|
|
511
536
|
elif "Remember" in data:
|
|
512
537
|
memory_items = data["Remember"]
|
|
513
|
-
|
|
538
|
+
|
|
514
539
|
# Process memory items if found and not null
|
|
515
540
|
if memory_items is not None and memory_items != "null":
|
|
516
541
|
# Skip if explicitly null or empty list
|
|
@@ -520,129 +545,146 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
520
545
|
for item in memory_items:
|
|
521
546
|
if item and isinstance(item, str) and item.strip():
|
|
522
547
|
valid_items.append(item.strip())
|
|
523
|
-
|
|
548
|
+
|
|
524
549
|
# Only proceed if we have valid items
|
|
525
550
|
if valid_items:
|
|
526
|
-
self.logger.info(
|
|
527
|
-
|
|
551
|
+
self.logger.info(
|
|
552
|
+
f"Found {len(valid_items)} memory items for {agent_id}: {valid_items[:2]}..."
|
|
553
|
+
)
|
|
554
|
+
success = self._add_learnings_to_memory(
|
|
555
|
+
agent_id, valid_items
|
|
556
|
+
)
|
|
528
557
|
if success:
|
|
529
|
-
self.logger.info(
|
|
558
|
+
self.logger.info(
|
|
559
|
+
f"Successfully saved {len(valid_items)} memories for {agent_id} to project directory"
|
|
560
|
+
)
|
|
530
561
|
return True
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
562
|
+
self.logger.error(
|
|
563
|
+
f"Failed to save memories for {agent_id}"
|
|
564
|
+
)
|
|
565
|
+
|
|
534
566
|
except json.JSONDecodeError as je:
|
|
535
567
|
# Not valid JSON, continue to next match
|
|
536
568
|
self.logger.debug(f"JSON decode error for {agent_id}: {je}")
|
|
537
569
|
continue
|
|
538
|
-
|
|
570
|
+
|
|
539
571
|
self.logger.debug(f"No memory items found in response for {agent_id}")
|
|
540
572
|
return False
|
|
541
|
-
|
|
573
|
+
|
|
542
574
|
except Exception as e:
|
|
543
|
-
self.logger.error(
|
|
575
|
+
self.logger.error(
|
|
576
|
+
f"Error extracting memory from response for {agent_id}: {e}"
|
|
577
|
+
)
|
|
544
578
|
return False
|
|
545
|
-
|
|
579
|
+
|
|
546
580
|
def _add_learnings_to_memory(self, agent_id: str, learnings: List[str]) -> bool:
|
|
547
581
|
"""Add new learnings to agent memory as a simple list.
|
|
548
|
-
|
|
582
|
+
|
|
549
583
|
WHY: Simplified memory system - all memories are stored as a simple list
|
|
550
584
|
without categorization, making it easier to manage and understand.
|
|
551
585
|
Updates timestamp on every update.
|
|
552
|
-
|
|
586
|
+
|
|
553
587
|
Args:
|
|
554
588
|
agent_id: The agent identifier
|
|
555
589
|
learnings: List of new learning strings to add
|
|
556
|
-
|
|
590
|
+
|
|
557
591
|
Returns:
|
|
558
592
|
bool: True if memory was successfully updated
|
|
559
593
|
"""
|
|
560
594
|
try:
|
|
561
595
|
# Load existing memory
|
|
562
596
|
current_memory = self.load_agent_memory(agent_id)
|
|
563
|
-
|
|
597
|
+
|
|
564
598
|
# Parse existing memory into a simple list
|
|
565
599
|
existing_items = self._parse_memory_list(current_memory)
|
|
566
|
-
|
|
600
|
+
|
|
567
601
|
# Clean template placeholders if this is a fresh memory
|
|
568
602
|
existing_items = self._clean_template_placeholders_list(existing_items)
|
|
569
|
-
|
|
603
|
+
|
|
570
604
|
# Add new learnings, avoiding duplicates
|
|
571
605
|
updated = False
|
|
572
606
|
for learning in learnings:
|
|
573
607
|
if not learning or not isinstance(learning, str):
|
|
574
608
|
continue
|
|
575
|
-
|
|
609
|
+
|
|
576
610
|
learning = learning.strip()
|
|
577
611
|
if not learning:
|
|
578
612
|
continue
|
|
579
|
-
|
|
613
|
+
|
|
580
614
|
# Check for duplicates (case-insensitive)
|
|
581
615
|
normalized_learning = learning.lower()
|
|
582
616
|
# Strip bullet points from existing items for comparison
|
|
583
|
-
existing_normalized = [
|
|
584
|
-
|
|
617
|
+
existing_normalized = [
|
|
618
|
+
item.lstrip("- ").strip().lower() for item in existing_items
|
|
619
|
+
]
|
|
620
|
+
|
|
585
621
|
if normalized_learning not in existing_normalized:
|
|
586
622
|
# Add bullet point if not present
|
|
587
623
|
if not learning.startswith("-"):
|
|
588
624
|
learning = f"- {learning}"
|
|
589
625
|
existing_items.append(learning)
|
|
590
|
-
self.logger.info(
|
|
626
|
+
self.logger.info(
|
|
627
|
+
f"Added new memory for {agent_id}: {learning[:50]}..."
|
|
628
|
+
)
|
|
591
629
|
updated = True
|
|
592
630
|
else:
|
|
593
|
-
self.logger.debug(
|
|
594
|
-
|
|
631
|
+
self.logger.debug(
|
|
632
|
+
f"Skipping duplicate memory for {agent_id}: {learning}"
|
|
633
|
+
)
|
|
634
|
+
|
|
595
635
|
# Only save if we actually added new items
|
|
596
636
|
if not updated:
|
|
597
637
|
self.logger.debug(f"No new memories to add for {agent_id}")
|
|
598
638
|
return True # Not an error, just nothing new to add
|
|
599
|
-
|
|
639
|
+
|
|
600
640
|
# Rebuild memory content as simple list with updated timestamp
|
|
601
641
|
new_content = self._build_simple_memory_content(agent_id, existing_items)
|
|
602
|
-
|
|
642
|
+
|
|
603
643
|
# Validate and save
|
|
604
644
|
agent_limits = self._get_agent_limits(agent_id)
|
|
605
645
|
if self.content_manager.exceeds_limits(new_content, agent_limits):
|
|
606
646
|
self.logger.debug(f"Memory for {agent_id} exceeds limits, truncating")
|
|
607
|
-
new_content = self.content_manager.truncate_simple_list(
|
|
608
|
-
|
|
647
|
+
new_content = self.content_manager.truncate_simple_list(
|
|
648
|
+
new_content, agent_limits
|
|
649
|
+
)
|
|
650
|
+
|
|
609
651
|
# All memories go to project directory
|
|
610
652
|
return self._save_memory_file(agent_id, new_content)
|
|
611
|
-
|
|
653
|
+
|
|
612
654
|
except Exception as e:
|
|
613
655
|
self.logger.error(f"Error adding learnings to memory for {agent_id}: {e}")
|
|
614
656
|
return False
|
|
615
|
-
|
|
657
|
+
|
|
616
658
|
def _parse_memory_list(self, memory_content: str) -> List[str]:
|
|
617
659
|
"""Parse memory content into a simple list.
|
|
618
|
-
|
|
660
|
+
|
|
619
661
|
Args:
|
|
620
662
|
memory_content: Raw memory file content
|
|
621
|
-
|
|
663
|
+
|
|
622
664
|
Returns:
|
|
623
665
|
List of memory items
|
|
624
666
|
"""
|
|
625
667
|
items = []
|
|
626
|
-
|
|
627
|
-
for line in memory_content.split(
|
|
668
|
+
|
|
669
|
+
for line in memory_content.split("\n"):
|
|
628
670
|
line = line.strip()
|
|
629
671
|
# Skip metadata lines and headers
|
|
630
|
-
if line.startswith(
|
|
672
|
+
if line.startswith(("<!-- ", "#")) or not line:
|
|
631
673
|
continue
|
|
632
674
|
# Collect items (with or without bullet points)
|
|
633
|
-
if line.startswith(
|
|
675
|
+
if line.startswith("- "):
|
|
634
676
|
items.append(line)
|
|
635
|
-
elif line and not line.startswith(
|
|
677
|
+
elif line and not line.startswith("##"): # Legacy format without bullets
|
|
636
678
|
items.append(f"- {line}")
|
|
637
|
-
|
|
679
|
+
|
|
638
680
|
return items
|
|
639
|
-
|
|
681
|
+
|
|
640
682
|
def _clean_template_placeholders_list(self, items: List[str]) -> List[str]:
|
|
641
683
|
"""Remove template placeholder text from item list.
|
|
642
|
-
|
|
684
|
+
|
|
643
685
|
Args:
|
|
644
686
|
items: List of memory items
|
|
645
|
-
|
|
687
|
+
|
|
646
688
|
Returns:
|
|
647
689
|
List with placeholder text removed
|
|
648
690
|
"""
|
|
@@ -653,9 +695,9 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
653
695
|
"Extract implementation guidelines from project documentation",
|
|
654
696
|
"Learn from errors encountered during project work",
|
|
655
697
|
"Project analysis pending - gather context during tasks",
|
|
656
|
-
"claude-mpm: Software project requiring analysis"
|
|
698
|
+
"claude-mpm: Software project requiring analysis",
|
|
657
699
|
]
|
|
658
|
-
|
|
700
|
+
|
|
659
701
|
cleaned = []
|
|
660
702
|
for item in items:
|
|
661
703
|
# Remove bullet point for comparison
|
|
@@ -663,15 +705,17 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
663
705
|
# Keep item if it's not a placeholder
|
|
664
706
|
if item_text and item_text not in placeholders:
|
|
665
707
|
cleaned.append(item)
|
|
666
|
-
|
|
708
|
+
|
|
667
709
|
return cleaned
|
|
668
|
-
|
|
669
|
-
def _clean_template_placeholders(
|
|
710
|
+
|
|
711
|
+
def _clean_template_placeholders(
|
|
712
|
+
self, sections: Dict[str, List[str]]
|
|
713
|
+
) -> Dict[str, List[str]]:
|
|
670
714
|
"""Remove template placeholder text from sections.
|
|
671
|
-
|
|
715
|
+
|
|
672
716
|
Args:
|
|
673
717
|
sections: Dict mapping section names to lists of items
|
|
674
|
-
|
|
718
|
+
|
|
675
719
|
Returns:
|
|
676
720
|
Dict with placeholder text removed
|
|
677
721
|
"""
|
|
@@ -682,9 +726,9 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
682
726
|
"Extract implementation guidelines from project documentation",
|
|
683
727
|
"Learn from errors encountered during project work",
|
|
684
728
|
"Project analysis pending - gather context during tasks",
|
|
685
|
-
"claude-mpm: Software project requiring analysis"
|
|
729
|
+
"claude-mpm: Software project requiring analysis",
|
|
686
730
|
]
|
|
687
|
-
|
|
731
|
+
|
|
688
732
|
cleaned = {}
|
|
689
733
|
for section_name, items in sections.items():
|
|
690
734
|
cleaned_items = []
|
|
@@ -694,84 +738,151 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
694
738
|
# Keep item if it's not a placeholder
|
|
695
739
|
if item_text and item_text not in placeholders:
|
|
696
740
|
cleaned_items.append(item)
|
|
697
|
-
|
|
741
|
+
|
|
698
742
|
# Only include section if it has real content
|
|
699
743
|
if cleaned_items:
|
|
700
744
|
cleaned[section_name] = cleaned_items
|
|
701
|
-
|
|
745
|
+
|
|
702
746
|
return cleaned
|
|
703
|
-
|
|
747
|
+
|
|
704
748
|
def _categorize_learning(self, learning: str) -> str:
|
|
705
749
|
"""Categorize a learning item into appropriate section.
|
|
706
|
-
|
|
750
|
+
|
|
707
751
|
Args:
|
|
708
752
|
learning: The learning string to categorize
|
|
709
|
-
|
|
753
|
+
|
|
710
754
|
Returns:
|
|
711
755
|
str: The section name for this learning
|
|
712
756
|
"""
|
|
713
757
|
learning_lower = learning.lower()
|
|
714
|
-
|
|
758
|
+
|
|
715
759
|
# Check for keywords to categorize with improved patterns
|
|
716
760
|
# Order matters - more specific patterns should come first
|
|
717
|
-
|
|
761
|
+
|
|
718
762
|
# Architecture keywords
|
|
719
|
-
if any(
|
|
763
|
+
if any(
|
|
764
|
+
word in learning_lower
|
|
765
|
+
for word in [
|
|
766
|
+
"architecture",
|
|
767
|
+
"structure",
|
|
768
|
+
"design",
|
|
769
|
+
"module",
|
|
770
|
+
"component",
|
|
771
|
+
"microservices",
|
|
772
|
+
"service-oriented",
|
|
773
|
+
]
|
|
774
|
+
):
|
|
720
775
|
return "Project Architecture"
|
|
721
|
-
|
|
776
|
+
|
|
722
777
|
# Integration keywords (check before patterns to avoid "use" conflict)
|
|
723
|
-
|
|
778
|
+
if any(
|
|
779
|
+
word in learning_lower
|
|
780
|
+
for word in [
|
|
781
|
+
"integration",
|
|
782
|
+
"interface",
|
|
783
|
+
"api",
|
|
784
|
+
"connection",
|
|
785
|
+
"database",
|
|
786
|
+
"pooling",
|
|
787
|
+
"via",
|
|
788
|
+
]
|
|
789
|
+
):
|
|
724
790
|
return "Integration Points"
|
|
725
|
-
|
|
791
|
+
|
|
726
792
|
# Mistake keywords (check before patterns to avoid conflicts)
|
|
727
|
-
|
|
793
|
+
if any(
|
|
794
|
+
word in learning_lower
|
|
795
|
+
for word in ["mistake", "error", "avoid", "don't", "never", "not"]
|
|
796
|
+
):
|
|
728
797
|
return "Common Mistakes to Avoid"
|
|
729
|
-
|
|
798
|
+
|
|
730
799
|
# Context keywords (check before patterns to avoid "working", "version" conflicts)
|
|
731
|
-
|
|
800
|
+
if any(
|
|
801
|
+
word in learning_lower
|
|
802
|
+
for word in [
|
|
803
|
+
"context",
|
|
804
|
+
"current",
|
|
805
|
+
"currently",
|
|
806
|
+
"working",
|
|
807
|
+
"version",
|
|
808
|
+
"release",
|
|
809
|
+
"candidate",
|
|
810
|
+
]
|
|
811
|
+
):
|
|
732
812
|
return "Current Technical Context"
|
|
733
|
-
|
|
813
|
+
|
|
734
814
|
# Guideline keywords (check before patterns to avoid "must", "should" conflicts)
|
|
735
|
-
|
|
815
|
+
if any(
|
|
816
|
+
word in learning_lower
|
|
817
|
+
for word in [
|
|
818
|
+
"guideline",
|
|
819
|
+
"rule",
|
|
820
|
+
"standard",
|
|
821
|
+
"practice",
|
|
822
|
+
"docstring",
|
|
823
|
+
"documentation",
|
|
824
|
+
"must",
|
|
825
|
+
"should",
|
|
826
|
+
"include",
|
|
827
|
+
"comprehensive",
|
|
828
|
+
]
|
|
829
|
+
):
|
|
736
830
|
return "Implementation Guidelines"
|
|
737
|
-
|
|
831
|
+
|
|
738
832
|
# Pattern keywords (including dependency injection, conventions)
|
|
739
|
-
|
|
833
|
+
if any(
|
|
834
|
+
word in learning_lower
|
|
835
|
+
for word in [
|
|
836
|
+
"pattern",
|
|
837
|
+
"convention",
|
|
838
|
+
"style",
|
|
839
|
+
"format",
|
|
840
|
+
"dependency injection",
|
|
841
|
+
"instantiation",
|
|
842
|
+
"use",
|
|
843
|
+
"implement",
|
|
844
|
+
]
|
|
845
|
+
):
|
|
740
846
|
return "Coding Patterns Learned"
|
|
741
|
-
|
|
742
|
-
# Strategy keywords
|
|
743
|
-
|
|
847
|
+
|
|
848
|
+
# Strategy keywords
|
|
849
|
+
if any(
|
|
850
|
+
word in learning_lower
|
|
851
|
+
for word in ["strategy", "approach", "method", "technique", "effective"]
|
|
852
|
+
):
|
|
744
853
|
return "Effective Strategies"
|
|
745
|
-
|
|
854
|
+
|
|
746
855
|
# Performance keywords
|
|
747
|
-
|
|
856
|
+
if any(
|
|
857
|
+
word in learning_lower
|
|
858
|
+
for word in ["performance", "optimization", "speed", "efficiency"]
|
|
859
|
+
):
|
|
748
860
|
return "Performance Considerations"
|
|
749
|
-
|
|
861
|
+
|
|
750
862
|
# Domain keywords
|
|
751
|
-
|
|
863
|
+
if any(word in learning_lower for word in ["domain", "business", "specific"]):
|
|
752
864
|
return "Domain-Specific Knowledge"
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
865
|
+
|
|
866
|
+
return "Recent Learnings"
|
|
867
|
+
|
|
757
868
|
def _build_simple_memory_content(self, agent_id: str, items: List[str]) -> str:
|
|
758
869
|
"""Build memory content as a simple list with updated timestamp.
|
|
759
|
-
|
|
870
|
+
|
|
760
871
|
Args:
|
|
761
872
|
agent_id: The agent identifier
|
|
762
873
|
items: List of memory items
|
|
763
|
-
|
|
874
|
+
|
|
764
875
|
Returns:
|
|
765
876
|
str: The formatted memory content
|
|
766
877
|
"""
|
|
767
878
|
lines = []
|
|
768
|
-
|
|
879
|
+
|
|
769
880
|
# Add header
|
|
770
881
|
lines.append(f"# Agent Memory: {agent_id}")
|
|
771
882
|
# Always update timestamp when building new content
|
|
772
883
|
lines.append(f"<!-- Last Updated: {datetime.now().isoformat()}Z -->")
|
|
773
884
|
lines.append("")
|
|
774
|
-
|
|
885
|
+
|
|
775
886
|
# Add all items as a simple list
|
|
776
887
|
for item in items:
|
|
777
888
|
if item.strip():
|
|
@@ -780,9 +891,9 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
780
891
|
lines.append(f"- {item.strip()}")
|
|
781
892
|
else:
|
|
782
893
|
lines.append(item.strip())
|
|
783
|
-
|
|
784
|
-
return
|
|
785
|
-
|
|
894
|
+
|
|
895
|
+
return "\n".join(lines)
|
|
896
|
+
|
|
786
897
|
def replace_agent_memory(self, agent_id: str, memory_items: List[str]) -> bool:
|
|
787
898
|
"""Replace agent's memory with new content as a simple list.
|
|
788
899
|
|
|
@@ -800,16 +911,18 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
800
911
|
try:
|
|
801
912
|
# Build new memory content as simple list with updated timestamp
|
|
802
913
|
new_content = self._build_simple_memory_content(agent_id, memory_items)
|
|
803
|
-
|
|
914
|
+
|
|
804
915
|
# Validate and save
|
|
805
916
|
agent_limits = self._get_agent_limits(agent_id)
|
|
806
917
|
if self.content_manager.exceeds_limits(new_content, agent_limits):
|
|
807
918
|
self.logger.debug(f"Memory for {agent_id} exceeds limits, truncating")
|
|
808
|
-
new_content = self.content_manager.truncate_simple_list(
|
|
809
|
-
|
|
919
|
+
new_content = self.content_manager.truncate_simple_list(
|
|
920
|
+
new_content, agent_limits
|
|
921
|
+
)
|
|
922
|
+
|
|
810
923
|
# Save the new memory
|
|
811
924
|
return self._save_memory_file(agent_id, new_content)
|
|
812
|
-
|
|
925
|
+
|
|
813
926
|
except Exception as e:
|
|
814
927
|
self.logger.error(f"Error replacing memory for {agent_id}: {e}")
|
|
815
928
|
return False
|
|
@@ -832,13 +945,13 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
832
945
|
"total_agents": 0,
|
|
833
946
|
"total_size_kb": 0,
|
|
834
947
|
"agents": {},
|
|
835
|
-
"system_health": "healthy"
|
|
948
|
+
"system_health": "healthy",
|
|
836
949
|
}
|
|
837
|
-
|
|
950
|
+
|
|
838
951
|
if self.memories_dir.exists():
|
|
839
952
|
memory_files = list(self.memories_dir.glob("*_memories.md"))
|
|
840
953
|
status["total_agents"] = len(memory_files)
|
|
841
|
-
|
|
954
|
+
|
|
842
955
|
for file_path in memory_files:
|
|
843
956
|
if file_path.name != "README.md":
|
|
844
957
|
size_kb = file_path.stat().st_size / 1024
|
|
@@ -846,9 +959,9 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
846
959
|
agent_id = file_path.stem.replace("_memories", "")
|
|
847
960
|
status["agents"][agent_id] = {
|
|
848
961
|
"file": file_path.name,
|
|
849
|
-
"size_kb": round(size_kb, 2)
|
|
962
|
+
"size_kb": round(size_kb, 2),
|
|
850
963
|
}
|
|
851
|
-
|
|
964
|
+
|
|
852
965
|
return status
|
|
853
966
|
|
|
854
967
|
def cross_reference_memories(self, query: Optional[str] = None) -> Dict[str, Any]:
|
|
@@ -868,7 +981,7 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
868
981
|
return {
|
|
869
982
|
"status": "deprecated",
|
|
870
983
|
"message": "Cross-reference analysis has been deprecated in favor of simplified memory management",
|
|
871
|
-
"suggestion": "Use get_memory_status() for memory overview"
|
|
984
|
+
"suggestion": "Use get_memory_status() for memory overview",
|
|
872
985
|
}
|
|
873
986
|
|
|
874
987
|
def get_all_memories_raw(self) -> Dict[str, Any]:
|
|
@@ -883,9 +996,9 @@ class AgentMemoryManager(MemoryServiceInterface):
|
|
|
883
996
|
"""
|
|
884
997
|
# Deprecated - return informative message
|
|
885
998
|
return {
|
|
886
|
-
"status": "deprecated",
|
|
999
|
+
"status": "deprecated",
|
|
887
1000
|
"message": "Raw memory access has been deprecated in favor of simplified memory management",
|
|
888
|
-
"suggestion": "Use load_agent_memory() for specific agent memories"
|
|
1001
|
+
"suggestion": "Use load_agent_memory() for specific agent memories",
|
|
889
1002
|
}
|
|
890
1003
|
|
|
891
1004
|
def _ensure_memories_directory(self):
|
|
@@ -944,43 +1057,43 @@ Standard markdown with structured sections. Agents expect:
|
|
|
944
1057
|
self.logger.error(f"Error ensuring memories directory: {e}")
|
|
945
1058
|
# Continue anyway - memory system should not block operations
|
|
946
1059
|
|
|
947
|
-
|
|
948
|
-
|
|
949
1060
|
def _parse_memory_sections(self, memory_content: str) -> Dict[str, List[str]]:
|
|
950
1061
|
"""Parse memory content into sections and items.
|
|
951
|
-
|
|
1062
|
+
|
|
952
1063
|
Args:
|
|
953
1064
|
memory_content: Raw memory file content
|
|
954
|
-
|
|
1065
|
+
|
|
955
1066
|
Returns:
|
|
956
1067
|
Dict mapping section names to lists of items
|
|
957
1068
|
"""
|
|
958
1069
|
sections = {}
|
|
959
1070
|
current_section = None
|
|
960
1071
|
current_items = []
|
|
961
|
-
|
|
962
|
-
for line in memory_content.split(
|
|
1072
|
+
|
|
1073
|
+
for line in memory_content.split("\n"):
|
|
963
1074
|
# Skip metadata lines
|
|
964
|
-
if line.startswith(
|
|
1075
|
+
if line.startswith("<!-- ") and line.endswith(" -->"):
|
|
965
1076
|
continue
|
|
966
1077
|
# Check for section headers (## Level 2 headers)
|
|
967
|
-
|
|
1078
|
+
if line.startswith("## "):
|
|
968
1079
|
# Save previous section if exists
|
|
969
1080
|
if current_section and current_items:
|
|
970
1081
|
sections[current_section] = current_items
|
|
971
|
-
|
|
1082
|
+
|
|
972
1083
|
# Start new section
|
|
973
1084
|
current_section = line[3:].strip() # Remove "## " prefix
|
|
974
1085
|
current_items = []
|
|
975
1086
|
# Collect non-empty lines as items (but not HTML comments)
|
|
976
|
-
elif
|
|
1087
|
+
elif (
|
|
1088
|
+
line.strip() and current_section and not line.strip().startswith("<!--")
|
|
1089
|
+
):
|
|
977
1090
|
# Keep the full line with its formatting
|
|
978
1091
|
current_items.append(line.strip())
|
|
979
|
-
|
|
1092
|
+
|
|
980
1093
|
# Save last section
|
|
981
1094
|
if current_section and current_items:
|
|
982
1095
|
sections[current_section] = current_items
|
|
983
|
-
|
|
1096
|
+
|
|
984
1097
|
return sections
|
|
985
1098
|
|
|
986
1099
|
# ================================================================================
|
|
@@ -1066,12 +1179,8 @@ Standard markdown with structured sections. Agents expect:
|
|
|
1066
1179
|
Dictionary with memory metrics
|
|
1067
1180
|
"""
|
|
1068
1181
|
# Minimal implementation for interface compliance
|
|
1069
|
-
metrics = {
|
|
1070
|
-
|
|
1071
|
-
"agent_count": 0,
|
|
1072
|
-
"agents": {}
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1182
|
+
metrics = {"total_memory_kb": 0, "agent_count": 0, "agents": {}}
|
|
1183
|
+
|
|
1075
1184
|
if self.memories_dir.exists():
|
|
1076
1185
|
if agent_id:
|
|
1077
1186
|
# Metrics for specific agent
|
|
@@ -1080,8 +1189,17 @@ Standard markdown with structured sections. Agents expect:
|
|
|
1080
1189
|
size_kb = memory_file.stat().st_size / 1024
|
|
1081
1190
|
metrics["agents"][agent_id] = {
|
|
1082
1191
|
"size_kb": round(size_kb, 2),
|
|
1083
|
-
"limit_kb": self._get_agent_limits(agent_id)[
|
|
1084
|
-
|
|
1192
|
+
"limit_kb": self._get_agent_limits(agent_id)[
|
|
1193
|
+
"max_file_size_kb"
|
|
1194
|
+
],
|
|
1195
|
+
"usage_percent": round(
|
|
1196
|
+
(
|
|
1197
|
+
size_kb
|
|
1198
|
+
/ self._get_agent_limits(agent_id)["max_file_size_kb"]
|
|
1199
|
+
)
|
|
1200
|
+
* 100,
|
|
1201
|
+
1,
|
|
1202
|
+
),
|
|
1085
1203
|
}
|
|
1086
1204
|
metrics["total_memory_kb"] = round(size_kb, 2)
|
|
1087
1205
|
metrics["agent_count"] = 1
|
|
@@ -1092,17 +1210,19 @@ Standard markdown with structured sections. Agents expect:
|
|
|
1092
1210
|
if file_path.name != "README.md":
|
|
1093
1211
|
agent_name = file_path.stem.replace("_memories", "")
|
|
1094
1212
|
size_kb = file_path.stat().st_size / 1024
|
|
1095
|
-
limit_kb = self._get_agent_limits(agent_name)[
|
|
1213
|
+
limit_kb = self._get_agent_limits(agent_name)[
|
|
1214
|
+
"max_file_size_kb"
|
|
1215
|
+
]
|
|
1096
1216
|
metrics["agents"][agent_name] = {
|
|
1097
1217
|
"size_kb": round(size_kb, 2),
|
|
1098
1218
|
"limit_kb": limit_kb,
|
|
1099
|
-
"usage_percent": round((size_kb / limit_kb) * 100, 1)
|
|
1219
|
+
"usage_percent": round((size_kb / limit_kb) * 100, 1),
|
|
1100
1220
|
}
|
|
1101
1221
|
metrics["total_memory_kb"] += size_kb
|
|
1102
|
-
|
|
1222
|
+
|
|
1103
1223
|
metrics["total_memory_kb"] = round(metrics["total_memory_kb"], 2)
|
|
1104
1224
|
metrics["agent_count"] = len(metrics["agents"])
|
|
1105
|
-
|
|
1225
|
+
|
|
1106
1226
|
return metrics
|
|
1107
1227
|
|
|
1108
1228
|
|