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_llm/levels.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Empathy Level Definitions
|
|
2
|
+
|
|
3
|
+
Defines behavior for each of the 5 empathy levels.
|
|
4
|
+
|
|
5
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
6
|
+
Licensed under Fair Source 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from enum import IntEnum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class EmpathyLevel(IntEnum):
|
|
13
|
+
"""The 5 levels of AI-human collaboration empathy.
|
|
14
|
+
|
|
15
|
+
Each level builds on previous levels.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
REACTIVE = 1 # Help after being asked
|
|
19
|
+
GUIDED = 2 # Ask clarifying questions
|
|
20
|
+
PROACTIVE = 3 # Act before being asked (patterns)
|
|
21
|
+
ANTICIPATORY = 4 # Predict future needs (trajectory)
|
|
22
|
+
SYSTEMS = 5 # Build structures that scale (cross-domain)
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def get_description(cls, level: int) -> str:
|
|
26
|
+
"""Get description of empathy level"""
|
|
27
|
+
descriptions = {
|
|
28
|
+
1: "Reactive: Help after being asked. Traditional Q&A.",
|
|
29
|
+
2: "Guided: Ask clarifying questions. Collaborative exploration.",
|
|
30
|
+
3: "Proactive: Act before being asked. Pattern detection.",
|
|
31
|
+
4: "Anticipatory: Predict future needs. Trajectory analysis.",
|
|
32
|
+
5: "Systems: Build structures that scale. Cross-domain learning.",
|
|
33
|
+
}
|
|
34
|
+
return descriptions.get(level, "Unknown level")
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def get_system_prompt(cls, level: int) -> str:
|
|
38
|
+
"""Get system prompt for operating at specific level"""
|
|
39
|
+
base = """You are an AI assistant using the Empathy Framework for collaboration.
|
|
40
|
+
|
|
41
|
+
Your responses should be:
|
|
42
|
+
- Honest about experience (not predictive claims)
|
|
43
|
+
- Clear about reasoning
|
|
44
|
+
- Transparent about confidence
|
|
45
|
+
- Focused on user's actual needs
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
level_specific = {
|
|
49
|
+
1: """
|
|
50
|
+
LEVEL 1 (REACTIVE):
|
|
51
|
+
- Respond directly to user's question
|
|
52
|
+
- Be accurate and complete
|
|
53
|
+
- Don't anticipate or assume
|
|
54
|
+
""",
|
|
55
|
+
2: """
|
|
56
|
+
LEVEL 2 (GUIDED):
|
|
57
|
+
- Ask 1-2 calibrated questions before responding
|
|
58
|
+
- Understand user's actual goal
|
|
59
|
+
- Tailor response to their specific situation
|
|
60
|
+
|
|
61
|
+
Calibrated questions:
|
|
62
|
+
- "What are you hoping to accomplish?"
|
|
63
|
+
- "How does this fit into your workflow?"
|
|
64
|
+
- "What would make this most helpful?"
|
|
65
|
+
""",
|
|
66
|
+
3: """
|
|
67
|
+
LEVEL 3 (PROACTIVE):
|
|
68
|
+
- Detect patterns in user behavior
|
|
69
|
+
- Act before being asked when confident
|
|
70
|
+
- Explain your reasoning
|
|
71
|
+
- Provide escape hatch if wrong
|
|
72
|
+
|
|
73
|
+
When acting proactively:
|
|
74
|
+
1. Reference the detected pattern
|
|
75
|
+
2. Explain why you're acting
|
|
76
|
+
3. Show what you did
|
|
77
|
+
4. Ask if this was helpful
|
|
78
|
+
""",
|
|
79
|
+
4: """
|
|
80
|
+
LEVEL 4 (ANTICIPATORY):
|
|
81
|
+
- Analyze system trajectory
|
|
82
|
+
- Predict future bottlenecks BEFORE they occur
|
|
83
|
+
- Alert user with time to prevent issues
|
|
84
|
+
- Design structural relief in advance
|
|
85
|
+
|
|
86
|
+
Anticipatory format:
|
|
87
|
+
1. Current state analysis
|
|
88
|
+
2. Trajectory prediction (where headed)
|
|
89
|
+
3. Alert about future bottleneck
|
|
90
|
+
4. Prevention steps (actionable)
|
|
91
|
+
5. Reasoning (based on experience)
|
|
92
|
+
|
|
93
|
+
Use phrases like:
|
|
94
|
+
- "In our experience..."
|
|
95
|
+
- "This trajectory suggests..."
|
|
96
|
+
- "Alert: Before this becomes critical..."
|
|
97
|
+
- NOT "Will happen in X days" (be honest, not predictive)
|
|
98
|
+
""",
|
|
99
|
+
5: """
|
|
100
|
+
LEVEL 5 (SYSTEMS):
|
|
101
|
+
- Identify cross-domain patterns
|
|
102
|
+
- Build reusable structures
|
|
103
|
+
- Contribute to shared knowledge
|
|
104
|
+
- Enable scaling
|
|
105
|
+
|
|
106
|
+
Pattern contribution:
|
|
107
|
+
1. Identify core principle (domain-agnostic)
|
|
108
|
+
2. Show applicability to other domains
|
|
109
|
+
3. Provide adaptation guidelines
|
|
110
|
+
""",
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return base + level_specific.get(level, "")
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def get_temperature_recommendation(cls, level: int) -> float:
|
|
117
|
+
"""Get recommended temperature for each level.
|
|
118
|
+
|
|
119
|
+
Higher levels benefit from lower temperature (more focused).
|
|
120
|
+
"""
|
|
121
|
+
temps = {
|
|
122
|
+
1: 0.7, # Reactive: Some creativity okay
|
|
123
|
+
2: 0.6, # Guided: Focused questions
|
|
124
|
+
3: 0.5, # Proactive: Pattern recognition
|
|
125
|
+
4: 0.3, # Anticipatory: Precise analysis
|
|
126
|
+
5: 0.4, # Systems: Structured abstraction
|
|
127
|
+
}
|
|
128
|
+
return temps.get(level, 0.7)
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def get_required_context(cls, level: int) -> dict[str, bool]:
|
|
132
|
+
"""Get context requirements for each level.
|
|
133
|
+
|
|
134
|
+
Returns dict of {context_type: required}
|
|
135
|
+
"""
|
|
136
|
+
requirements = {
|
|
137
|
+
1: {
|
|
138
|
+
"conversation_history": False,
|
|
139
|
+
"user_patterns": False,
|
|
140
|
+
"trajectory_data": False,
|
|
141
|
+
"pattern_library": False,
|
|
142
|
+
},
|
|
143
|
+
2: {
|
|
144
|
+
"conversation_history": True, # Need recent context
|
|
145
|
+
"user_patterns": False,
|
|
146
|
+
"trajectory_data": False,
|
|
147
|
+
"pattern_library": False,
|
|
148
|
+
},
|
|
149
|
+
3: {
|
|
150
|
+
"conversation_history": True,
|
|
151
|
+
"user_patterns": True, # Need detected patterns
|
|
152
|
+
"trajectory_data": False,
|
|
153
|
+
"pattern_library": False,
|
|
154
|
+
},
|
|
155
|
+
4: {
|
|
156
|
+
"conversation_history": True,
|
|
157
|
+
"user_patterns": True,
|
|
158
|
+
"trajectory_data": True, # Need historical data
|
|
159
|
+
"pattern_library": False,
|
|
160
|
+
},
|
|
161
|
+
5: {
|
|
162
|
+
"conversation_history": True,
|
|
163
|
+
"user_patterns": True,
|
|
164
|
+
"trajectory_data": True,
|
|
165
|
+
"pattern_library": True, # Need cross-domain patterns
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return requirements.get(level, requirements[1])
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def get_max_tokens_recommendation(cls, level: int) -> int:
|
|
173
|
+
"""Get recommended max_tokens for each level.
|
|
174
|
+
|
|
175
|
+
Higher levels often need longer responses.
|
|
176
|
+
"""
|
|
177
|
+
return {
|
|
178
|
+
1: 1024, # Reactive: Concise answers
|
|
179
|
+
2: 1536, # Guided: Questions + answer
|
|
180
|
+
3: 2048, # Proactive: Explanation + action
|
|
181
|
+
4: 4096, # Anticipatory: Full analysis
|
|
182
|
+
5: 4096, # Systems: Pattern abstraction
|
|
183
|
+
}.get(level, 1024)
|
|
184
|
+
|
|
185
|
+
@classmethod
|
|
186
|
+
def should_use_json_mode(cls, level: int) -> bool:
|
|
187
|
+
"""Determine if JSON mode is beneficial for level.
|
|
188
|
+
|
|
189
|
+
Levels 4-5 benefit from structured output.
|
|
190
|
+
"""
|
|
191
|
+
return level >= 4
|
|
192
|
+
|
|
193
|
+
@classmethod
|
|
194
|
+
def get_typical_use_cases(cls, level: int) -> list[str]:
|
|
195
|
+
"""Get typical use cases for each level"""
|
|
196
|
+
return {
|
|
197
|
+
1: [
|
|
198
|
+
"One-off questions",
|
|
199
|
+
"Simple information lookup",
|
|
200
|
+
"No context needed",
|
|
201
|
+
"Compliance scenarios",
|
|
202
|
+
],
|
|
203
|
+
2: [
|
|
204
|
+
"Ambiguous requests",
|
|
205
|
+
"Multiple valid approaches",
|
|
206
|
+
"Learning user preferences",
|
|
207
|
+
"High-stakes decisions",
|
|
208
|
+
],
|
|
209
|
+
3: [
|
|
210
|
+
"Established workflows",
|
|
211
|
+
"Repetitive tasks",
|
|
212
|
+
"Time-sensitive operations",
|
|
213
|
+
"Pattern-rich interactions",
|
|
214
|
+
],
|
|
215
|
+
4: [
|
|
216
|
+
"Predictable future events",
|
|
217
|
+
"Growth trajectory visible",
|
|
218
|
+
"Structural issues emerging",
|
|
219
|
+
"Prevention better than cure",
|
|
220
|
+
],
|
|
221
|
+
5: [
|
|
222
|
+
"Multiple similar domains",
|
|
223
|
+
"Reusable patterns identified",
|
|
224
|
+
"Scaling requirements",
|
|
225
|
+
"Cross-pollination opportunities",
|
|
226
|
+
],
|
|
227
|
+
}.get(level, [])
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"""Pattern Confidence Scoring
|
|
2
|
+
|
|
3
|
+
Tracks how often stored fixes resolve similar issues,
|
|
4
|
+
building confidence scores over time.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from attune_llm.pattern_confidence import PatternConfidenceTracker
|
|
8
|
+
|
|
9
|
+
tracker = PatternConfidenceTracker("./patterns")
|
|
10
|
+
|
|
11
|
+
# Record when a pattern is suggested
|
|
12
|
+
tracker.record_suggestion("bug_20250915_abc123")
|
|
13
|
+
|
|
14
|
+
# Record when a pattern fix is applied
|
|
15
|
+
tracker.record_application("bug_20250915_abc123", successful=True)
|
|
16
|
+
|
|
17
|
+
# Get confidence stats
|
|
18
|
+
stats = tracker.get_pattern_stats("bug_20250915_abc123")
|
|
19
|
+
# Returns: {"times_suggested": 15, "times_applied": 12, "success_rate": 0.92}
|
|
20
|
+
|
|
21
|
+
Author: Empathy Framework Team
|
|
22
|
+
Version: 2.1.3
|
|
23
|
+
License: Fair Source 0.9
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import logging
|
|
28
|
+
from dataclasses import asdict, dataclass, field
|
|
29
|
+
from datetime import datetime
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Any
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class PatternUsageStats:
|
|
38
|
+
"""Statistics for a single pattern's usage."""
|
|
39
|
+
|
|
40
|
+
pattern_id: str
|
|
41
|
+
times_suggested: int = 0
|
|
42
|
+
times_applied: int = 0
|
|
43
|
+
times_successful: int = 0
|
|
44
|
+
times_unsuccessful: int = 0
|
|
45
|
+
last_suggested: str | None = None
|
|
46
|
+
last_applied: str | None = None
|
|
47
|
+
created_at: str = field(default_factory=lambda: datetime.now().isoformat())
|
|
48
|
+
feedback: list[dict] = field(default_factory=list)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def success_rate(self) -> float:
|
|
52
|
+
"""Calculate success rate of applied fixes."""
|
|
53
|
+
total = self.times_successful + self.times_unsuccessful
|
|
54
|
+
if total == 0:
|
|
55
|
+
return 0.0
|
|
56
|
+
return self.times_successful / total
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def application_rate(self) -> float:
|
|
60
|
+
"""Calculate how often suggestions lead to applications."""
|
|
61
|
+
if self.times_suggested == 0:
|
|
62
|
+
return 0.0
|
|
63
|
+
return self.times_applied / self.times_suggested
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def confidence_score(self) -> float:
|
|
67
|
+
"""Calculate overall confidence score (0.0 - 1.0)."""
|
|
68
|
+
# Base confidence from success rate
|
|
69
|
+
base = self.success_rate
|
|
70
|
+
|
|
71
|
+
# Boost for high application rate
|
|
72
|
+
if self.application_rate > 0.5:
|
|
73
|
+
base += 0.1
|
|
74
|
+
|
|
75
|
+
# Boost for volume
|
|
76
|
+
if self.times_applied >= 5:
|
|
77
|
+
base += 0.1
|
|
78
|
+
|
|
79
|
+
# Decay for low usage
|
|
80
|
+
if self.times_suggested < 2:
|
|
81
|
+
base *= 0.8
|
|
82
|
+
|
|
83
|
+
return min(max(base, 0.0), 1.0)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class PatternConfidenceTracker:
|
|
87
|
+
"""Tracks pattern usage and calculates confidence scores.
|
|
88
|
+
|
|
89
|
+
Stores usage data in patterns/confidence/usage_stats.json
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
def __init__(self, patterns_dir: str = "./patterns"):
|
|
93
|
+
self.patterns_dir = Path(patterns_dir)
|
|
94
|
+
self.confidence_dir = self.patterns_dir / "confidence"
|
|
95
|
+
self.stats_file = self.confidence_dir / "usage_stats.json"
|
|
96
|
+
self._stats: dict[str, PatternUsageStats] = {}
|
|
97
|
+
self._loaded = False
|
|
98
|
+
|
|
99
|
+
def _ensure_loaded(self) -> None:
|
|
100
|
+
"""Ensure stats are loaded from disk."""
|
|
101
|
+
if self._loaded:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
self.confidence_dir.mkdir(parents=True, exist_ok=True)
|
|
105
|
+
|
|
106
|
+
if self.stats_file.exists():
|
|
107
|
+
try:
|
|
108
|
+
with open(self.stats_file, encoding="utf-8") as f:
|
|
109
|
+
data = json.load(f)
|
|
110
|
+
for pattern_id, stats_dict in data.get("patterns", {}).items():
|
|
111
|
+
self._stats[pattern_id] = PatternUsageStats(
|
|
112
|
+
pattern_id=pattern_id,
|
|
113
|
+
**{k: v for k, v in stats_dict.items() if k != "pattern_id"},
|
|
114
|
+
)
|
|
115
|
+
except (json.JSONDecodeError, OSError) as e:
|
|
116
|
+
logger.warning("Failed to load usage stats: %s", e)
|
|
117
|
+
|
|
118
|
+
self._loaded = True
|
|
119
|
+
|
|
120
|
+
def _save(self) -> None:
|
|
121
|
+
"""Save stats to disk."""
|
|
122
|
+
self.confidence_dir.mkdir(parents=True, exist_ok=True)
|
|
123
|
+
|
|
124
|
+
data = {
|
|
125
|
+
"version": "1.0",
|
|
126
|
+
"updated_at": datetime.now().isoformat(),
|
|
127
|
+
"patterns": {
|
|
128
|
+
pattern_id: {
|
|
129
|
+
**asdict(stats),
|
|
130
|
+
"success_rate": stats.success_rate,
|
|
131
|
+
"application_rate": stats.application_rate,
|
|
132
|
+
"confidence_score": stats.confidence_score,
|
|
133
|
+
}
|
|
134
|
+
for pattern_id, stats in self._stats.items()
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try:
|
|
139
|
+
with open(self.stats_file, "w", encoding="utf-8") as f:
|
|
140
|
+
json.dump(data, f, indent=2, default=str)
|
|
141
|
+
except OSError as e:
|
|
142
|
+
logger.error("Failed to save usage stats: %s", e)
|
|
143
|
+
|
|
144
|
+
def _get_or_create_stats(self, pattern_id: str) -> PatternUsageStats:
|
|
145
|
+
"""Get or create stats for a pattern."""
|
|
146
|
+
self._ensure_loaded()
|
|
147
|
+
if pattern_id not in self._stats:
|
|
148
|
+
self._stats[pattern_id] = PatternUsageStats(pattern_id=pattern_id)
|
|
149
|
+
return self._stats[pattern_id]
|
|
150
|
+
|
|
151
|
+
def record_suggestion(self, pattern_id: str) -> None:
|
|
152
|
+
"""Record that a pattern was suggested to the user.
|
|
153
|
+
|
|
154
|
+
Call this when a pattern is shown as a potential fix.
|
|
155
|
+
"""
|
|
156
|
+
stats = self._get_or_create_stats(pattern_id)
|
|
157
|
+
stats.times_suggested += 1
|
|
158
|
+
stats.last_suggested = datetime.now().isoformat()
|
|
159
|
+
self._save()
|
|
160
|
+
logger.debug("Pattern %s suggested (total: %d)", pattern_id, stats.times_suggested)
|
|
161
|
+
|
|
162
|
+
def record_application(
|
|
163
|
+
self,
|
|
164
|
+
pattern_id: str,
|
|
165
|
+
successful: bool = True,
|
|
166
|
+
notes: str | None = None,
|
|
167
|
+
) -> None:
|
|
168
|
+
"""Record that a pattern fix was applied.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
pattern_id: The pattern that was applied
|
|
172
|
+
successful: Whether the fix resolved the issue
|
|
173
|
+
notes: Optional feedback notes
|
|
174
|
+
|
|
175
|
+
"""
|
|
176
|
+
stats = self._get_or_create_stats(pattern_id)
|
|
177
|
+
stats.times_applied += 1
|
|
178
|
+
stats.last_applied = datetime.now().isoformat()
|
|
179
|
+
|
|
180
|
+
if successful:
|
|
181
|
+
stats.times_successful += 1
|
|
182
|
+
else:
|
|
183
|
+
stats.times_unsuccessful += 1
|
|
184
|
+
|
|
185
|
+
if notes:
|
|
186
|
+
stats.feedback.append(
|
|
187
|
+
{
|
|
188
|
+
"date": datetime.now().isoformat(),
|
|
189
|
+
"successful": successful,
|
|
190
|
+
"notes": notes,
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
self._save()
|
|
195
|
+
logger.debug(
|
|
196
|
+
"Pattern %s applied (success=%s, rate=%.0f%%)",
|
|
197
|
+
pattern_id,
|
|
198
|
+
successful,
|
|
199
|
+
stats.success_rate * 100,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def get_pattern_stats(self, pattern_id: str) -> dict[str, Any]:
|
|
203
|
+
"""Get usage statistics for a pattern.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
Dict with usage stats and calculated scores
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
stats = self._get_or_create_stats(pattern_id)
|
|
210
|
+
return {
|
|
211
|
+
"pattern_id": pattern_id,
|
|
212
|
+
"times_suggested": stats.times_suggested,
|
|
213
|
+
"times_applied": stats.times_applied,
|
|
214
|
+
"times_successful": stats.times_successful,
|
|
215
|
+
"times_unsuccessful": stats.times_unsuccessful,
|
|
216
|
+
"success_rate": round(stats.success_rate, 2),
|
|
217
|
+
"application_rate": round(stats.application_rate, 2),
|
|
218
|
+
"confidence_score": round(stats.confidence_score, 2),
|
|
219
|
+
"last_suggested": stats.last_suggested,
|
|
220
|
+
"last_applied": stats.last_applied,
|
|
221
|
+
"feedback_count": len(stats.feedback),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
def get_all_stats(self) -> list[dict[str, Any]]:
|
|
225
|
+
"""Get stats for all tracked patterns."""
|
|
226
|
+
self._ensure_loaded()
|
|
227
|
+
return [self.get_pattern_stats(pid) for pid in self._stats]
|
|
228
|
+
|
|
229
|
+
def get_top_patterns(self, limit: int = 10) -> list[dict[str, Any]]:
|
|
230
|
+
"""Get top patterns by confidence score.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
limit: Maximum patterns to return
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
List of pattern stats, sorted by confidence
|
|
237
|
+
|
|
238
|
+
"""
|
|
239
|
+
self._ensure_loaded()
|
|
240
|
+
all_stats = self.get_all_stats()
|
|
241
|
+
sorted_stats = sorted(
|
|
242
|
+
all_stats,
|
|
243
|
+
key=lambda s: (s["confidence_score"], s["times_applied"]),
|
|
244
|
+
reverse=True,
|
|
245
|
+
)
|
|
246
|
+
return sorted_stats[:limit]
|
|
247
|
+
|
|
248
|
+
def get_stale_patterns(self, days: int = 90) -> list[dict[str, Any]]:
|
|
249
|
+
"""Get patterns that haven't been used recently.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
days: Number of days to consider stale
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
List of stale pattern stats
|
|
256
|
+
|
|
257
|
+
"""
|
|
258
|
+
self._ensure_loaded()
|
|
259
|
+
stale = []
|
|
260
|
+
cutoff = datetime.now().timestamp() - (days * 86400)
|
|
261
|
+
|
|
262
|
+
for pattern_id, stats in self._stats.items():
|
|
263
|
+
last_used = stats.last_applied or stats.last_suggested
|
|
264
|
+
if last_used:
|
|
265
|
+
try:
|
|
266
|
+
last_ts = datetime.fromisoformat(last_used).timestamp()
|
|
267
|
+
if last_ts < cutoff:
|
|
268
|
+
stale.append(self.get_pattern_stats(pattern_id))
|
|
269
|
+
except ValueError:
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
return stale
|
|
273
|
+
|
|
274
|
+
def update_pattern_summary(self) -> bool:
|
|
275
|
+
"""Update the patterns_summary.md with confidence scores.
|
|
276
|
+
|
|
277
|
+
This adds a confidence section to the generated summary.
|
|
278
|
+
"""
|
|
279
|
+
try:
|
|
280
|
+
# Get top patterns
|
|
281
|
+
top_patterns = self.get_top_patterns(5)
|
|
282
|
+
if not top_patterns:
|
|
283
|
+
return False
|
|
284
|
+
|
|
285
|
+
# Generate additional markdown
|
|
286
|
+
confidence_section = [
|
|
287
|
+
"## Pattern Confidence (Top 5)",
|
|
288
|
+
"",
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
for p in top_patterns:
|
|
292
|
+
score = p["confidence_score"]
|
|
293
|
+
icon = "🟢" if score >= 0.8 else "🟡" if score >= 0.5 else "🔴"
|
|
294
|
+
confidence_section.append(
|
|
295
|
+
f"- {icon} **{p['pattern_id']}**: {score:.0%} confidence "
|
|
296
|
+
f"({p['times_applied']} applied, {p['times_successful']} successful)",
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
confidence_section.append("")
|
|
300
|
+
|
|
301
|
+
# Read existing summary
|
|
302
|
+
summary_path = Path("./.claude/patterns_summary.md")
|
|
303
|
+
if not summary_path.exists():
|
|
304
|
+
return False
|
|
305
|
+
|
|
306
|
+
content = summary_path.read_text(encoding="utf-8")
|
|
307
|
+
|
|
308
|
+
# Insert before "How to Use" section
|
|
309
|
+
insert_point = content.find("## How to Use These Patterns")
|
|
310
|
+
if insert_point == -1:
|
|
311
|
+
content += "\n" + "\n".join(confidence_section)
|
|
312
|
+
else:
|
|
313
|
+
content = (
|
|
314
|
+
content[:insert_point]
|
|
315
|
+
+ "\n".join(confidence_section)
|
|
316
|
+
+ "\n"
|
|
317
|
+
+ content[insert_point:]
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
summary_path.write_text(content, encoding="utf-8")
|
|
321
|
+
logger.info("Updated patterns_summary.md with confidence scores")
|
|
322
|
+
return True
|
|
323
|
+
|
|
324
|
+
except Exception as e:
|
|
325
|
+
logger.error("Failed to update summary: %s", e)
|
|
326
|
+
return False
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def main():
|
|
330
|
+
"""CLI entry point for pattern confidence."""
|
|
331
|
+
import argparse
|
|
332
|
+
|
|
333
|
+
parser = argparse.ArgumentParser(description="Pattern confidence tracking")
|
|
334
|
+
parser.add_argument("--patterns-dir", default="./patterns", help="Patterns directory")
|
|
335
|
+
|
|
336
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
337
|
+
|
|
338
|
+
# List command
|
|
339
|
+
list_parser = subparsers.add_parser("list", help="List all pattern stats")
|
|
340
|
+
list_parser.add_argument("--top", type=int, default=10, help="Show top N patterns")
|
|
341
|
+
|
|
342
|
+
# Stats command
|
|
343
|
+
stats_parser = subparsers.add_parser("stats", help="Show stats for a pattern")
|
|
344
|
+
stats_parser.add_argument("pattern_id", help="Pattern ID")
|
|
345
|
+
|
|
346
|
+
# Record command
|
|
347
|
+
record_parser = subparsers.add_parser("record", help="Record pattern usage")
|
|
348
|
+
record_parser.add_argument("pattern_id", help="Pattern ID")
|
|
349
|
+
record_parser.add_argument("--suggested", action="store_true", help="Record suggestion")
|
|
350
|
+
record_parser.add_argument("--applied", action="store_true", help="Record application")
|
|
351
|
+
record_parser.add_argument("--success", action="store_true", help="Mark as successful")
|
|
352
|
+
record_parser.add_argument("--notes", help="Feedback notes")
|
|
353
|
+
|
|
354
|
+
# Stale command
|
|
355
|
+
stale_parser = subparsers.add_parser("stale", help="List stale patterns")
|
|
356
|
+
stale_parser.add_argument("--days", type=int, default=90, help="Days to consider stale")
|
|
357
|
+
|
|
358
|
+
args = parser.parse_args()
|
|
359
|
+
|
|
360
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
|
361
|
+
|
|
362
|
+
tracker = PatternConfidenceTracker(args.patterns_dir)
|
|
363
|
+
|
|
364
|
+
if args.command == "list":
|
|
365
|
+
top = tracker.get_top_patterns(args.top)
|
|
366
|
+
if not top:
|
|
367
|
+
print("No pattern usage data recorded yet.")
|
|
368
|
+
return
|
|
369
|
+
|
|
370
|
+
print(f"\nTop {len(top)} Patterns by Confidence:\n")
|
|
371
|
+
for i, p in enumerate(top, 1):
|
|
372
|
+
score = p["confidence_score"]
|
|
373
|
+
icon = "🟢" if score >= 0.8 else "🟡" if score >= 0.5 else "🔴"
|
|
374
|
+
print(f"{i}. {icon} {p['pattern_id']}")
|
|
375
|
+
print(f" Confidence: {score:.0%}")
|
|
376
|
+
print(f" Applied: {p['times_applied']} times ({p['times_successful']} successful)")
|
|
377
|
+
print(f" Suggested: {p['times_suggested']} times")
|
|
378
|
+
print()
|
|
379
|
+
|
|
380
|
+
elif args.command == "stats":
|
|
381
|
+
stats = tracker.get_pattern_stats(args.pattern_id)
|
|
382
|
+
print(f"\nStats for {args.pattern_id}:\n")
|
|
383
|
+
for key, value in stats.items():
|
|
384
|
+
print(f" {key}: {value}")
|
|
385
|
+
|
|
386
|
+
elif args.command == "record":
|
|
387
|
+
if args.suggested:
|
|
388
|
+
tracker.record_suggestion(args.pattern_id)
|
|
389
|
+
print(f"✓ Recorded suggestion for {args.pattern_id}")
|
|
390
|
+
|
|
391
|
+
if args.applied:
|
|
392
|
+
tracker.record_application(
|
|
393
|
+
args.pattern_id,
|
|
394
|
+
successful=args.success,
|
|
395
|
+
notes=args.notes,
|
|
396
|
+
)
|
|
397
|
+
print(f"✓ Recorded application for {args.pattern_id} (success={args.success})")
|
|
398
|
+
|
|
399
|
+
elif args.command == "stale":
|
|
400
|
+
stale = tracker.get_stale_patterns(args.days)
|
|
401
|
+
if not stale:
|
|
402
|
+
print(f"No patterns unused in the last {args.days} days.")
|
|
403
|
+
return
|
|
404
|
+
|
|
405
|
+
print(f"\nPatterns unused in {args.days}+ days:\n")
|
|
406
|
+
for p in stale:
|
|
407
|
+
print(f" - {p['pattern_id']} (last used: {p['last_applied'] or p['last_suggested']})")
|
|
408
|
+
|
|
409
|
+
else:
|
|
410
|
+
parser.print_help()
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
if __name__ == "__main__":
|
|
414
|
+
main()
|