attune-ai 2.0.0__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.
- attune/__init__.py +358 -0
- attune/adaptive/__init__.py +13 -0
- attune/adaptive/task_complexity.py +127 -0
- attune/agent_monitoring.py +414 -0
- attune/cache/__init__.py +117 -0
- attune/cache/base.py +166 -0
- attune/cache/dependency_manager.py +256 -0
- attune/cache/hash_only.py +251 -0
- attune/cache/hybrid.py +457 -0
- attune/cache/storage.py +285 -0
- attune/cache_monitor.py +356 -0
- attune/cache_stats.py +298 -0
- attune/cli/__init__.py +152 -0
- attune/cli/__main__.py +12 -0
- attune/cli/commands/__init__.py +1 -0
- attune/cli/commands/batch.py +264 -0
- attune/cli/commands/cache.py +248 -0
- attune/cli/commands/help.py +331 -0
- attune/cli/commands/info.py +140 -0
- attune/cli/commands/inspect.py +436 -0
- attune/cli/commands/inspection.py +57 -0
- attune/cli/commands/memory.py +48 -0
- attune/cli/commands/metrics.py +92 -0
- attune/cli/commands/orchestrate.py +184 -0
- attune/cli/commands/patterns.py +207 -0
- attune/cli/commands/profiling.py +202 -0
- attune/cli/commands/provider.py +98 -0
- attune/cli/commands/routing.py +285 -0
- attune/cli/commands/setup.py +96 -0
- attune/cli/commands/status.py +235 -0
- attune/cli/commands/sync.py +166 -0
- attune/cli/commands/tier.py +121 -0
- attune/cli/commands/utilities.py +114 -0
- attune/cli/commands/workflow.py +579 -0
- attune/cli/core.py +32 -0
- attune/cli/parsers/__init__.py +68 -0
- attune/cli/parsers/batch.py +118 -0
- attune/cli/parsers/cache.py +65 -0
- attune/cli/parsers/help.py +41 -0
- attune/cli/parsers/info.py +26 -0
- attune/cli/parsers/inspect.py +66 -0
- attune/cli/parsers/metrics.py +42 -0
- attune/cli/parsers/orchestrate.py +61 -0
- attune/cli/parsers/patterns.py +54 -0
- attune/cli/parsers/provider.py +40 -0
- attune/cli/parsers/routing.py +110 -0
- attune/cli/parsers/setup.py +42 -0
- attune/cli/parsers/status.py +47 -0
- attune/cli/parsers/sync.py +31 -0
- attune/cli/parsers/tier.py +33 -0
- attune/cli/parsers/workflow.py +77 -0
- attune/cli/utils/__init__.py +1 -0
- attune/cli/utils/data.py +242 -0
- attune/cli/utils/helpers.py +68 -0
- attune/cli_legacy.py +3957 -0
- attune/cli_minimal.py +1159 -0
- attune/cli_router.py +437 -0
- attune/cli_unified.py +814 -0
- attune/config/__init__.py +66 -0
- attune/config/xml_config.py +286 -0
- attune/config.py +545 -0
- attune/coordination.py +870 -0
- attune/core.py +1511 -0
- attune/core_modules/__init__.py +15 -0
- attune/cost_tracker.py +626 -0
- attune/dashboard/__init__.py +41 -0
- attune/dashboard/app.py +512 -0
- attune/dashboard/simple_server.py +435 -0
- attune/dashboard/standalone_server.py +547 -0
- attune/discovery.py +306 -0
- attune/emergence.py +306 -0
- attune/exceptions.py +123 -0
- attune/feedback_loops.py +373 -0
- attune/hot_reload/README.md +473 -0
- attune/hot_reload/__init__.py +62 -0
- attune/hot_reload/config.py +83 -0
- attune/hot_reload/integration.py +229 -0
- attune/hot_reload/reloader.py +298 -0
- attune/hot_reload/watcher.py +183 -0
- attune/hot_reload/websocket.py +177 -0
- attune/levels.py +577 -0
- attune/leverage_points.py +441 -0
- attune/logging_config.py +261 -0
- attune/mcp/__init__.py +10 -0
- attune/mcp/server.py +506 -0
- attune/memory/__init__.py +237 -0
- attune/memory/claude_memory.py +469 -0
- attune/memory/config.py +224 -0
- attune/memory/control_panel.py +1290 -0
- attune/memory/control_panel_support.py +145 -0
- attune/memory/cross_session.py +845 -0
- attune/memory/edges.py +179 -0
- attune/memory/encryption.py +159 -0
- attune/memory/file_session.py +770 -0
- attune/memory/graph.py +570 -0
- attune/memory/long_term.py +913 -0
- attune/memory/long_term_types.py +99 -0
- attune/memory/mixins/__init__.py +25 -0
- attune/memory/mixins/backend_init_mixin.py +249 -0
- attune/memory/mixins/capabilities_mixin.py +208 -0
- attune/memory/mixins/handoff_mixin.py +208 -0
- attune/memory/mixins/lifecycle_mixin.py +49 -0
- attune/memory/mixins/long_term_mixin.py +352 -0
- attune/memory/mixins/promotion_mixin.py +109 -0
- attune/memory/mixins/short_term_mixin.py +182 -0
- attune/memory/nodes.py +179 -0
- attune/memory/redis_bootstrap.py +540 -0
- attune/memory/security/__init__.py +31 -0
- attune/memory/security/audit_logger.py +932 -0
- attune/memory/security/pii_scrubber.py +640 -0
- attune/memory/security/secrets_detector.py +678 -0
- attune/memory/short_term.py +2192 -0
- attune/memory/simple_storage.py +302 -0
- attune/memory/storage/__init__.py +15 -0
- attune/memory/storage_backend.py +167 -0
- attune/memory/summary_index.py +583 -0
- attune/memory/types.py +446 -0
- attune/memory/unified.py +182 -0
- attune/meta_workflows/__init__.py +74 -0
- attune/meta_workflows/agent_creator.py +248 -0
- attune/meta_workflows/builtin_templates.py +567 -0
- attune/meta_workflows/cli_commands/__init__.py +56 -0
- attune/meta_workflows/cli_commands/agent_commands.py +321 -0
- attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
- attune/meta_workflows/cli_commands/config_commands.py +232 -0
- attune/meta_workflows/cli_commands/memory_commands.py +182 -0
- attune/meta_workflows/cli_commands/template_commands.py +354 -0
- attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
- attune/meta_workflows/cli_meta_workflows.py +59 -0
- attune/meta_workflows/form_engine.py +292 -0
- attune/meta_workflows/intent_detector.py +409 -0
- attune/meta_workflows/models.py +569 -0
- attune/meta_workflows/pattern_learner.py +738 -0
- attune/meta_workflows/plan_generator.py +384 -0
- attune/meta_workflows/session_context.py +397 -0
- attune/meta_workflows/template_registry.py +229 -0
- attune/meta_workflows/workflow.py +984 -0
- attune/metrics/__init__.py +12 -0
- attune/metrics/collector.py +31 -0
- attune/metrics/prompt_metrics.py +194 -0
- attune/models/__init__.py +172 -0
- attune/models/__main__.py +13 -0
- attune/models/adaptive_routing.py +437 -0
- attune/models/auth_cli.py +444 -0
- attune/models/auth_strategy.py +450 -0
- attune/models/cli.py +655 -0
- attune/models/empathy_executor.py +354 -0
- attune/models/executor.py +257 -0
- attune/models/fallback.py +762 -0
- attune/models/provider_config.py +282 -0
- attune/models/registry.py +472 -0
- attune/models/tasks.py +359 -0
- attune/models/telemetry/__init__.py +71 -0
- attune/models/telemetry/analytics.py +594 -0
- attune/models/telemetry/backend.py +196 -0
- attune/models/telemetry/data_models.py +431 -0
- attune/models/telemetry/storage.py +489 -0
- attune/models/token_estimator.py +420 -0
- attune/models/validation.py +280 -0
- attune/monitoring/__init__.py +52 -0
- attune/monitoring/alerts.py +946 -0
- attune/monitoring/alerts_cli.py +448 -0
- attune/monitoring/multi_backend.py +271 -0
- attune/monitoring/otel_backend.py +362 -0
- attune/optimization/__init__.py +19 -0
- attune/optimization/context_optimizer.py +272 -0
- attune/orchestration/__init__.py +67 -0
- attune/orchestration/agent_templates.py +707 -0
- attune/orchestration/config_store.py +499 -0
- attune/orchestration/execution_strategies.py +2111 -0
- attune/orchestration/meta_orchestrator.py +1168 -0
- attune/orchestration/pattern_learner.py +696 -0
- attune/orchestration/real_tools.py +931 -0
- attune/pattern_cache.py +187 -0
- attune/pattern_library.py +542 -0
- attune/patterns/debugging/all_patterns.json +81 -0
- attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
- attune/patterns/refactoring_memory.json +89 -0
- attune/persistence.py +564 -0
- attune/platform_utils.py +265 -0
- attune/plugins/__init__.py +28 -0
- attune/plugins/base.py +361 -0
- attune/plugins/registry.py +268 -0
- attune/project_index/__init__.py +32 -0
- attune/project_index/cli.py +335 -0
- attune/project_index/index.py +667 -0
- attune/project_index/models.py +504 -0
- attune/project_index/reports.py +474 -0
- attune/project_index/scanner.py +777 -0
- attune/project_index/scanner_parallel.py +291 -0
- attune/prompts/__init__.py +61 -0
- attune/prompts/config.py +77 -0
- attune/prompts/context.py +177 -0
- attune/prompts/parser.py +285 -0
- attune/prompts/registry.py +313 -0
- attune/prompts/templates.py +208 -0
- attune/redis_config.py +302 -0
- attune/redis_memory.py +799 -0
- attune/resilience/__init__.py +56 -0
- attune/resilience/circuit_breaker.py +256 -0
- attune/resilience/fallback.py +179 -0
- attune/resilience/health.py +300 -0
- attune/resilience/retry.py +209 -0
- attune/resilience/timeout.py +135 -0
- attune/routing/__init__.py +43 -0
- attune/routing/chain_executor.py +433 -0
- attune/routing/classifier.py +217 -0
- attune/routing/smart_router.py +234 -0
- attune/routing/workflow_registry.py +343 -0
- attune/scaffolding/README.md +589 -0
- attune/scaffolding/__init__.py +35 -0
- attune/scaffolding/__main__.py +14 -0
- attune/scaffolding/cli.py +240 -0
- attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
- attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
- attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
- attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
- attune/socratic/__init__.py +256 -0
- attune/socratic/ab_testing.py +958 -0
- attune/socratic/blueprint.py +533 -0
- attune/socratic/cli.py +703 -0
- attune/socratic/collaboration.py +1114 -0
- attune/socratic/domain_templates.py +924 -0
- attune/socratic/embeddings.py +738 -0
- attune/socratic/engine.py +794 -0
- attune/socratic/explainer.py +682 -0
- attune/socratic/feedback.py +772 -0
- attune/socratic/forms.py +629 -0
- attune/socratic/generator.py +732 -0
- attune/socratic/llm_analyzer.py +637 -0
- attune/socratic/mcp_server.py +702 -0
- attune/socratic/session.py +312 -0
- attune/socratic/storage.py +667 -0
- attune/socratic/success.py +730 -0
- attune/socratic/visual_editor.py +860 -0
- attune/socratic/web_ui.py +958 -0
- attune/telemetry/__init__.py +39 -0
- attune/telemetry/agent_coordination.py +475 -0
- attune/telemetry/agent_tracking.py +367 -0
- attune/telemetry/approval_gates.py +545 -0
- attune/telemetry/cli.py +1231 -0
- attune/telemetry/commands/__init__.py +14 -0
- attune/telemetry/commands/dashboard_commands.py +696 -0
- attune/telemetry/event_streaming.py +409 -0
- attune/telemetry/feedback_loop.py +567 -0
- attune/telemetry/usage_tracker.py +591 -0
- attune/templates.py +754 -0
- attune/test_generator/__init__.py +38 -0
- attune/test_generator/__main__.py +14 -0
- attune/test_generator/cli.py +234 -0
- attune/test_generator/generator.py +355 -0
- attune/test_generator/risk_analyzer.py +216 -0
- attune/test_generator/templates/unit_test.py.jinja2 +272 -0
- attune/tier_recommender.py +384 -0
- attune/tools.py +183 -0
- attune/trust/__init__.py +28 -0
- attune/trust/circuit_breaker.py +579 -0
- attune/trust_building.py +527 -0
- attune/validation/__init__.py +19 -0
- attune/validation/xml_validator.py +281 -0
- attune/vscode_bridge.py +173 -0
- attune/workflow_commands.py +780 -0
- attune/workflow_patterns/__init__.py +33 -0
- attune/workflow_patterns/behavior.py +249 -0
- attune/workflow_patterns/core.py +76 -0
- attune/workflow_patterns/output.py +99 -0
- attune/workflow_patterns/registry.py +255 -0
- attune/workflow_patterns/structural.py +288 -0
- attune/workflows/__init__.py +539 -0
- attune/workflows/autonomous_test_gen.py +1268 -0
- attune/workflows/base.py +2667 -0
- attune/workflows/batch_processing.py +342 -0
- attune/workflows/bug_predict.py +1084 -0
- attune/workflows/builder.py +273 -0
- attune/workflows/caching.py +253 -0
- attune/workflows/code_review.py +1048 -0
- attune/workflows/code_review_adapters.py +312 -0
- attune/workflows/code_review_pipeline.py +722 -0
- attune/workflows/config.py +645 -0
- attune/workflows/dependency_check.py +644 -0
- attune/workflows/document_gen/__init__.py +25 -0
- attune/workflows/document_gen/config.py +30 -0
- attune/workflows/document_gen/report_formatter.py +162 -0
- attune/workflows/document_gen/workflow.py +1426 -0
- attune/workflows/document_manager.py +216 -0
- attune/workflows/document_manager_README.md +134 -0
- attune/workflows/documentation_orchestrator.py +1205 -0
- attune/workflows/history.py +510 -0
- attune/workflows/keyboard_shortcuts/__init__.py +39 -0
- attune/workflows/keyboard_shortcuts/generators.py +391 -0
- attune/workflows/keyboard_shortcuts/parsers.py +416 -0
- attune/workflows/keyboard_shortcuts/prompts.py +295 -0
- attune/workflows/keyboard_shortcuts/schema.py +193 -0
- attune/workflows/keyboard_shortcuts/workflow.py +509 -0
- attune/workflows/llm_base.py +363 -0
- attune/workflows/manage_docs.py +87 -0
- attune/workflows/manage_docs_README.md +134 -0
- attune/workflows/manage_documentation.py +821 -0
- attune/workflows/new_sample_workflow1.py +149 -0
- attune/workflows/new_sample_workflow1_README.md +150 -0
- attune/workflows/orchestrated_health_check.py +849 -0
- attune/workflows/orchestrated_release_prep.py +600 -0
- attune/workflows/output.py +413 -0
- attune/workflows/perf_audit.py +863 -0
- attune/workflows/pr_review.py +762 -0
- attune/workflows/progress.py +785 -0
- attune/workflows/progress_server.py +322 -0
- attune/workflows/progressive/README 2.md +454 -0
- attune/workflows/progressive/README.md +454 -0
- attune/workflows/progressive/__init__.py +82 -0
- attune/workflows/progressive/cli.py +219 -0
- attune/workflows/progressive/core.py +488 -0
- attune/workflows/progressive/orchestrator.py +723 -0
- attune/workflows/progressive/reports.py +520 -0
- attune/workflows/progressive/telemetry.py +274 -0
- attune/workflows/progressive/test_gen.py +495 -0
- attune/workflows/progressive/workflow.py +589 -0
- attune/workflows/refactor_plan.py +694 -0
- attune/workflows/release_prep.py +895 -0
- attune/workflows/release_prep_crew.py +969 -0
- attune/workflows/research_synthesis.py +404 -0
- attune/workflows/routing.py +168 -0
- attune/workflows/secure_release.py +593 -0
- attune/workflows/security_adapters.py +297 -0
- attune/workflows/security_audit.py +1329 -0
- attune/workflows/security_audit_phase3.py +355 -0
- attune/workflows/seo_optimization.py +633 -0
- attune/workflows/step_config.py +234 -0
- attune/workflows/telemetry_mixin.py +269 -0
- attune/workflows/test5.py +125 -0
- attune/workflows/test5_README.md +158 -0
- attune/workflows/test_coverage_boost_crew.py +849 -0
- attune/workflows/test_gen/__init__.py +52 -0
- attune/workflows/test_gen/ast_analyzer.py +249 -0
- attune/workflows/test_gen/config.py +88 -0
- attune/workflows/test_gen/data_models.py +38 -0
- attune/workflows/test_gen/report_formatter.py +289 -0
- attune/workflows/test_gen/test_templates.py +381 -0
- attune/workflows/test_gen/workflow.py +655 -0
- attune/workflows/test_gen.py +54 -0
- attune/workflows/test_gen_behavioral.py +477 -0
- attune/workflows/test_gen_parallel.py +341 -0
- attune/workflows/test_lifecycle.py +526 -0
- attune/workflows/test_maintenance.py +627 -0
- attune/workflows/test_maintenance_cli.py +590 -0
- attune/workflows/test_maintenance_crew.py +840 -0
- attune/workflows/test_runner.py +622 -0
- attune/workflows/tier_tracking.py +531 -0
- attune/workflows/xml_enhanced_crew.py +285 -0
- attune_ai-2.0.0.dist-info/METADATA +1026 -0
- attune_ai-2.0.0.dist-info/RECORD +457 -0
- attune_ai-2.0.0.dist-info/WHEEL +5 -0
- attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
- attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
- attune_ai-2.0.0.dist-info/top_level.txt +5 -0
- attune_healthcare/__init__.py +13 -0
- attune_healthcare/monitors/__init__.py +9 -0
- attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
- attune_healthcare/monitors/monitoring/__init__.py +44 -0
- attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
- attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
- attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
- attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
- attune_llm/README.md +553 -0
- attune_llm/__init__.py +28 -0
- attune_llm/agent_factory/__init__.py +53 -0
- attune_llm/agent_factory/adapters/__init__.py +85 -0
- attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
- attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
- attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
- attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
- attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
- attune_llm/agent_factory/adapters/native.py +228 -0
- attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
- attune_llm/agent_factory/base.py +305 -0
- attune_llm/agent_factory/crews/__init__.py +67 -0
- attune_llm/agent_factory/crews/code_review.py +1113 -0
- attune_llm/agent_factory/crews/health_check.py +1262 -0
- attune_llm/agent_factory/crews/refactoring.py +1128 -0
- attune_llm/agent_factory/crews/security_audit.py +1018 -0
- attune_llm/agent_factory/decorators.py +287 -0
- attune_llm/agent_factory/factory.py +558 -0
- attune_llm/agent_factory/framework.py +193 -0
- attune_llm/agent_factory/memory_integration.py +328 -0
- attune_llm/agent_factory/resilient.py +320 -0
- attune_llm/agents_md/__init__.py +22 -0
- attune_llm/agents_md/loader.py +218 -0
- attune_llm/agents_md/parser.py +271 -0
- attune_llm/agents_md/registry.py +307 -0
- attune_llm/claude_memory.py +466 -0
- attune_llm/cli/__init__.py +8 -0
- attune_llm/cli/sync_claude.py +487 -0
- attune_llm/code_health.py +1313 -0
- attune_llm/commands/__init__.py +51 -0
- attune_llm/commands/context.py +375 -0
- attune_llm/commands/loader.py +301 -0
- attune_llm/commands/models.py +231 -0
- attune_llm/commands/parser.py +371 -0
- attune_llm/commands/registry.py +429 -0
- attune_llm/config/__init__.py +29 -0
- attune_llm/config/unified.py +291 -0
- attune_llm/context/__init__.py +22 -0
- attune_llm/context/compaction.py +455 -0
- attune_llm/context/manager.py +434 -0
- attune_llm/contextual_patterns.py +361 -0
- attune_llm/core.py +907 -0
- attune_llm/git_pattern_extractor.py +435 -0
- attune_llm/hooks/__init__.py +24 -0
- attune_llm/hooks/config.py +306 -0
- attune_llm/hooks/executor.py +289 -0
- attune_llm/hooks/registry.py +302 -0
- attune_llm/hooks/scripts/__init__.py +39 -0
- attune_llm/hooks/scripts/evaluate_session.py +201 -0
- attune_llm/hooks/scripts/first_time_init.py +285 -0
- attune_llm/hooks/scripts/pre_compact.py +207 -0
- attune_llm/hooks/scripts/session_end.py +183 -0
- attune_llm/hooks/scripts/session_start.py +163 -0
- attune_llm/hooks/scripts/suggest_compact.py +225 -0
- attune_llm/learning/__init__.py +30 -0
- attune_llm/learning/evaluator.py +438 -0
- attune_llm/learning/extractor.py +514 -0
- attune_llm/learning/storage.py +560 -0
- attune_llm/levels.py +227 -0
- attune_llm/pattern_confidence.py +414 -0
- attune_llm/pattern_resolver.py +272 -0
- attune_llm/pattern_summary.py +350 -0
- attune_llm/providers.py +967 -0
- attune_llm/routing/__init__.py +32 -0
- attune_llm/routing/model_router.py +362 -0
- attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
- attune_llm/security/PHASE2_COMPLETE.md +384 -0
- attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- attune_llm/security/QUICK_REFERENCE.md +316 -0
- attune_llm/security/README.md +262 -0
- attune_llm/security/__init__.py +62 -0
- attune_llm/security/audit_logger.py +929 -0
- attune_llm/security/audit_logger_example.py +152 -0
- attune_llm/security/pii_scrubber.py +640 -0
- attune_llm/security/secrets_detector.py +678 -0
- attune_llm/security/secrets_detector_example.py +304 -0
- attune_llm/security/secure_memdocs.py +1192 -0
- attune_llm/security/secure_memdocs_example.py +278 -0
- attune_llm/session_status.py +745 -0
- attune_llm/state.py +246 -0
- attune_llm/utils/__init__.py +5 -0
- attune_llm/utils/tokens.py +349 -0
- attune_software/SOFTWARE_PLUGIN_README.md +57 -0
- attune_software/__init__.py +13 -0
- attune_software/cli/__init__.py +120 -0
- attune_software/cli/inspect.py +362 -0
- attune_software/cli.py +574 -0
- attune_software/plugin.py +188 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Pattern promotion mixin for UnifiedMemory.
|
|
2
|
+
|
|
3
|
+
Handles promotion of patterns from short-term to long-term memory.
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
6
|
+
Licensed under Fair Source 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
import structlog
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ..long_term import Classification
|
|
15
|
+
from ..short_term import AgentCredentials, RedisShortTermMemory
|
|
16
|
+
|
|
17
|
+
logger = structlog.get_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PatternPromotionMixin:
|
|
21
|
+
"""Mixin providing pattern promotion capabilities for UnifiedMemory."""
|
|
22
|
+
|
|
23
|
+
# Type hints for attributes that will be provided by UnifiedMemory
|
|
24
|
+
_short_term: "RedisShortTermMemory | None"
|
|
25
|
+
_long_term: Any # SecureMemDocsIntegration | None
|
|
26
|
+
|
|
27
|
+
# Needs access to methods from other mixins
|
|
28
|
+
@property
|
|
29
|
+
def credentials(self) -> "AgentCredentials":
|
|
30
|
+
"""Get credentials - provided by ShortTermOperationsMixin."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def get_staged_patterns(self) -> list[dict]:
|
|
34
|
+
"""Get staged patterns - provided by ShortTermOperationsMixin."""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
def persist_pattern(
|
|
38
|
+
self,
|
|
39
|
+
content: str,
|
|
40
|
+
pattern_type: str,
|
|
41
|
+
classification: "Classification | str | None" = None,
|
|
42
|
+
auto_classify: bool = True,
|
|
43
|
+
metadata: dict[str, Any] | None = None,
|
|
44
|
+
) -> dict[str, Any] | None:
|
|
45
|
+
"""Persist pattern - provided by LongTermOperationsMixin."""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
# =========================================================================
|
|
49
|
+
# PATTERN PROMOTION (SHORT-TERM → LONG-TERM)
|
|
50
|
+
# =========================================================================
|
|
51
|
+
|
|
52
|
+
def promote_pattern(
|
|
53
|
+
self,
|
|
54
|
+
staged_pattern_id: str,
|
|
55
|
+
classification: "Classification | str | None" = None,
|
|
56
|
+
auto_classify: bool = True,
|
|
57
|
+
) -> dict[str, Any] | None:
|
|
58
|
+
"""Promote a staged pattern from short-term to long-term memory.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
staged_pattern_id: ID of staged pattern to promote
|
|
62
|
+
classification: Override classification (or auto-detect)
|
|
63
|
+
auto_classify: Auto-detect classification from content
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Long-term storage result, or None if failed
|
|
67
|
+
|
|
68
|
+
"""
|
|
69
|
+
if not self._short_term or not self._long_term:
|
|
70
|
+
logger.error("memory_backends_unavailable")
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
# Retrieve staged pattern
|
|
74
|
+
staged_patterns = self.get_staged_patterns()
|
|
75
|
+
staged = next(
|
|
76
|
+
(p for p in staged_patterns if p.get("pattern_id") == staged_pattern_id),
|
|
77
|
+
None,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if not staged:
|
|
81
|
+
logger.warning("staged_pattern_not_found", pattern_id=staged_pattern_id)
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
# Persist to long-term storage
|
|
85
|
+
# Content is stored in context dict by stage_pattern
|
|
86
|
+
context = staged.get("context", {})
|
|
87
|
+
content = context.get("content", "") or staged.get("description", "")
|
|
88
|
+
result = self.persist_pattern(
|
|
89
|
+
content=content,
|
|
90
|
+
pattern_type=staged.get("pattern_type", "general"),
|
|
91
|
+
classification=classification,
|
|
92
|
+
auto_classify=auto_classify,
|
|
93
|
+
metadata=context,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if result:
|
|
97
|
+
# Remove from staging (use promote_pattern which handles deletion)
|
|
98
|
+
try:
|
|
99
|
+
self._short_term.promote_pattern(staged_pattern_id, self.credentials)
|
|
100
|
+
except PermissionError:
|
|
101
|
+
# If we can't promote (delete from staging), just log it
|
|
102
|
+
logger.warning("could_not_remove_from_staging", pattern_id=staged_pattern_id)
|
|
103
|
+
logger.info(
|
|
104
|
+
"pattern_promoted",
|
|
105
|
+
staged_id=staged_pattern_id,
|
|
106
|
+
long_term_id=result.get("pattern_id"),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
return result
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Short-term memory operations mixin for UnifiedMemory.
|
|
2
|
+
|
|
3
|
+
Provides working memory operations (stash/retrieve) and pattern staging.
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
6
|
+
Licensed under Fair Source 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import uuid
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
import structlog
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from ..file_session import FileSessionMemory
|
|
17
|
+
from ..redis_bootstrap import RedisStatus
|
|
18
|
+
from ..short_term import (
|
|
19
|
+
AccessTier,
|
|
20
|
+
AgentCredentials,
|
|
21
|
+
RedisShortTermMemory,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
logger = structlog.get_logger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ShortTermOperationsMixin:
|
|
28
|
+
"""Mixin providing short-term memory operations for UnifiedMemory."""
|
|
29
|
+
|
|
30
|
+
# Type hints for attributes that will be provided by UnifiedMemory
|
|
31
|
+
user_id: str
|
|
32
|
+
access_tier: "AccessTier"
|
|
33
|
+
_file_session: "FileSessionMemory | None"
|
|
34
|
+
_short_term: "RedisShortTermMemory | None"
|
|
35
|
+
_redis_status: "RedisStatus | None"
|
|
36
|
+
config: Any # MemoryConfig
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def credentials(self) -> "AgentCredentials":
|
|
40
|
+
"""Get agent credentials for short-term memory operations."""
|
|
41
|
+
from ..short_term import AgentCredentials
|
|
42
|
+
|
|
43
|
+
return AgentCredentials(agent_id=self.user_id, tier=self.access_tier)
|
|
44
|
+
|
|
45
|
+
# =========================================================================
|
|
46
|
+
# SHORT-TERM MEMORY OPERATIONS (Working Memory)
|
|
47
|
+
# =========================================================================
|
|
48
|
+
|
|
49
|
+
def stash(self, key: str, value: Any, ttl_seconds: int | None = None) -> bool:
|
|
50
|
+
"""Store data in working memory with TTL.
|
|
51
|
+
|
|
52
|
+
Uses file-based session as primary storage, with optional Redis for
|
|
53
|
+
real-time features. Data is persisted to disk automatically.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
key: Storage key
|
|
57
|
+
value: Data to store (must be JSON-serializable)
|
|
58
|
+
ttl_seconds: Time-to-live in seconds (default from config)
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
True if stored successfully
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
from ..short_term import TTLStrategy
|
|
65
|
+
|
|
66
|
+
ttl = ttl_seconds or self.config.default_ttl_seconds
|
|
67
|
+
|
|
68
|
+
# Primary: File session memory (always available)
|
|
69
|
+
if self._file_session:
|
|
70
|
+
self._file_session.stash(key, value, ttl=ttl)
|
|
71
|
+
|
|
72
|
+
# Optional: Redis for real-time sync
|
|
73
|
+
if self._short_term and self._redis_status and self._redis_status.available:
|
|
74
|
+
# Map ttl_seconds to TTLStrategy
|
|
75
|
+
ttl_strategy = TTLStrategy.WORKING_RESULTS
|
|
76
|
+
if ttl_seconds is not None:
|
|
77
|
+
# COORDINATION removed in v5.0 - use SESSION for short-lived data
|
|
78
|
+
if ttl_seconds <= TTLStrategy.SESSION.value:
|
|
79
|
+
ttl_strategy = TTLStrategy.SESSION
|
|
80
|
+
elif ttl_seconds <= TTLStrategy.WORKING_RESULTS.value:
|
|
81
|
+
ttl_strategy = TTLStrategy.WORKING_RESULTS
|
|
82
|
+
elif ttl_seconds <= TTLStrategy.STAGED_PATTERNS.value:
|
|
83
|
+
ttl_strategy = TTLStrategy.STAGED_PATTERNS
|
|
84
|
+
else:
|
|
85
|
+
ttl_strategy = TTLStrategy.CONFLICT_CONTEXT
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
self._short_term.stash(key, value, self.credentials, ttl_strategy)
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.debug("redis_stash_failed", key=key, error=str(e))
|
|
91
|
+
|
|
92
|
+
# Return True if at least one backend succeeded
|
|
93
|
+
return self._file_session is not None
|
|
94
|
+
|
|
95
|
+
def retrieve(self, key: str) -> Any | None:
|
|
96
|
+
"""Retrieve data from working memory.
|
|
97
|
+
|
|
98
|
+
Checks Redis first (if available) for faster access, then falls back
|
|
99
|
+
to file-based session storage.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
key: Storage key
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Stored data or None if not found
|
|
106
|
+
|
|
107
|
+
"""
|
|
108
|
+
# Try Redis first (faster, if available)
|
|
109
|
+
if self._short_term and self._redis_status and self._redis_status.available:
|
|
110
|
+
try:
|
|
111
|
+
result = self._short_term.retrieve(key, self.credentials)
|
|
112
|
+
if result is not None:
|
|
113
|
+
return result
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.debug("redis_retrieve_failed", key=key, error=str(e))
|
|
116
|
+
|
|
117
|
+
# Fall back to file session (primary storage)
|
|
118
|
+
if self._file_session:
|
|
119
|
+
return self._file_session.retrieve(key)
|
|
120
|
+
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
# =========================================================================
|
|
124
|
+
# PATTERN STAGING
|
|
125
|
+
# =========================================================================
|
|
126
|
+
|
|
127
|
+
def stage_pattern(
|
|
128
|
+
self,
|
|
129
|
+
pattern_data: dict[str, Any],
|
|
130
|
+
pattern_type: str = "general",
|
|
131
|
+
ttl_hours: int = 24,
|
|
132
|
+
) -> str | None:
|
|
133
|
+
"""Stage a pattern for validation before long-term storage.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
pattern_data: Pattern content and metadata
|
|
137
|
+
pattern_type: Type of pattern (algorithm, protocol, etc.)
|
|
138
|
+
ttl_hours: Hours before staged pattern expires (not used in current impl)
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Staged pattern ID or None if failed
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
from ..short_term import StagedPattern
|
|
145
|
+
|
|
146
|
+
if not self._short_term:
|
|
147
|
+
logger.warning("short_term_memory_unavailable")
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
# Create a StagedPattern object from the pattern_data dict
|
|
151
|
+
pattern_id = f"staged_{uuid.uuid4().hex[:12]}"
|
|
152
|
+
staged_pattern = StagedPattern(
|
|
153
|
+
pattern_id=pattern_id,
|
|
154
|
+
agent_id=self.user_id,
|
|
155
|
+
pattern_type=pattern_type,
|
|
156
|
+
name=pattern_data.get("name", f"Pattern {pattern_id[:8]}"),
|
|
157
|
+
description=pattern_data.get("description", ""),
|
|
158
|
+
code=pattern_data.get("code"),
|
|
159
|
+
context=pattern_data.get("context", {}),
|
|
160
|
+
confidence=pattern_data.get("confidence", 0.5),
|
|
161
|
+
staged_at=datetime.now(),
|
|
162
|
+
interests=pattern_data.get("interests", []),
|
|
163
|
+
)
|
|
164
|
+
# Store content in context if provided
|
|
165
|
+
if "content" in pattern_data:
|
|
166
|
+
staged_pattern.context["content"] = pattern_data["content"]
|
|
167
|
+
|
|
168
|
+
success = self._short_term.stage_pattern(staged_pattern, self.credentials)
|
|
169
|
+
return pattern_id if success else None
|
|
170
|
+
|
|
171
|
+
def get_staged_patterns(self) -> list[dict]:
|
|
172
|
+
"""Get all staged patterns awaiting validation.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of staged patterns with metadata
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
if not self._short_term:
|
|
179
|
+
return []
|
|
180
|
+
|
|
181
|
+
staged_list = self._short_term.list_staged_patterns(self.credentials)
|
|
182
|
+
return [p.to_dict() for p in staged_list]
|
attune/memory/nodes.py
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Memory Graph Node Types
|
|
2
|
+
|
|
3
|
+
Defines node types for the cross-workflow knowledge graph.
|
|
4
|
+
Each node represents an entity discovered by a workflow.
|
|
5
|
+
|
|
6
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
7
|
+
Licensed under Fair Source 0.9
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NodeType(Enum):
|
|
17
|
+
"""Types of nodes in the memory graph."""
|
|
18
|
+
|
|
19
|
+
# Code entities
|
|
20
|
+
FILE = "file"
|
|
21
|
+
FUNCTION = "function"
|
|
22
|
+
CLASS = "class"
|
|
23
|
+
MODULE = "module"
|
|
24
|
+
|
|
25
|
+
# Issues and findings
|
|
26
|
+
BUG = "bug"
|
|
27
|
+
VULNERABILITY = "vulnerability"
|
|
28
|
+
PERFORMANCE_ISSUE = "performance_issue"
|
|
29
|
+
CODE_SMELL = "code_smell"
|
|
30
|
+
TECH_DEBT = "tech_debt"
|
|
31
|
+
|
|
32
|
+
# Solutions and patterns
|
|
33
|
+
PATTERN = "pattern"
|
|
34
|
+
FIX = "fix"
|
|
35
|
+
REFACTOR = "refactor"
|
|
36
|
+
|
|
37
|
+
# Testing
|
|
38
|
+
TEST = "test"
|
|
39
|
+
TEST_CASE = "test_case"
|
|
40
|
+
COVERAGE_GAP = "coverage_gap"
|
|
41
|
+
|
|
42
|
+
# Documentation
|
|
43
|
+
DOC = "doc"
|
|
44
|
+
API_ENDPOINT = "api_endpoint"
|
|
45
|
+
|
|
46
|
+
# Dependencies
|
|
47
|
+
DEPENDENCY = "dependency"
|
|
48
|
+
LICENSE = "license"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Node:
|
|
53
|
+
"""A node in the memory graph.
|
|
54
|
+
|
|
55
|
+
Represents any entity that workflows discover or create.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
id: str
|
|
59
|
+
type: NodeType
|
|
60
|
+
name: str
|
|
61
|
+
description: str = ""
|
|
62
|
+
|
|
63
|
+
# Where this node came from
|
|
64
|
+
source_workflow: str = ""
|
|
65
|
+
source_file: str = ""
|
|
66
|
+
source_line: int | None = None
|
|
67
|
+
|
|
68
|
+
# Classification
|
|
69
|
+
severity: str = "" # critical, high, medium, low, info
|
|
70
|
+
confidence: float = 1.0 # 0.0 - 1.0
|
|
71
|
+
|
|
72
|
+
# Metadata
|
|
73
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
74
|
+
tags: list[str] = field(default_factory=list)
|
|
75
|
+
|
|
76
|
+
# Timestamps
|
|
77
|
+
created_at: datetime = field(default_factory=datetime.now)
|
|
78
|
+
updated_at: datetime = field(default_factory=datetime.now)
|
|
79
|
+
|
|
80
|
+
# Status tracking
|
|
81
|
+
status: str = "open" # open, investigating, resolved, wontfix
|
|
82
|
+
|
|
83
|
+
def to_dict(self) -> dict[str, Any]:
|
|
84
|
+
"""Convert node to dictionary for JSON serialization."""
|
|
85
|
+
return {
|
|
86
|
+
"id": self.id,
|
|
87
|
+
"type": self.type.value,
|
|
88
|
+
"name": self.name,
|
|
89
|
+
"description": self.description,
|
|
90
|
+
"source_workflow": self.source_workflow,
|
|
91
|
+
"source_file": self.source_file,
|
|
92
|
+
"source_line": self.source_line,
|
|
93
|
+
"severity": self.severity,
|
|
94
|
+
"confidence": self.confidence,
|
|
95
|
+
"metadata": self.metadata,
|
|
96
|
+
"tags": self.tags,
|
|
97
|
+
"created_at": self.created_at.isoformat(),
|
|
98
|
+
"updated_at": self.updated_at.isoformat(),
|
|
99
|
+
"status": self.status,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@classmethod
|
|
103
|
+
def from_dict(cls, data: dict[str, Any]) -> "Node":
|
|
104
|
+
"""Create node from dictionary."""
|
|
105
|
+
return cls(
|
|
106
|
+
id=data["id"],
|
|
107
|
+
type=NodeType(data["type"]),
|
|
108
|
+
name=data["name"],
|
|
109
|
+
description=data.get("description", ""),
|
|
110
|
+
source_workflow=data.get("source_workflow", data.get("source_wizard", "")),
|
|
111
|
+
source_file=data.get("source_file", ""),
|
|
112
|
+
source_line=data.get("source_line"),
|
|
113
|
+
severity=data.get("severity", ""),
|
|
114
|
+
confidence=data.get("confidence", 1.0),
|
|
115
|
+
metadata=data.get("metadata", {}),
|
|
116
|
+
tags=data.get("tags", []),
|
|
117
|
+
created_at=(
|
|
118
|
+
datetime.fromisoformat(data["created_at"])
|
|
119
|
+
if "created_at" in data
|
|
120
|
+
else datetime.now()
|
|
121
|
+
),
|
|
122
|
+
updated_at=(
|
|
123
|
+
datetime.fromisoformat(data["updated_at"])
|
|
124
|
+
if "updated_at" in data
|
|
125
|
+
else datetime.now()
|
|
126
|
+
),
|
|
127
|
+
status=data.get("status", "open"),
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class BugNode(Node):
|
|
133
|
+
"""Specialized node for bugs."""
|
|
134
|
+
|
|
135
|
+
root_cause: str = ""
|
|
136
|
+
fix_suggestion: str = ""
|
|
137
|
+
reproduction_steps: list[str] = field(default_factory=list)
|
|
138
|
+
|
|
139
|
+
def __post_init__(self):
|
|
140
|
+
self.type = NodeType.BUG
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dataclass
|
|
144
|
+
class VulnerabilityNode(Node):
|
|
145
|
+
"""Specialized node for security vulnerabilities."""
|
|
146
|
+
|
|
147
|
+
cwe_id: str = ""
|
|
148
|
+
cvss_score: float = 0.0
|
|
149
|
+
attack_vector: str = ""
|
|
150
|
+
remediation: str = ""
|
|
151
|
+
|
|
152
|
+
def __post_init__(self):
|
|
153
|
+
self.type = NodeType.VULNERABILITY
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@dataclass
|
|
157
|
+
class PerformanceNode(Node):
|
|
158
|
+
"""Specialized node for performance issues."""
|
|
159
|
+
|
|
160
|
+
metric: str = "" # latency, memory, cpu, etc.
|
|
161
|
+
current_value: float = 0.0
|
|
162
|
+
target_value: float = 0.0
|
|
163
|
+
optimization_suggestion: str = ""
|
|
164
|
+
|
|
165
|
+
def __post_init__(self):
|
|
166
|
+
self.type = NodeType.PERFORMANCE_ISSUE
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@dataclass
|
|
170
|
+
class PatternNode(Node):
|
|
171
|
+
"""Specialized node for code patterns."""
|
|
172
|
+
|
|
173
|
+
pattern_type: str = "" # anti-pattern, best-practice, idiom
|
|
174
|
+
language: str = ""
|
|
175
|
+
example_code: str = ""
|
|
176
|
+
applies_to: list[str] = field(default_factory=list)
|
|
177
|
+
|
|
178
|
+
def __post_init__(self):
|
|
179
|
+
self.type = NodeType.PATTERN
|