claude-mpm 3.9.9__py3-none-any.whl → 4.0.3__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/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +155 -0
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +90 -49
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +21 -18
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +143 -762
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +203 -81
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +305 -197
- claude_mpm/cli/parser.py +24 -1150
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +104 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +217 -0
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +36 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +120 -54
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +571 -0
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +40 -23
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +14 -21
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +97 -93
- claude_mpm/services/mcp_gateway/main.py +307 -127
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
- claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +110 -121
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +223 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +145 -65
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +170 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +20 -534
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +9 -0
- claude_mpm/storage/state_storage.py +552 -0
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/memory_guardian.py +0 -770
- claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.9.dist-info/RECORD +0 -293
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
| @@ -13,16 +13,23 @@ agent outputs because: | |
| 13 13 | 
             
            """
         | 
| 14 14 |  | 
| 15 15 | 
             
            import re
         | 
| 16 | 
            -
            from typing import  | 
| 17 | 
            -
             | 
| 16 | 
            +
            from typing import Any, Dict, List
         | 
| 17 | 
            +
             | 
| 18 18 | 
             
            from claude_mpm.core.config import Config
         | 
| 19 19 | 
             
            from claude_mpm.core.logger import get_logger
         | 
| 20 | 
            +
            from claude_mpm.hooks.base_hook import (
         | 
| 21 | 
            +
                HookContext,
         | 
| 22 | 
            +
                HookResult,
         | 
| 23 | 
            +
                PostDelegationHook,
         | 
| 24 | 
            +
                PreDelegationHook,
         | 
| 25 | 
            +
            )
         | 
| 20 26 |  | 
| 21 27 | 
             
            logger = get_logger(__name__)
         | 
| 22 28 |  | 
| 23 29 | 
             
            # Try to import memory manager with fallback handling
         | 
| 24 30 | 
             
            try:
         | 
| 25 31 | 
             
                from claude_mpm.services.agents.memory import AgentMemoryManager
         | 
| 32 | 
            +
             | 
| 26 33 | 
             
                MEMORY_MANAGER_AVAILABLE = True
         | 
| 27 34 | 
             
            except ImportError as e:
         | 
| 28 35 | 
             
                logger.warning(f"AgentMemoryManager not available: {e}")
         | 
| @@ -32,6 +39,7 @@ except ImportError as e: | |
| 32 39 | 
             
            # Try to import socketio server with fallback handling
         | 
| 33 40 | 
             
            try:
         | 
| 34 41 | 
             
                from claude_mpm.services.socketio_server import get_socketio_server
         | 
| 42 | 
            +
             | 
| 35 43 | 
             
                SOCKETIO_AVAILABLE = True
         | 
| 36 44 | 
             
            except ImportError as e:
         | 
| 37 45 | 
             
                logger.debug(f"SocketIO server not available: {e}")
         | 
| @@ -41,24 +49,24 @@ except ImportError as e: | |
| 41 49 |  | 
| 42 50 | 
             
            class MemoryPreDelegationHook(PreDelegationHook):
         | 
| 43 51 | 
             
                """Inject agent memory into delegation context.
         | 
| 44 | 
            -
             | 
| 52 | 
            +
             | 
| 45 53 | 
             
                WHY: Agents perform better when they have access to accumulated project knowledge.
         | 
| 46 54 | 
             
                This hook loads agent-specific memory and adds it to the delegation context,
         | 
| 47 55 | 
             
                allowing agents to apply learned patterns and avoid known mistakes.
         | 
| 48 | 
            -
             | 
| 56 | 
            +
             | 
| 49 57 | 
             
                DESIGN DECISION: Memory is injected as a clearly formatted section in the context
         | 
| 50 58 | 
             
                to ensure agents understand it's their accumulated knowledge, not current task info.
         | 
| 51 59 | 
             
                """
         | 
| 52 | 
            -
             | 
| 60 | 
            +
             | 
| 53 61 | 
             
                def __init__(self, config: Config = None):
         | 
| 54 62 | 
             
                    """Initialize with optional config.
         | 
| 55 | 
            -
             | 
| 63 | 
            +
             | 
| 56 64 | 
             
                    Args:
         | 
| 57 65 | 
             
                        config: Optional Config object. If not provided, will create default Config.
         | 
| 58 66 | 
             
                    """
         | 
| 59 67 | 
             
                    super().__init__(name="memory_pre_delegation", priority=20)
         | 
| 60 68 | 
             
                    self.config = config or Config()
         | 
| 61 | 
            -
             | 
| 69 | 
            +
             | 
| 62 70 | 
             
                    # Initialize memory manager only if available
         | 
| 63 71 | 
             
                    if MEMORY_MANAGER_AVAILABLE and AgentMemoryManager:
         | 
| 64 72 | 
             
                        try:
         | 
| @@ -69,10 +77,10 @@ class MemoryPreDelegationHook(PreDelegationHook): | |
| 69 77 | 
             
                    else:
         | 
| 70 78 | 
             
                        logger.info("Memory manager not available - hook will be inactive")
         | 
| 71 79 | 
             
                        self.memory_manager = None
         | 
| 72 | 
            -
             | 
| 80 | 
            +
             | 
| 73 81 | 
             
                def execute(self, context: HookContext) -> HookResult:
         | 
| 74 82 | 
             
                    """Add agent memory to delegation context.
         | 
| 75 | 
            -
             | 
| 83 | 
            +
             | 
| 76 84 | 
             
                    WHY: By loading memory before delegation, agents can reference their
         | 
| 77 85 | 
             
                    accumulated knowledge when performing tasks, leading to better outcomes.
         | 
| 78 86 | 
             
                    """
         | 
| @@ -80,27 +88,33 @@ class MemoryPreDelegationHook(PreDelegationHook): | |
| 80 88 | 
             
                    if not self.memory_manager:
         | 
| 81 89 | 
             
                        logger.debug("Memory manager not available - skipping memory injection")
         | 
| 82 90 | 
             
                        return HookResult(success=True, data=context.data, modified=False)
         | 
| 83 | 
            -
             | 
| 91 | 
            +
             | 
| 84 92 | 
             
                    try:
         | 
| 85 93 | 
             
                        # Extract and normalize agent ID from context
         | 
| 86 | 
            -
                        agent_name = context.data.get( | 
| 94 | 
            +
                        agent_name = context.data.get("agent", "")
         | 
| 87 95 | 
             
                        if not agent_name:
         | 
| 88 96 | 
             
                            return HookResult(success=True, data=context.data, modified=False)
         | 
| 89 | 
            -
             | 
| 97 | 
            +
             | 
| 90 98 | 
             
                        # Normalize agent ID (e.g., "Engineer Agent" -> "engineer")
         | 
| 91 | 
            -
                        agent_id =  | 
| 92 | 
            -
             | 
| 99 | 
            +
                        agent_id = (
         | 
| 100 | 
            +
                            agent_name.lower()
         | 
| 101 | 
            +
                            .replace(" ", "_")
         | 
| 102 | 
            +
                            .replace("_agent", "")
         | 
| 103 | 
            +
                            .replace("agent", "")
         | 
| 104 | 
            +
                            .strip("_")
         | 
| 105 | 
            +
                        )
         | 
| 106 | 
            +
             | 
| 93 107 | 
             
                        if agent_id:
         | 
| 94 108 | 
             
                            # Load agent memory
         | 
| 95 109 | 
             
                            memory_content = self.memory_manager.load_agent_memory(agent_id)
         | 
| 96 | 
            -
             | 
| 110 | 
            +
             | 
| 97 111 | 
             
                            if memory_content and memory_content.strip():
         | 
| 98 112 | 
             
                                # Get existing context data
         | 
| 99 | 
            -
                                delegation_context = context.data.get( | 
| 113 | 
            +
                                delegation_context = context.data.get("context", {})
         | 
| 100 114 | 
             
                                if isinstance(delegation_context, str):
         | 
| 101 115 | 
             
                                    # If context is a string, convert to dict
         | 
| 102 | 
            -
                                    delegation_context = { | 
| 103 | 
            -
             | 
| 116 | 
            +
                                    delegation_context = {"prompt": delegation_context}
         | 
| 117 | 
            +
             | 
| 104 118 | 
             
                                # Add memory with clear formatting
         | 
| 105 119 | 
             
                                memory_section = f"""
         | 
| 106 120 | 
             
            AGENT MEMORY - PROJECT-SPECIFIC KNOWLEDGE:
         | 
| @@ -108,34 +122,34 @@ AGENT MEMORY - PROJECT-SPECIFIC KNOWLEDGE: | |
| 108 122 |  | 
| 109 123 | 
             
            INSTRUCTIONS: Review your memory above before proceeding. Apply learned patterns and avoid known mistakes.
         | 
| 110 124 | 
             
            """
         | 
| 111 | 
            -
             | 
| 125 | 
            +
             | 
| 112 126 | 
             
                                # Add to context
         | 
| 113 | 
            -
                                delegation_context[ | 
| 114 | 
            -
             | 
| 127 | 
            +
                                delegation_context["agent_memory"] = memory_section
         | 
| 128 | 
            +
             | 
| 115 129 | 
             
                                # Update the context data
         | 
| 116 130 | 
             
                                updated_data = context.data.copy()
         | 
| 117 | 
            -
                                updated_data[ | 
| 118 | 
            -
             | 
| 131 | 
            +
                                updated_data["context"] = delegation_context
         | 
| 132 | 
            +
             | 
| 119 133 | 
             
                                logger.info(f"Injected memory for agent '{agent_id}'")
         | 
| 120 | 
            -
             | 
| 134 | 
            +
             | 
| 121 135 | 
             
                                # Emit Socket.IO event for memory injected
         | 
| 122 136 | 
             
                                try:
         | 
| 123 137 | 
             
                                    socketio_server = get_socketio_server()
         | 
| 124 138 | 
             
                                    # Calculate size of injected content
         | 
| 125 | 
            -
                                    injected_size = len(memory_section.encode( | 
| 139 | 
            +
                                    injected_size = len(memory_section.encode("utf-8"))
         | 
| 126 140 | 
             
                                    socketio_server.memory_injected(agent_id, injected_size)
         | 
| 127 141 | 
             
                                except Exception as ws_error:
         | 
| 128 142 | 
             
                                    logger.debug(f"Socket.IO notification failed: {ws_error}")
         | 
| 129 | 
            -
             | 
| 143 | 
            +
             | 
| 130 144 | 
             
                                return HookResult(
         | 
| 131 145 | 
             
                                    success=True,
         | 
| 132 146 | 
             
                                    data=updated_data,
         | 
| 133 147 | 
             
                                    modified=True,
         | 
| 134 | 
            -
                                    metadata={ | 
| 148 | 
            +
                                    metadata={"memory_injected": True, "agent_id": agent_id},
         | 
| 135 149 | 
             
                                )
         | 
| 136 | 
            -
             | 
| 150 | 
            +
             | 
| 137 151 | 
             
                        return HookResult(success=True, data=context.data, modified=False)
         | 
| 138 | 
            -
             | 
| 152 | 
            +
             | 
| 139 153 | 
             
                    except Exception as e:
         | 
| 140 154 | 
             
                        logger.error(f"Memory injection failed: {e}")
         | 
| 141 155 | 
             
                        # Don't fail the delegation if memory injection fails
         | 
| @@ -143,73 +157,77 @@ INSTRUCTIONS: Review your memory above before proceeding. Apply learned patterns | |
| 143 157 | 
             
                            success=True,
         | 
| 144 158 | 
             
                            data=context.data,
         | 
| 145 159 | 
             
                            modified=False,
         | 
| 146 | 
            -
                            error=f"Memory injection failed: {str(e)}"
         | 
| 160 | 
            +
                            error=f"Memory injection failed: {str(e)}",
         | 
| 147 161 | 
             
                        )
         | 
| 148 162 |  | 
| 149 163 |  | 
| 150 164 | 
             
            class MemoryPostDelegationHook(PostDelegationHook):
         | 
| 151 165 | 
             
                """Extract learnings from delegation results using explicit markers.
         | 
| 152 | 
            -
             | 
| 166 | 
            +
             | 
| 153 167 | 
             
                WHY: Agents produce valuable insights during task execution. This hook
         | 
| 154 168 | 
             
                extracts structured learnings from their outputs using explicit markers,
         | 
| 155 169 | 
             
                building up project-specific knowledge over time.
         | 
| 156 | 
            -
             | 
| 170 | 
            +
             | 
| 157 171 | 
             
                DESIGN DECISION: We use explicit markers to give agents full control over
         | 
| 158 172 | 
             
                what gets memorized. This is more reliable than pattern matching and allows
         | 
| 159 173 | 
             
                multiple learnings per response. Supports multiple trigger phrases for flexibility.
         | 
| 160 | 
            -
             | 
| 174 | 
            +
             | 
| 161 175 | 
             
                Supported formats:
         | 
| 162 176 | 
             
                # Add To Memory:
         | 
| 163 177 | 
             
                Type: pattern
         | 
| 164 178 | 
             
                Content: All services use dependency injection for flexibility
         | 
| 165 179 | 
             
                #
         | 
| 166 | 
            -
             | 
| 180 | 
            +
             | 
| 167 181 | 
             
                # Memorize:
         | 
| 168 182 | 
             
                Type: guideline
         | 
| 169 183 | 
             
                Content: Always validate input parameters before processing
         | 
| 170 184 | 
             
                #
         | 
| 171 | 
            -
             | 
| 185 | 
            +
             | 
| 172 186 | 
             
                # Remember:
         | 
| 173 187 | 
             
                Type: mistake
         | 
| 174 188 | 
             
                Content: Never hardcode configuration values
         | 
| 175 189 | 
             
                #
         | 
| 176 190 | 
             
                """
         | 
| 177 | 
            -
             | 
| 191 | 
            +
             | 
| 178 192 | 
             
                def __init__(self, config: Config = None):
         | 
| 179 193 | 
             
                    """Initialize with optional config.
         | 
| 180 | 
            -
             | 
| 194 | 
            +
             | 
| 181 195 | 
             
                    Args:
         | 
| 182 196 | 
             
                        config: Optional Config object. If not provided, will create default Config.
         | 
| 183 197 | 
             
                    """
         | 
| 184 198 | 
             
                    super().__init__(name="memory_post_delegation", priority=80)
         | 
| 185 199 | 
             
                    self.config = config or Config()
         | 
| 186 | 
            -
             | 
| 200 | 
            +
             | 
| 187 201 | 
             
                    # Initialize memory manager only if available
         | 
| 188 202 | 
             
                    if MEMORY_MANAGER_AVAILABLE and AgentMemoryManager:
         | 
| 189 203 | 
             
                        try:
         | 
| 190 204 | 
             
                            self.memory_manager = AgentMemoryManager(self.config)
         | 
| 191 205 | 
             
                        except Exception as e:
         | 
| 192 | 
            -
                            logger.error( | 
| 206 | 
            +
                            logger.error(
         | 
| 207 | 
            +
                                f"Failed to initialize AgentMemoryManager in PostDelegationHook: {e}"
         | 
| 208 | 
            +
                            )
         | 
| 193 209 | 
             
                            self.memory_manager = None
         | 
| 194 210 | 
             
                    else:
         | 
| 195 | 
            -
                        logger.info( | 
| 211 | 
            +
                        logger.info(
         | 
| 212 | 
            +
                            "Memory manager not available - post-delegation hook will be inactive"
         | 
| 213 | 
            +
                        )
         | 
| 196 214 | 
             
                        self.memory_manager = None
         | 
| 197 | 
            -
             | 
| 215 | 
            +
             | 
| 198 216 | 
             
                    # Map of supported types to memory sections
         | 
| 199 217 | 
             
                    self.type_mapping = {
         | 
| 200 | 
            -
                         | 
| 201 | 
            -
                         | 
| 202 | 
            -
                         | 
| 203 | 
            -
                         | 
| 204 | 
            -
                         | 
| 205 | 
            -
                         | 
| 206 | 
            -
                         | 
| 207 | 
            -
                         | 
| 218 | 
            +
                        "pattern": "pattern",  # Coding Patterns Learned
         | 
| 219 | 
            +
                        "architecture": "architecture",  # Project Architecture
         | 
| 220 | 
            +
                        "guideline": "guideline",  # Implementation Guidelines
         | 
| 221 | 
            +
                        "mistake": "mistake",  # Common Mistakes to Avoid
         | 
| 222 | 
            +
                        "strategy": "strategy",  # Effective Strategies
         | 
| 223 | 
            +
                        "integration": "integration",  # Integration Points
         | 
| 224 | 
            +
                        "performance": "performance",  # Performance Considerations
         | 
| 225 | 
            +
                        "context": "context",  # Current Technical Context
         | 
| 208 226 | 
             
                    }
         | 
| 209 | 
            -
             | 
| 227 | 
            +
             | 
| 210 228 | 
             
                def execute(self, context: HookContext) -> HookResult:
         | 
| 211 229 | 
             
                    """Extract and store learnings from delegation result.
         | 
| 212 | 
            -
             | 
| 230 | 
            +
             | 
| 213 231 | 
             
                    WHY: Capturing learnings immediately after task completion ensures we
         | 
| 214 232 | 
             
                    don't lose valuable insights that agents discover during execution.
         | 
| 215 233 | 
             
                    """
         | 
| @@ -217,62 +235,74 @@ class MemoryPostDelegationHook(PostDelegationHook): | |
| 217 235 | 
             
                    if not self.memory_manager:
         | 
| 218 236 | 
             
                        logger.debug("Memory manager not available - skipping learning extraction")
         | 
| 219 237 | 
             
                        return HookResult(success=True, data=context.data, modified=False)
         | 
| 220 | 
            -
             | 
| 238 | 
            +
             | 
| 221 239 | 
             
                    try:
         | 
| 222 240 | 
             
                        # Check if auto-learning is enabled
         | 
| 223 | 
            -
                        if not self.config.get( | 
| 241 | 
            +
                        if not self.config.get(
         | 
| 242 | 
            +
                            "memory.auto_learning", True
         | 
| 243 | 
            +
                        ):  # Changed default to True
         | 
| 224 244 | 
             
                            return HookResult(success=True, data=context.data, modified=False)
         | 
| 225 | 
            -
             | 
| 245 | 
            +
             | 
| 226 246 | 
             
                        # Extract agent ID
         | 
| 227 | 
            -
                        agent_name = context.data.get( | 
| 247 | 
            +
                        agent_name = context.data.get("agent", "")
         | 
| 228 248 | 
             
                        if not agent_name:
         | 
| 229 249 | 
             
                            return HookResult(success=True, data=context.data, modified=False)
         | 
| 230 | 
            -
             | 
| 250 | 
            +
             | 
| 231 251 | 
             
                        # Normalize agent ID
         | 
| 232 | 
            -
                        agent_id =  | 
| 233 | 
            -
             | 
| 252 | 
            +
                        agent_id = (
         | 
| 253 | 
            +
                            agent_name.lower()
         | 
| 254 | 
            +
                            .replace(" ", "_")
         | 
| 255 | 
            +
                            .replace("_agent", "")
         | 
| 256 | 
            +
                            .replace("agent", "")
         | 
| 257 | 
            +
                            .strip("_")
         | 
| 258 | 
            +
                        )
         | 
| 259 | 
            +
             | 
| 234 260 | 
             
                        # Check if auto-learning is enabled for this specific agent
         | 
| 235 | 
            -
                        agent_overrides = self.config.get( | 
| 261 | 
            +
                        agent_overrides = self.config.get("memory.agent_overrides", {})
         | 
| 236 262 | 
             
                        agent_config = agent_overrides.get(agent_id, {})
         | 
| 237 | 
            -
                        if  | 
| 263 | 
            +
                        if "auto_learning" in agent_config and not agent_config["auto_learning"]:
         | 
| 238 264 | 
             
                            return HookResult(success=True, data=context.data, modified=False)
         | 
| 239 | 
            -
             | 
| 265 | 
            +
             | 
| 240 266 | 
             
                        # Extract result content
         | 
| 241 | 
            -
                        result = context.data.get( | 
| 267 | 
            +
                        result = context.data.get("result", {})
         | 
| 242 268 | 
             
                        if isinstance(result, dict):
         | 
| 243 | 
            -
                            result_text = result.get( | 
| 269 | 
            +
                            result_text = result.get("content", "") or str(result)
         | 
| 244 270 | 
             
                        else:
         | 
| 245 271 | 
             
                            result_text = str(result)
         | 
| 246 | 
            -
             | 
| 272 | 
            +
             | 
| 247 273 | 
             
                        if agent_id and result_text:
         | 
| 248 274 | 
             
                            # Extract learnings using patterns
         | 
| 249 275 | 
             
                            learnings = self._extract_learnings(result_text)
         | 
| 250 | 
            -
             | 
| 276 | 
            +
             | 
| 251 277 | 
             
                            # Store each learning
         | 
| 252 278 | 
             
                            learnings_stored = 0
         | 
| 253 279 | 
             
                            for learning_type, items in learnings.items():
         | 
| 254 280 | 
             
                                for item in items:
         | 
| 255 281 | 
             
                                    try:
         | 
| 256 | 
            -
                                        self.memory_manager.add_learning( | 
| 282 | 
            +
                                        self.memory_manager.add_learning(
         | 
| 283 | 
            +
                                            agent_id, learning_type, item
         | 
| 284 | 
            +
                                        )
         | 
| 257 285 | 
             
                                        learnings_stored += 1
         | 
| 258 286 | 
             
                                    except Exception as e:
         | 
| 259 287 | 
             
                                        logger.warning(f"Failed to store learning: {e}")
         | 
| 260 | 
            -
             | 
| 288 | 
            +
             | 
| 261 289 | 
             
                            if learnings_stored > 0:
         | 
| 262 | 
            -
                                logger.info( | 
| 263 | 
            -
             | 
| 290 | 
            +
                                logger.info(
         | 
| 291 | 
            +
                                    f"Extracted {learnings_stored} learnings for agent '{agent_id}'"
         | 
| 292 | 
            +
                                )
         | 
| 293 | 
            +
             | 
| 264 294 | 
             
                                return HookResult(
         | 
| 265 295 | 
             
                                    success=True,
         | 
| 266 296 | 
             
                                    data=context.data,
         | 
| 267 297 | 
             
                                    modified=False,
         | 
| 268 298 | 
             
                                    metadata={
         | 
| 269 | 
            -
                                         | 
| 270 | 
            -
                                         | 
| 271 | 
            -
                                    }
         | 
| 299 | 
            +
                                        "learnings_extracted": learnings_stored,
         | 
| 300 | 
            +
                                        "agent_id": agent_id,
         | 
| 301 | 
            +
                                    },
         | 
| 272 302 | 
             
                                )
         | 
| 273 | 
            -
             | 
| 303 | 
            +
             | 
| 274 304 | 
             
                        return HookResult(success=True, data=context.data, modified=False)
         | 
| 275 | 
            -
             | 
| 305 | 
            +
             | 
| 276 306 | 
             
                    except Exception as e:
         | 
| 277 307 | 
             
                        logger.error(f"Learning extraction failed: {e}")
         | 
| 278 308 | 
             
                        # Don't fail the delegation result if learning extraction fails
         | 
| @@ -280,54 +310,58 @@ class MemoryPostDelegationHook(PostDelegationHook): | |
| 280 310 | 
             
                            success=True,
         | 
| 281 311 | 
             
                            data=context.data,
         | 
| 282 312 | 
             
                            modified=False,
         | 
| 283 | 
            -
                            error=f"Learning extraction failed: {str(e)}"
         | 
| 313 | 
            +
                            error=f"Learning extraction failed: {str(e)}",
         | 
| 284 314 | 
             
                        )
         | 
| 285 | 
            -
             | 
| 315 | 
            +
             | 
| 286 316 | 
             
                def _extract_learnings(self, text: str) -> Dict[str, List[str]]:
         | 
| 287 317 | 
             
                    """Extract structured learnings from text using explicit markers.
         | 
| 288 | 
            -
             | 
| 318 | 
            +
             | 
| 289 319 | 
             
                    WHY: We limit learnings to 100 characters to keep memory entries
         | 
| 290 320 | 
             
                    concise and actionable. Longer entries tend to be less useful as
         | 
| 291 321 | 
             
                    quick reference points.
         | 
| 292 | 
            -
             | 
| 322 | 
            +
             | 
| 293 323 | 
             
                    DESIGN DECISION: Using explicit markers gives agents full control and makes
         | 
| 294 324 | 
             
                    extraction reliable. We support multiple memory additions in a single response
         | 
| 295 325 | 
             
                    and multiple trigger phrases (Add To Memory, Memorize, Remember) for flexibility.
         | 
| 296 | 
            -
             | 
| 326 | 
            +
             | 
| 297 327 | 
             
                    Args:
         | 
| 298 328 | 
             
                        text: The text to extract learnings from
         | 
| 299 | 
            -
             | 
| 329 | 
            +
             | 
| 300 330 | 
             
                    Returns:
         | 
| 301 331 | 
             
                        Dictionary mapping learning types to lists of extracted learnings
         | 
| 302 332 | 
             
                    """
         | 
| 303 333 | 
             
                    learnings = {learning_type: [] for learning_type in self.type_mapping.keys()}
         | 
| 304 334 | 
             
                    seen_learnings = set()  # Avoid duplicates
         | 
| 305 | 
            -
             | 
| 335 | 
            +
             | 
| 306 336 | 
             
                    # Pattern to find memory blocks with multiple trigger phrases
         | 
| 307 337 | 
             
                    # Matches: # Add To Memory: / # Memorize: / # Remember:\n...\n#
         | 
| 308 338 | 
             
                    # Only matches complete blocks with proper closing markers
         | 
| 309 | 
            -
                    memory_pattern = r | 
| 310 | 
            -
                    matches = re.finditer( | 
| 311 | 
            -
             | 
| 339 | 
            +
                    memory_pattern = r"#\s*(?:Add\s+To\s+Memory|Memorize|Remember):\s*\n((?:[^#](?:[^#]|#(?!\s*(?:Add\s+To\s+Memory|Memorize|Remember):))*?)?)\n\s*#\s*$"
         | 
| 340 | 
            +
                    matches = re.finditer(
         | 
| 341 | 
            +
                        memory_pattern, text, re.MULTILINE | re.DOTALL | re.IGNORECASE
         | 
| 342 | 
            +
                    )
         | 
| 343 | 
            +
             | 
| 312 344 | 
             
                    for match in matches:
         | 
| 313 345 | 
             
                        block_content = match.group(1).strip()
         | 
| 314 346 | 
             
                        logger.debug(f"Found memory block: {block_content[:50]}...")
         | 
| 315 | 
            -
             | 
| 347 | 
            +
             | 
| 316 348 | 
             
                        # Extract type and content from the block
         | 
| 317 | 
            -
                        type_match = re.search(r | 
| 318 | 
            -
                        content_match = re.search( | 
| 319 | 
            -
             | 
| 349 | 
            +
                        type_match = re.search(r"Type:\s*(\w+)", block_content, re.IGNORECASE)
         | 
| 350 | 
            +
                        content_match = re.search(
         | 
| 351 | 
            +
                            r"Content:\s*(.+)", block_content, re.IGNORECASE | re.DOTALL
         | 
| 352 | 
            +
                        )
         | 
| 353 | 
            +
             | 
| 320 354 | 
             
                        if type_match and content_match:
         | 
| 321 355 | 
             
                            learning_type = type_match.group(1).lower().strip()
         | 
| 322 356 | 
             
                            content = content_match.group(1).strip()
         | 
| 323 | 
            -
             | 
| 357 | 
            +
             | 
| 324 358 | 
             
                            # Clean up multi-line content - take first line if multiple
         | 
| 325 | 
            -
                            if  | 
| 326 | 
            -
                                content = content.split( | 
| 327 | 
            -
             | 
| 359 | 
            +
                            if "\n" in content:
         | 
| 360 | 
            +
                                content = content.split("\n")[0].strip()
         | 
| 361 | 
            +
             | 
| 328 362 | 
             
                            # Remove trailing punctuation
         | 
| 329 | 
            -
                            content = content.rstrip( | 
| 330 | 
            -
             | 
| 363 | 
            +
                            content = content.rstrip(".!?,;")
         | 
| 364 | 
            +
             | 
| 331 365 | 
             
                            # Validate type is supported
         | 
| 332 366 | 
             
                            if learning_type in self.type_mapping:
         | 
| 333 367 | 
             
                                # Check content length (between 5 and 100 characters)
         | 
| @@ -337,16 +371,22 @@ class MemoryPostDelegationHook(PostDelegationHook): | |
| 337 371 | 
             
                                    if normalized not in seen_learnings:
         | 
| 338 372 | 
             
                                        learnings[learning_type].append(content)
         | 
| 339 373 | 
             
                                        seen_learnings.add(normalized)
         | 
| 340 | 
            -
                                        logger.debug( | 
| 374 | 
            +
                                        logger.debug(
         | 
| 375 | 
            +
                                            f"Extracted learning - Type: {learning_type}, Content: {content}"
         | 
| 376 | 
            +
                                        )
         | 
| 341 377 | 
             
                                    else:
         | 
| 342 378 | 
             
                                        logger.debug(f"Skipping duplicate learning: {content}")
         | 
| 343 379 | 
             
                                else:
         | 
| 344 | 
            -
                                    logger.debug( | 
| 380 | 
            +
                                    logger.debug(
         | 
| 381 | 
            +
                                        f"Skipping learning - invalid length ({len(content)}): {content}"
         | 
| 382 | 
            +
                                    )
         | 
| 345 383 | 
             
                            else:
         | 
| 346 | 
            -
                                logger.warning( | 
| 384 | 
            +
                                logger.warning(
         | 
| 385 | 
            +
                                    f"Unsupported learning type: {learning_type}. Supported types: {list(self.type_mapping.keys())}"
         | 
| 386 | 
            +
                                )
         | 
| 347 387 | 
             
                        else:
         | 
| 348 388 | 
             
                            logger.debug(f"Invalid memory block format - missing Type or Content")
         | 
| 349 | 
            -
             | 
| 389 | 
            +
             | 
| 350 390 | 
             
                    # Log summary of extracted learnings
         | 
| 351 391 | 
             
                    total_learnings = sum(len(items) for items in learnings.values())
         | 
| 352 392 | 
             
                    if total_learnings > 0:
         | 
| @@ -354,5 +394,5 @@ class MemoryPostDelegationHook(PostDelegationHook): | |
| 354 394 | 
             
                        for learning_type, items in learnings.items():
         | 
| 355 395 | 
             
                            if items:
         | 
| 356 396 | 
             
                                logger.debug(f"  {learning_type}: {len(items)} items")
         | 
| 357 | 
            -
             | 
| 358 | 
            -
                    return learnings
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                    return learnings
         |