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
attune/exceptions.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Custom exceptions for the Empathy Framework
|
|
2
|
+
|
|
3
|
+
Provides domain-specific exceptions for better error handling and debugging.
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
6
|
+
Licensed under Fair Source 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class EmpathyFrameworkError(Exception):
|
|
11
|
+
"""Base exception for all Empathy Framework errors
|
|
12
|
+
|
|
13
|
+
All custom exceptions in the framework inherit from this class,
|
|
14
|
+
making it easy to catch any framework-specific error.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ValidationError(EmpathyFrameworkError):
|
|
19
|
+
"""Raised when input validation fails
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
- Empty strings when non-empty required
|
|
23
|
+
- Wrong type provided
|
|
24
|
+
- Invalid value ranges
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PatternNotFoundError(EmpathyFrameworkError):
|
|
30
|
+
"""Raised when a pattern lookup fails
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
- Pattern ID doesn't exist in library
|
|
34
|
+
- No patterns match query criteria
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, pattern_id: str, message: str | None = None):
|
|
39
|
+
self.pattern_id = pattern_id
|
|
40
|
+
if message is None:
|
|
41
|
+
message = f"Pattern not found: {pattern_id}"
|
|
42
|
+
super().__init__(message)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class TrustThresholdError(EmpathyFrameworkError):
|
|
46
|
+
"""Raised when trust level is insufficient for an operation
|
|
47
|
+
|
|
48
|
+
Examples:
|
|
49
|
+
- Trust too low for proactive actions
|
|
50
|
+
- Erosion loop detected
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, current_trust: float, required_trust: float, message: str | None = None):
|
|
55
|
+
self.current_trust = current_trust
|
|
56
|
+
self.required_trust = required_trust
|
|
57
|
+
if message is None:
|
|
58
|
+
message = f"Trust level {current_trust:.2f} is below required {required_trust:.2f}"
|
|
59
|
+
super().__init__(message)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class ConfidenceThresholdError(EmpathyFrameworkError):
|
|
63
|
+
"""Raised when confidence is too low for proactive action
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
- Pattern confidence below threshold
|
|
67
|
+
- Prediction uncertainty too high
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def __init__(self, confidence: float, threshold: float, message: str | None = None):
|
|
72
|
+
self.confidence = confidence
|
|
73
|
+
self.threshold = threshold
|
|
74
|
+
if message is None:
|
|
75
|
+
message = f"Confidence {confidence:.2f} is below threshold {threshold:.2f}"
|
|
76
|
+
super().__init__(message)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class EmpathyLevelError(EmpathyFrameworkError):
|
|
80
|
+
"""Raised when empathy level operations fail
|
|
81
|
+
|
|
82
|
+
Examples:
|
|
83
|
+
- Invalid level number
|
|
84
|
+
- Level not yet achieved
|
|
85
|
+
- Cannot regress to lower level
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, level: int, message: str | None = None):
|
|
90
|
+
self.level = level
|
|
91
|
+
if message is None:
|
|
92
|
+
message = f"Invalid empathy level: {level}"
|
|
93
|
+
super().__init__(message)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class LeveragePointError(EmpathyFrameworkError):
|
|
97
|
+
"""Raised when leverage point analysis fails
|
|
98
|
+
|
|
99
|
+
Examples:
|
|
100
|
+
- No leverage points found
|
|
101
|
+
- Intervention feasibility too low
|
|
102
|
+
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class FeedbackLoopError(EmpathyFrameworkError):
|
|
107
|
+
"""Raised when feedback loop detection or management fails
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
- Vicious cycle detected but cannot break
|
|
111
|
+
- Insufficient history for loop detection
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class CollaborationStateError(EmpathyFrameworkError):
|
|
117
|
+
"""Raised when collaboration state operations fail
|
|
118
|
+
|
|
119
|
+
Examples:
|
|
120
|
+
- Invalid state transition
|
|
121
|
+
- State corruption detected
|
|
122
|
+
|
|
123
|
+
"""
|
attune/feedback_loops.py
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""Feedback Loop Detection for AI-Human Collaboration
|
|
2
|
+
|
|
3
|
+
Detects and analyzes reinforcing and balancing feedback loops in AI-human
|
|
4
|
+
collaboration based on systems thinking (Meadows, Senge).
|
|
5
|
+
|
|
6
|
+
Feedback loops are circular causal relationships that either amplify
|
|
7
|
+
(reinforcing) or stabilize (balancing) system behaviors.
|
|
8
|
+
|
|
9
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
10
|
+
Licensed under Fair Source 0.9
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class LoopType(Enum):
|
|
20
|
+
"""Types of feedback loops"""
|
|
21
|
+
|
|
22
|
+
REINFORCING = "reinforcing" # Amplifying, can be virtuous or vicious
|
|
23
|
+
BALANCING = "balancing" # Stabilizing, seeks equilibrium
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LoopPolarity(Enum):
|
|
27
|
+
"""Polarity of reinforcing loops"""
|
|
28
|
+
|
|
29
|
+
VIRTUOUS = "virtuous" # Positive reinforcing loop (good spiral)
|
|
30
|
+
VICIOUS = "vicious" # Negative reinforcing loop (bad spiral)
|
|
31
|
+
NEUTRAL = "neutral" # Balancing loops
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class FeedbackLoop:
|
|
36
|
+
"""A detected feedback loop in the system
|
|
37
|
+
|
|
38
|
+
Feedback loops are circular causal chains where:
|
|
39
|
+
A -> B -> C -> A (with delays and polarities)
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
loop_id: str
|
|
43
|
+
loop_type: LoopType
|
|
44
|
+
polarity: LoopPolarity
|
|
45
|
+
description: str
|
|
46
|
+
components: list[str] # Variables involved in the loop
|
|
47
|
+
strength: float = 0.5 # 0.0-1.0, how strong is the loop effect
|
|
48
|
+
detected_at: datetime = field(default_factory=datetime.now)
|
|
49
|
+
evidence: list[dict[str, Any]] = field(default_factory=list)
|
|
50
|
+
intervention_points: list[str] = field(default_factory=list)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class FeedbackLoopDetector:
|
|
54
|
+
"""Detects reinforcing and balancing feedback loops in AI-human collaboration
|
|
55
|
+
|
|
56
|
+
Based on systems thinking (Meadows, Senge):
|
|
57
|
+
|
|
58
|
+
**Common Loops:**
|
|
59
|
+
- R1: Trust building loop (virtuous reinforcing)
|
|
60
|
+
- Success → Trust ↑ → Willingness to delegate ↑ → More success
|
|
61
|
+
- R2: Trust erosion loop (vicious reinforcing)
|
|
62
|
+
- Failure → Trust ↓ → Micromanagement ↑ → More failures
|
|
63
|
+
- B1: Quality control loop (balancing)
|
|
64
|
+
- Error rate ↑ → Guardrails ↑ → Error rate ↓
|
|
65
|
+
|
|
66
|
+
**Reinforcing Loops (R):**
|
|
67
|
+
- Amplify change (exponential growth or decay)
|
|
68
|
+
- Can be virtuous (good spiral) or vicious (bad spiral)
|
|
69
|
+
- Examples: compound interest, viral growth, panic
|
|
70
|
+
|
|
71
|
+
**Balancing Loops (B):**
|
|
72
|
+
- Seek equilibrium
|
|
73
|
+
- Stabilize systems
|
|
74
|
+
- Examples: thermostat, supply-demand, homeostasis
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
>>> detector = FeedbackLoopDetector()
|
|
78
|
+
>>> history = [
|
|
79
|
+
... {"trust": 0.5, "success": True},
|
|
80
|
+
... {"trust": 0.6, "success": True},
|
|
81
|
+
... {"trust": 0.7, "success": True}
|
|
82
|
+
... ]
|
|
83
|
+
>>> loops = detector.detect_active_loop(history)
|
|
84
|
+
>>> print(loops["dominant_loop"])
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self):
|
|
89
|
+
"""Initialize FeedbackLoopDetector"""
|
|
90
|
+
self.detected_loops: list[FeedbackLoop] = []
|
|
91
|
+
self._initialize_standard_loops()
|
|
92
|
+
|
|
93
|
+
def _initialize_standard_loops(self):
|
|
94
|
+
"""Initialize standard loops from systems thinking literature"""
|
|
95
|
+
# R1: Trust building loop (virtuous)
|
|
96
|
+
trust_building = FeedbackLoop(
|
|
97
|
+
loop_id="R1_trust_building",
|
|
98
|
+
loop_type=LoopType.REINFORCING,
|
|
99
|
+
polarity=LoopPolarity.VIRTUOUS,
|
|
100
|
+
description="Trust building cycle: Success → Trust ↑ → Delegation ↑ → More Success",
|
|
101
|
+
components=["trust", "success_rate", "delegation_level"],
|
|
102
|
+
intervention_points=["celebrate_wins", "increase_transparency"],
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# R2: Trust erosion loop (vicious)
|
|
106
|
+
trust_erosion = FeedbackLoop(
|
|
107
|
+
loop_id="R2_trust_erosion",
|
|
108
|
+
loop_type=LoopType.REINFORCING,
|
|
109
|
+
polarity=LoopPolarity.VICIOUS,
|
|
110
|
+
description="Trust erosion: Failure → Trust ↓ → Micromanagement ↑ → More Failures",
|
|
111
|
+
components=["trust", "failure_rate", "oversight_level"],
|
|
112
|
+
intervention_points=["break_cycle", "rebuild_confidence", "adjust_scope"],
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# B1: Quality control loop (balancing)
|
|
116
|
+
quality_control = FeedbackLoop(
|
|
117
|
+
loop_id="B1_quality_control",
|
|
118
|
+
loop_type=LoopType.BALANCING,
|
|
119
|
+
polarity=LoopPolarity.NEUTRAL,
|
|
120
|
+
description="Quality control: Error Rate ↑ → Guardrails ↑ → Error Rate ↓",
|
|
121
|
+
components=["error_rate", "guardrail_strength", "intervention_frequency"],
|
|
122
|
+
intervention_points=["adjust_guardrails", "calibrate_sensitivity"],
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Add to detected loops
|
|
126
|
+
self.detected_loops.extend([trust_building, trust_erosion, quality_control])
|
|
127
|
+
|
|
128
|
+
def detect_active_loop(self, session_history: list[dict[str, Any]]) -> dict[str, Any]:
|
|
129
|
+
"""Analyze session history for active feedback loops
|
|
130
|
+
|
|
131
|
+
Examines trends in trust, success rate, and collaboration metrics
|
|
132
|
+
to determine which feedback loop is currently dominant.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
session_history: List of session state snapshots over time
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Dict with:
|
|
139
|
+
- dominant_loop: The most active loop
|
|
140
|
+
- loop_strength: How strongly the loop is operating (0-1)
|
|
141
|
+
- trend: "amplifying" or "stabilizing"
|
|
142
|
+
- recommendation: Suggested intervention
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
>>> history = [
|
|
146
|
+
... {"trust": 0.5, "success_rate": 0.6},
|
|
147
|
+
... {"trust": 0.6, "success_rate": 0.7},
|
|
148
|
+
... {"trust": 0.7, "success_rate": 0.8}
|
|
149
|
+
... ]
|
|
150
|
+
>>> result = detector.detect_active_loop(history)
|
|
151
|
+
|
|
152
|
+
"""
|
|
153
|
+
if len(session_history) < 2:
|
|
154
|
+
return {
|
|
155
|
+
"dominant_loop": None,
|
|
156
|
+
"loop_strength": 0.0,
|
|
157
|
+
"trend": "insufficient_data",
|
|
158
|
+
"recommendation": "Continue collaboration to gather data",
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
# Analyze trust trend - use generator to avoid intermediate list for calculations
|
|
162
|
+
trust_values = [s.get("trust", 0.5) for s in session_history]
|
|
163
|
+
trust_trend = self._calculate_trend(trust_values)
|
|
164
|
+
|
|
165
|
+
# Analyze success rate trend - extract directly without intermediate list
|
|
166
|
+
success_count = sum(1 for s in session_history if s.get("success", False))
|
|
167
|
+
success_rate = success_count / len(session_history) if session_history else 0.5
|
|
168
|
+
|
|
169
|
+
# Determine active loop
|
|
170
|
+
if trust_trend > 0.1 and success_rate > 0.6:
|
|
171
|
+
# Trust building virtuous cycle active
|
|
172
|
+
dominant_loop = self._get_loop_by_id("R1_trust_building")
|
|
173
|
+
return {
|
|
174
|
+
"dominant_loop": "R1_trust_building",
|
|
175
|
+
"loop_type": "reinforcing_virtuous",
|
|
176
|
+
"loop_strength": min(trust_trend * success_rate, 1.0),
|
|
177
|
+
"trend": "amplifying_positive",
|
|
178
|
+
"recommendation": "Maintain momentum. Consider increasing delegation.",
|
|
179
|
+
"details": dominant_loop,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if trust_trend < -0.1 and success_rate < 0.4:
|
|
183
|
+
# Trust erosion vicious cycle active
|
|
184
|
+
dominant_loop = self._get_loop_by_id("R2_trust_erosion")
|
|
185
|
+
return {
|
|
186
|
+
"dominant_loop": "R2_trust_erosion",
|
|
187
|
+
"loop_type": "reinforcing_vicious",
|
|
188
|
+
"loop_strength": min(abs(trust_trend) * (1 - success_rate), 1.0),
|
|
189
|
+
"trend": "amplifying_negative",
|
|
190
|
+
"recommendation": "INTERVENTION NEEDED: Break cycle. Reduce scope, rebuild confidence.",
|
|
191
|
+
"details": dominant_loop,
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
# Quality control balancing loop active
|
|
195
|
+
dominant_loop = self._get_loop_by_id("B1_quality_control")
|
|
196
|
+
return {
|
|
197
|
+
"dominant_loop": "B1_quality_control",
|
|
198
|
+
"loop_type": "balancing",
|
|
199
|
+
"loop_strength": 0.5,
|
|
200
|
+
"trend": "stabilizing",
|
|
201
|
+
"recommendation": "System stable. Monitor for reinforcing loop activation.",
|
|
202
|
+
"details": dominant_loop,
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
def detect_virtuous_cycle(self, history: list[dict[str, Any]]) -> bool:
|
|
206
|
+
"""Detect reinforcing positive feedback (virtuous cycle)
|
|
207
|
+
|
|
208
|
+
A virtuous cycle is present when:
|
|
209
|
+
1. Trust is increasing
|
|
210
|
+
2. Success rate is high (>60%)
|
|
211
|
+
3. Trend is accelerating (not just linear)
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
history: Session history with trust and success metrics
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
True if virtuous cycle detected, False otherwise
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
>>> history = [
|
|
221
|
+
... {"trust": 0.5, "success": True},
|
|
222
|
+
... {"trust": 0.6, "success": True},
|
|
223
|
+
... {"trust": 0.75, "success": True} # Accelerating
|
|
224
|
+
... ]
|
|
225
|
+
>>> detector.detect_virtuous_cycle(history)
|
|
226
|
+
True
|
|
227
|
+
|
|
228
|
+
"""
|
|
229
|
+
if len(history) < 3:
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
trust_values = [h.get("trust", 0.5) for h in history]
|
|
233
|
+
success_count = sum(1 for h in history if h.get("success", False))
|
|
234
|
+
|
|
235
|
+
# Check trust is increasing
|
|
236
|
+
trust_trend = self._calculate_trend(trust_values)
|
|
237
|
+
if trust_trend <= 0:
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
# Check success rate is high - calculate directly without intermediate list
|
|
241
|
+
success_rate = success_count / len(history) if history else 0.0
|
|
242
|
+
if success_rate < 0.6:
|
|
243
|
+
return False
|
|
244
|
+
|
|
245
|
+
# Check for acceleration (reinforcing behavior)
|
|
246
|
+
recent_trust_trend = self._calculate_trend(trust_values[-3:])
|
|
247
|
+
overall_trust_trend = self._calculate_trend(trust_values)
|
|
248
|
+
|
|
249
|
+
is_accelerating = recent_trust_trend > overall_trust_trend
|
|
250
|
+
|
|
251
|
+
return is_accelerating
|
|
252
|
+
|
|
253
|
+
def detect_vicious_cycle(self, history: list[dict[str, Any]]) -> bool:
|
|
254
|
+
"""Detect reinforcing negative feedback (vicious cycle)
|
|
255
|
+
|
|
256
|
+
A vicious cycle is present when:
|
|
257
|
+
1. Trust is decreasing
|
|
258
|
+
2. Failure rate is high (>40%)
|
|
259
|
+
3. Trend is accelerating downward
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
history: Session history with trust and success metrics
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
True if vicious cycle detected, False otherwise
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
>>> history = [
|
|
269
|
+
... {"trust": 0.7, "success": False},
|
|
270
|
+
... {"trust": 0.5, "success": False},
|
|
271
|
+
... {"trust": 0.3, "success": False} # Accelerating down
|
|
272
|
+
... ]
|
|
273
|
+
>>> detector.detect_vicious_cycle(history)
|
|
274
|
+
True
|
|
275
|
+
|
|
276
|
+
"""
|
|
277
|
+
if len(history) < 3:
|
|
278
|
+
return False
|
|
279
|
+
|
|
280
|
+
trust_values = [h.get("trust", 0.5) for h in history]
|
|
281
|
+
failure_count = sum(1 for h in history if not h.get("success", True))
|
|
282
|
+
|
|
283
|
+
# Check trust is decreasing
|
|
284
|
+
trust_trend = self._calculate_trend(trust_values)
|
|
285
|
+
if trust_trend >= 0:
|
|
286
|
+
return False
|
|
287
|
+
|
|
288
|
+
# Check failure rate is high - calculate directly without intermediate list
|
|
289
|
+
failure_rate = failure_count / len(history) if history else 0.0
|
|
290
|
+
if failure_rate < 0.4:
|
|
291
|
+
return False
|
|
292
|
+
|
|
293
|
+
# Check for acceleration (reinforcing behavior)
|
|
294
|
+
recent_trust_trend = self._calculate_trend(trust_values[-3:])
|
|
295
|
+
overall_trust_trend = self._calculate_trend(trust_values)
|
|
296
|
+
|
|
297
|
+
is_accelerating_down = recent_trust_trend < overall_trust_trend
|
|
298
|
+
|
|
299
|
+
return is_accelerating_down
|
|
300
|
+
|
|
301
|
+
def get_intervention_recommendations(self, loop_id: str) -> list[str]:
|
|
302
|
+
"""Get recommended interventions for a specific loop
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
loop_id: ID of the loop (e.g., "R1_trust_building")
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
List of intervention recommendations
|
|
309
|
+
|
|
310
|
+
Example:
|
|
311
|
+
>>> recommendations = detector.get_intervention_recommendations("R2_trust_erosion")
|
|
312
|
+
>>> print(recommendations)
|
|
313
|
+
['break_cycle', 'rebuild_confidence', 'adjust_scope']
|
|
314
|
+
|
|
315
|
+
"""
|
|
316
|
+
loop = self._get_loop_by_id(loop_id)
|
|
317
|
+
if loop:
|
|
318
|
+
return loop.intervention_points
|
|
319
|
+
return []
|
|
320
|
+
|
|
321
|
+
def _calculate_trend(self, values: list[float]) -> float:
|
|
322
|
+
"""Calculate trend direction and magnitude
|
|
323
|
+
|
|
324
|
+
Uses simple linear regression slope as trend indicator.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Positive value: increasing trend
|
|
328
|
+
Negative value: decreasing trend
|
|
329
|
+
Near zero: stable
|
|
330
|
+
|
|
331
|
+
"""
|
|
332
|
+
if len(values) < 2:
|
|
333
|
+
return 0.0
|
|
334
|
+
|
|
335
|
+
n = len(values)
|
|
336
|
+
# x_mean is sum(0,1,...,n-1)/n = (n-1)/2
|
|
337
|
+
x_mean = (n - 1) / 2
|
|
338
|
+
y_mean = sum(values) / n
|
|
339
|
+
|
|
340
|
+
# Use i directly instead of x[i] since x would just be range(n)
|
|
341
|
+
numerator = sum((i - x_mean) * (values[i] - y_mean) for i in range(n))
|
|
342
|
+
denominator = sum((i - x_mean) ** 2 for i in range(n))
|
|
343
|
+
|
|
344
|
+
if denominator == 0:
|
|
345
|
+
return 0.0
|
|
346
|
+
|
|
347
|
+
slope = numerator / denominator
|
|
348
|
+
return slope
|
|
349
|
+
|
|
350
|
+
def _get_loop_by_id(self, loop_id: str) -> FeedbackLoop | None:
|
|
351
|
+
"""Get a loop by its ID"""
|
|
352
|
+
for loop in self.detected_loops:
|
|
353
|
+
if loop.loop_id == loop_id:
|
|
354
|
+
return loop
|
|
355
|
+
return None
|
|
356
|
+
|
|
357
|
+
def register_custom_loop(self, loop: FeedbackLoop):
|
|
358
|
+
"""Register a custom feedback loop for detection
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
loop: FeedbackLoop instance to register
|
|
362
|
+
|
|
363
|
+
"""
|
|
364
|
+
self.detected_loops.append(loop)
|
|
365
|
+
|
|
366
|
+
def get_all_loops(self) -> list[FeedbackLoop]:
|
|
367
|
+
"""Get all registered feedback loops"""
|
|
368
|
+
return self.detected_loops
|
|
369
|
+
|
|
370
|
+
def reset(self):
|
|
371
|
+
"""Reset detector and reinitialize standard loops"""
|
|
372
|
+
self.detected_loops = []
|
|
373
|
+
self._initialize_standard_loops()
|