tapps-agents 3.5.40__py3-none-any.whl → 3.6.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.
- tapps_agents/__init__.py +2 -2
- tapps_agents/agents/__init__.py +22 -22
- tapps_agents/agents/analyst/__init__.py +5 -5
- tapps_agents/agents/architect/__init__.py +5 -5
- tapps_agents/agents/architect/agent.py +1033 -1033
- tapps_agents/agents/architect/pattern_detector.py +75 -75
- tapps_agents/agents/cleanup/__init__.py +7 -7
- tapps_agents/agents/cleanup/agent.py +445 -445
- tapps_agents/agents/debugger/__init__.py +7 -7
- tapps_agents/agents/debugger/agent.py +310 -310
- tapps_agents/agents/debugger/error_analyzer.py +437 -437
- tapps_agents/agents/designer/__init__.py +5 -5
- tapps_agents/agents/designer/agent.py +786 -786
- tapps_agents/agents/designer/visual_designer.py +638 -638
- tapps_agents/agents/documenter/__init__.py +7 -7
- tapps_agents/agents/documenter/agent.py +531 -531
- tapps_agents/agents/documenter/doc_generator.py +472 -472
- tapps_agents/agents/documenter/doc_validator.py +393 -393
- tapps_agents/agents/documenter/framework_doc_updater.py +493 -493
- tapps_agents/agents/enhancer/__init__.py +7 -7
- tapps_agents/agents/evaluator/__init__.py +7 -7
- tapps_agents/agents/evaluator/agent.py +443 -443
- tapps_agents/agents/evaluator/priority_evaluator.py +641 -641
- tapps_agents/agents/evaluator/quality_analyzer.py +147 -147
- tapps_agents/agents/evaluator/report_generator.py +344 -344
- tapps_agents/agents/evaluator/usage_analyzer.py +192 -192
- tapps_agents/agents/evaluator/workflow_analyzer.py +189 -189
- tapps_agents/agents/implementer/__init__.py +7 -7
- tapps_agents/agents/implementer/agent.py +798 -798
- tapps_agents/agents/implementer/auto_fix.py +1119 -1119
- tapps_agents/agents/implementer/code_generator.py +73 -73
- tapps_agents/agents/improver/__init__.py +1 -1
- tapps_agents/agents/improver/agent.py +753 -753
- tapps_agents/agents/ops/__init__.py +1 -1
- tapps_agents/agents/ops/agent.py +619 -619
- tapps_agents/agents/ops/dependency_analyzer.py +600 -600
- tapps_agents/agents/orchestrator/__init__.py +5 -5
- tapps_agents/agents/orchestrator/agent.py +522 -522
- tapps_agents/agents/planner/__init__.py +7 -7
- tapps_agents/agents/planner/agent.py +1127 -1127
- tapps_agents/agents/reviewer/__init__.py +24 -24
- tapps_agents/agents/reviewer/agent.py +3513 -3513
- tapps_agents/agents/reviewer/aggregator.py +213 -213
- tapps_agents/agents/reviewer/batch_review.py +448 -448
- tapps_agents/agents/reviewer/cache.py +443 -443
- tapps_agents/agents/reviewer/context7_enhancer.py +630 -630
- tapps_agents/agents/reviewer/context_detector.py +203 -203
- tapps_agents/agents/reviewer/docker_compose_validator.py +158 -158
- tapps_agents/agents/reviewer/dockerfile_validator.py +176 -176
- tapps_agents/agents/reviewer/error_handling.py +126 -126
- tapps_agents/agents/reviewer/feedback_generator.py +490 -490
- tapps_agents/agents/reviewer/influxdb_validator.py +316 -316
- tapps_agents/agents/reviewer/issue_tracking.py +169 -169
- tapps_agents/agents/reviewer/library_detector.py +295 -295
- tapps_agents/agents/reviewer/library_patterns.py +268 -268
- tapps_agents/agents/reviewer/maintainability_scorer.py +593 -593
- tapps_agents/agents/reviewer/metric_strategies.py +276 -276
- tapps_agents/agents/reviewer/mqtt_validator.py +160 -160
- tapps_agents/agents/reviewer/output_enhancer.py +105 -105
- tapps_agents/agents/reviewer/pattern_detector.py +241 -241
- tapps_agents/agents/reviewer/performance_scorer.py +357 -357
- tapps_agents/agents/reviewer/phased_review.py +516 -516
- tapps_agents/agents/reviewer/progressive_review.py +435 -435
- tapps_agents/agents/reviewer/react_scorer.py +331 -331
- tapps_agents/agents/reviewer/score_constants.py +228 -228
- tapps_agents/agents/reviewer/score_validator.py +507 -507
- tapps_agents/agents/reviewer/scorer_registry.py +373 -373
- tapps_agents/agents/reviewer/scoring.py +1566 -1566
- tapps_agents/agents/reviewer/service_discovery.py +534 -534
- tapps_agents/agents/reviewer/tools/__init__.py +41 -41
- tapps_agents/agents/reviewer/tools/parallel_executor.py +581 -581
- tapps_agents/agents/reviewer/tools/ruff_grouping.py +250 -250
- tapps_agents/agents/reviewer/tools/scoped_mypy.py +284 -284
- tapps_agents/agents/reviewer/typescript_scorer.py +1142 -1142
- tapps_agents/agents/reviewer/validation.py +208 -208
- tapps_agents/agents/reviewer/websocket_validator.py +132 -132
- tapps_agents/agents/tester/__init__.py +7 -7
- tapps_agents/agents/tester/accessibility_auditor.py +309 -309
- tapps_agents/agents/tester/agent.py +1080 -1080
- tapps_agents/agents/tester/batch_generator.py +54 -54
- tapps_agents/agents/tester/context_learner.py +51 -51
- tapps_agents/agents/tester/coverage_analyzer.py +386 -386
- tapps_agents/agents/tester/coverage_test_generator.py +290 -290
- tapps_agents/agents/tester/debug_enhancer.py +238 -238
- tapps_agents/agents/tester/device_emulator.py +241 -241
- tapps_agents/agents/tester/integration_generator.py +62 -62
- tapps_agents/agents/tester/network_recorder.py +300 -300
- tapps_agents/agents/tester/performance_monitor.py +320 -320
- tapps_agents/agents/tester/test_fixer.py +316 -316
- tapps_agents/agents/tester/test_generator.py +632 -632
- tapps_agents/agents/tester/trace_manager.py +234 -234
- tapps_agents/agents/tester/visual_regression.py +291 -291
- tapps_agents/analysis/pattern_detector.py +36 -36
- tapps_agents/beads/hydration.py +213 -213
- tapps_agents/beads/parse.py +32 -32
- tapps_agents/beads/specs.py +206 -206
- tapps_agents/cli/__init__.py +9 -9
- tapps_agents/cli/__main__.py +8 -8
- tapps_agents/cli/base.py +478 -478
- tapps_agents/cli/command_classifier.py +72 -72
- tapps_agents/cli/commands/__init__.py +2 -2
- tapps_agents/cli/commands/analyst.py +173 -173
- tapps_agents/cli/commands/architect.py +109 -109
- tapps_agents/cli/commands/cleanup_agent.py +92 -92
- tapps_agents/cli/commands/common.py +126 -126
- tapps_agents/cli/commands/debugger.py +90 -90
- tapps_agents/cli/commands/designer.py +112 -112
- tapps_agents/cli/commands/documenter.py +136 -136
- tapps_agents/cli/commands/enhancer.py +110 -110
- tapps_agents/cli/commands/evaluator.py +255 -255
- tapps_agents/cli/commands/health.py +665 -665
- tapps_agents/cli/commands/implementer.py +301 -301
- tapps_agents/cli/commands/improver.py +91 -91
- tapps_agents/cli/commands/knowledge.py +111 -111
- tapps_agents/cli/commands/learning.py +172 -172
- tapps_agents/cli/commands/observability.py +283 -283
- tapps_agents/cli/commands/ops.py +135 -135
- tapps_agents/cli/commands/orchestrator.py +116 -116
- tapps_agents/cli/commands/planner.py +237 -237
- tapps_agents/cli/commands/reviewer.py +1872 -1872
- tapps_agents/cli/commands/status.py +285 -285
- tapps_agents/cli/commands/task.py +227 -219
- tapps_agents/cli/commands/tester.py +191 -191
- tapps_agents/cli/commands/top_level.py +3586 -3586
- tapps_agents/cli/feedback.py +936 -936
- tapps_agents/cli/formatters.py +608 -608
- tapps_agents/cli/help/__init__.py +7 -7
- tapps_agents/cli/help/static_help.py +425 -425
- tapps_agents/cli/network_detection.py +110 -110
- tapps_agents/cli/output_compactor.py +274 -274
- tapps_agents/cli/parsers/__init__.py +2 -2
- tapps_agents/cli/parsers/analyst.py +186 -186
- tapps_agents/cli/parsers/architect.py +167 -167
- tapps_agents/cli/parsers/cleanup_agent.py +228 -228
- tapps_agents/cli/parsers/debugger.py +116 -116
- tapps_agents/cli/parsers/designer.py +182 -182
- tapps_agents/cli/parsers/documenter.py +134 -134
- tapps_agents/cli/parsers/enhancer.py +113 -113
- tapps_agents/cli/parsers/evaluator.py +213 -213
- tapps_agents/cli/parsers/implementer.py +168 -168
- tapps_agents/cli/parsers/improver.py +132 -132
- tapps_agents/cli/parsers/ops.py +159 -159
- tapps_agents/cli/parsers/orchestrator.py +98 -98
- tapps_agents/cli/parsers/planner.py +145 -145
- tapps_agents/cli/parsers/reviewer.py +462 -462
- tapps_agents/cli/parsers/tester.py +124 -124
- tapps_agents/cli/progress_heartbeat.py +254 -254
- tapps_agents/cli/streaming_progress.py +336 -336
- tapps_agents/cli/utils/__init__.py +6 -6
- tapps_agents/cli/utils/agent_lifecycle.py +48 -48
- tapps_agents/cli/utils/error_formatter.py +82 -82
- tapps_agents/cli/utils/error_recovery.py +188 -188
- tapps_agents/cli/utils/output_handler.py +59 -59
- tapps_agents/cli/utils/prompt_enhancer.py +319 -319
- tapps_agents/cli/validators/__init__.py +9 -9
- tapps_agents/cli/validators/command_validator.py +81 -81
- tapps_agents/context7/__init__.py +112 -112
- tapps_agents/context7/agent_integration.py +869 -869
- tapps_agents/context7/analytics.py +382 -382
- tapps_agents/context7/analytics_dashboard.py +299 -299
- tapps_agents/context7/async_cache.py +681 -681
- tapps_agents/context7/backup_client.py +958 -958
- tapps_agents/context7/cache_locking.py +194 -194
- tapps_agents/context7/cache_metadata.py +214 -214
- tapps_agents/context7/cache_prewarm.py +488 -488
- tapps_agents/context7/cache_structure.py +168 -168
- tapps_agents/context7/cache_warming.py +604 -604
- tapps_agents/context7/circuit_breaker.py +376 -376
- tapps_agents/context7/cleanup.py +461 -461
- tapps_agents/context7/commands.py +858 -858
- tapps_agents/context7/credential_validation.py +276 -276
- tapps_agents/context7/cross_reference_resolver.py +168 -168
- tapps_agents/context7/cross_references.py +424 -424
- tapps_agents/context7/doc_manager.py +225 -225
- tapps_agents/context7/fuzzy_matcher.py +369 -369
- tapps_agents/context7/kb_cache.py +404 -404
- tapps_agents/context7/language_detector.py +219 -219
- tapps_agents/context7/library_detector.py +725 -725
- tapps_agents/context7/lookup.py +738 -738
- tapps_agents/context7/metadata.py +258 -258
- tapps_agents/context7/refresh_queue.py +300 -300
- tapps_agents/context7/security.py +373 -373
- tapps_agents/context7/staleness_policies.py +278 -278
- tapps_agents/context7/tiles_integration.py +47 -47
- tapps_agents/continuous_bug_fix/__init__.py +20 -20
- tapps_agents/continuous_bug_fix/bug_finder.py +306 -306
- tapps_agents/continuous_bug_fix/bug_fix_coordinator.py +177 -177
- tapps_agents/continuous_bug_fix/commit_manager.py +178 -178
- tapps_agents/continuous_bug_fix/continuous_bug_fixer.py +322 -322
- tapps_agents/continuous_bug_fix/proactive_bug_finder.py +285 -285
- tapps_agents/core/__init__.py +298 -298
- tapps_agents/core/adaptive_cache_config.py +432 -432
- tapps_agents/core/agent_base.py +647 -647
- tapps_agents/core/agent_cache.py +466 -466
- tapps_agents/core/agent_learning.py +1865 -1865
- tapps_agents/core/analytics_dashboard.py +563 -563
- tapps_agents/core/analytics_enhancements.py +597 -597
- tapps_agents/core/anonymization.py +274 -274
- tapps_agents/core/artifact_context_builder.py +293 -0
- tapps_agents/core/ast_parser.py +228 -228
- tapps_agents/core/async_file_ops.py +402 -402
- tapps_agents/core/best_practice_consultant.py +299 -299
- tapps_agents/core/brownfield_analyzer.py +299 -299
- tapps_agents/core/brownfield_review.py +541 -541
- tapps_agents/core/browser_controller.py +513 -513
- tapps_agents/core/capability_registry.py +418 -418
- tapps_agents/core/change_impact_analyzer.py +190 -190
- tapps_agents/core/checkpoint_manager.py +377 -377
- tapps_agents/core/code_generator.py +329 -329
- tapps_agents/core/code_validator.py +276 -276
- tapps_agents/core/command_registry.py +327 -327
- tapps_agents/core/config.py +33 -0
- tapps_agents/core/context_gathering/__init__.py +2 -2
- tapps_agents/core/context_gathering/repository_explorer.py +28 -28
- tapps_agents/core/context_intelligence/__init__.py +2 -2
- tapps_agents/core/context_intelligence/relevance_scorer.py +24 -24
- tapps_agents/core/context_intelligence/token_budget_manager.py +27 -27
- tapps_agents/core/context_manager.py +240 -240
- tapps_agents/core/cursor_feedback_monitor.py +146 -146
- tapps_agents/core/cursor_verification.py +290 -290
- tapps_agents/core/customization_loader.py +280 -280
- tapps_agents/core/customization_schema.py +260 -260
- tapps_agents/core/customization_template.py +238 -238
- tapps_agents/core/debug_logger.py +124 -124
- tapps_agents/core/design_validator.py +298 -298
- tapps_agents/core/diagram_generator.py +226 -226
- tapps_agents/core/docker_utils.py +232 -232
- tapps_agents/core/document_generator.py +617 -617
- tapps_agents/core/domain_detector.py +30 -30
- tapps_agents/core/error_envelope.py +454 -454
- tapps_agents/core/error_handler.py +270 -270
- tapps_agents/core/estimation_tracker.py +189 -189
- tapps_agents/core/eval_prompt_engine.py +116 -116
- tapps_agents/core/evaluation_base.py +119 -119
- tapps_agents/core/evaluation_models.py +320 -320
- tapps_agents/core/evaluation_orchestrator.py +225 -225
- tapps_agents/core/evaluators/__init__.py +7 -7
- tapps_agents/core/evaluators/architectural_evaluator.py +205 -205
- tapps_agents/core/evaluators/behavioral_evaluator.py +160 -160
- tapps_agents/core/evaluators/performance_profile_evaluator.py +160 -160
- tapps_agents/core/evaluators/security_posture_evaluator.py +148 -148
- tapps_agents/core/evaluators/spec_compliance_evaluator.py +181 -181
- tapps_agents/core/exceptions.py +107 -107
- tapps_agents/core/expert_config_generator.py +293 -293
- tapps_agents/core/export_schema.py +202 -202
- tapps_agents/core/external_feedback_models.py +102 -102
- tapps_agents/core/external_feedback_storage.py +213 -213
- tapps_agents/core/fallback_strategy.py +314 -314
- tapps_agents/core/feedback_analyzer.py +162 -162
- tapps_agents/core/feedback_collector.py +178 -178
- tapps_agents/core/git_operations.py +445 -445
- tapps_agents/core/hardware_profiler.py +151 -151
- tapps_agents/core/instructions.py +324 -324
- tapps_agents/core/io_guardrails.py +69 -69
- tapps_agents/core/issue_manifest.py +249 -249
- tapps_agents/core/issue_schema.py +139 -139
- tapps_agents/core/json_utils.py +128 -128
- tapps_agents/core/knowledge_graph.py +446 -446
- tapps_agents/core/language_detector.py +296 -296
- tapps_agents/core/learning_confidence.py +242 -242
- tapps_agents/core/learning_dashboard.py +246 -246
- tapps_agents/core/learning_decision.py +384 -384
- tapps_agents/core/learning_explainability.py +578 -578
- tapps_agents/core/learning_export.py +287 -287
- tapps_agents/core/learning_integration.py +228 -228
- tapps_agents/core/llm_behavior.py +232 -232
- tapps_agents/core/long_duration_support.py +786 -786
- tapps_agents/core/mcp_setup.py +106 -106
- tapps_agents/core/memory_integration.py +396 -396
- tapps_agents/core/meta_learning.py +666 -666
- tapps_agents/core/module_path_sanitizer.py +199 -199
- tapps_agents/core/multi_agent_orchestrator.py +382 -382
- tapps_agents/core/network_errors.py +125 -125
- tapps_agents/core/nfr_validator.py +336 -336
- tapps_agents/core/offline_mode.py +158 -158
- tapps_agents/core/output_contracts.py +300 -300
- tapps_agents/core/output_formatter.py +300 -300
- tapps_agents/core/path_normalizer.py +174 -174
- tapps_agents/core/path_validator.py +322 -322
- tapps_agents/core/pattern_library.py +250 -250
- tapps_agents/core/performance_benchmark.py +301 -301
- tapps_agents/core/performance_monitor.py +184 -184
- tapps_agents/core/playwright_mcp_controller.py +771 -771
- tapps_agents/core/policy_loader.py +135 -135
- tapps_agents/core/progress.py +166 -166
- tapps_agents/core/project_profile.py +354 -354
- tapps_agents/core/project_type_detector.py +454 -454
- tapps_agents/core/prompt_base.py +223 -223
- tapps_agents/core/prompt_learning/__init__.py +2 -2
- tapps_agents/core/prompt_learning/learning_loop.py +24 -24
- tapps_agents/core/prompt_learning/project_prompt_store.py +25 -25
- tapps_agents/core/prompt_learning/skills_prompt_analyzer.py +35 -35
- tapps_agents/core/prompt_optimization/__init__.py +6 -6
- tapps_agents/core/prompt_optimization/ab_tester.py +114 -114
- tapps_agents/core/prompt_optimization/correlation_analyzer.py +160 -160
- tapps_agents/core/prompt_optimization/progressive_refiner.py +129 -129
- tapps_agents/core/prompt_optimization/prompt_library.py +37 -37
- tapps_agents/core/requirements_evaluator.py +431 -431
- tapps_agents/core/resource_aware_executor.py +449 -449
- tapps_agents/core/resource_monitor.py +343 -343
- tapps_agents/core/resume_handler.py +298 -298
- tapps_agents/core/retry_handler.py +197 -197
- tapps_agents/core/review_checklists.py +479 -479
- tapps_agents/core/role_loader.py +201 -201
- tapps_agents/core/role_template_loader.py +201 -201
- tapps_agents/core/runtime_mode.py +60 -60
- tapps_agents/core/security_scanner.py +342 -342
- tapps_agents/core/skill_agent_registry.py +194 -194
- tapps_agents/core/skill_integration.py +208 -208
- tapps_agents/core/skill_loader.py +492 -492
- tapps_agents/core/skill_template.py +341 -341
- tapps_agents/core/skill_validator.py +478 -478
- tapps_agents/core/stack_analyzer.py +35 -35
- tapps_agents/core/startup.py +174 -174
- tapps_agents/core/storage_manager.py +397 -397
- tapps_agents/core/storage_models.py +166 -166
- tapps_agents/core/story_evaluator.py +410 -410
- tapps_agents/core/subprocess_utils.py +170 -170
- tapps_agents/core/task_duration.py +296 -296
- tapps_agents/core/task_memory.py +582 -582
- tapps_agents/core/task_state.py +226 -226
- tapps_agents/core/tech_stack_priorities.py +208 -208
- tapps_agents/core/temp_directory.py +194 -194
- tapps_agents/core/template_merger.py +600 -600
- tapps_agents/core/template_selector.py +280 -280
- tapps_agents/core/test_generator.py +286 -286
- tapps_agents/core/tiered_context.py +253 -253
- tapps_agents/core/token_monitor.py +345 -345
- tapps_agents/core/traceability.py +254 -254
- tapps_agents/core/trajectory_tracker.py +50 -50
- tapps_agents/core/unicode_safe.py +143 -143
- tapps_agents/core/unified_cache_config.py +170 -170
- tapps_agents/core/unified_state.py +324 -324
- tapps_agents/core/validate_cursor_setup.py +237 -237
- tapps_agents/core/validation_registry.py +136 -136
- tapps_agents/core/validators/__init__.py +4 -4
- tapps_agents/core/validators/python_validator.py +87 -87
- tapps_agents/core/verification_agent.py +90 -90
- tapps_agents/core/visual_feedback.py +644 -644
- tapps_agents/core/workflow_validator.py +197 -197
- tapps_agents/core/worktree.py +367 -367
- tapps_agents/docker/__init__.py +10 -10
- tapps_agents/docker/analyzer.py +186 -186
- tapps_agents/docker/debugger.py +229 -229
- tapps_agents/docker/error_patterns.py +216 -216
- tapps_agents/epic/__init__.py +22 -22
- tapps_agents/epic/beads_sync.py +115 -115
- tapps_agents/epic/markdown_sync.py +105 -105
- tapps_agents/epic/models.py +96 -96
- tapps_agents/experts/__init__.py +163 -163
- tapps_agents/experts/agent_integration.py +243 -243
- tapps_agents/experts/auto_generator.py +331 -331
- tapps_agents/experts/base_expert.py +536 -536
- tapps_agents/experts/builtin_registry.py +261 -261
- tapps_agents/experts/business_metrics.py +565 -565
- tapps_agents/experts/cache.py +266 -266
- tapps_agents/experts/confidence_breakdown.py +306 -306
- tapps_agents/experts/confidence_calculator.py +336 -336
- tapps_agents/experts/confidence_metrics.py +236 -236
- tapps_agents/experts/domain_config.py +311 -311
- tapps_agents/experts/domain_detector.py +550 -550
- tapps_agents/experts/domain_utils.py +84 -84
- tapps_agents/experts/expert_config.py +113 -113
- tapps_agents/experts/expert_engine.py +465 -465
- tapps_agents/experts/expert_registry.py +744 -744
- tapps_agents/experts/expert_synthesizer.py +70 -70
- tapps_agents/experts/governance.py +197 -197
- tapps_agents/experts/history_logger.py +312 -312
- tapps_agents/experts/knowledge/README.md +180 -180
- tapps_agents/experts/knowledge/accessibility/accessible-forms.md +331 -331
- tapps_agents/experts/knowledge/accessibility/aria-patterns.md +344 -344
- tapps_agents/experts/knowledge/accessibility/color-contrast.md +285 -285
- tapps_agents/experts/knowledge/accessibility/keyboard-navigation.md +332 -332
- tapps_agents/experts/knowledge/accessibility/screen-readers.md +282 -282
- tapps_agents/experts/knowledge/accessibility/semantic-html.md +355 -355
- tapps_agents/experts/knowledge/accessibility/testing-accessibility.md +369 -369
- tapps_agents/experts/knowledge/accessibility/wcag-2.1.md +296 -296
- tapps_agents/experts/knowledge/accessibility/wcag-2.2.md +211 -211
- tapps_agents/experts/knowledge/agent-learning/best-practices.md +715 -715
- tapps_agents/experts/knowledge/agent-learning/pattern-extraction.md +282 -282
- tapps_agents/experts/knowledge/agent-learning/prompt-optimization.md +320 -320
- tapps_agents/experts/knowledge/ai-frameworks/model-optimization.md +90 -90
- tapps_agents/experts/knowledge/ai-frameworks/openvino-patterns.md +260 -260
- tapps_agents/experts/knowledge/api-design-integration/api-gateway-patterns.md +309 -309
- tapps_agents/experts/knowledge/api-design-integration/api-security-patterns.md +521 -521
- tapps_agents/experts/knowledge/api-design-integration/api-versioning.md +421 -421
- tapps_agents/experts/knowledge/api-design-integration/async-protocol-patterns.md +61 -61
- tapps_agents/experts/knowledge/api-design-integration/contract-testing.md +221 -221
- tapps_agents/experts/knowledge/api-design-integration/external-api-integration.md +489 -489
- tapps_agents/experts/knowledge/api-design-integration/fastapi-patterns.md +360 -360
- tapps_agents/experts/knowledge/api-design-integration/fastapi-testing.md +262 -262
- tapps_agents/experts/knowledge/api-design-integration/graphql-patterns.md +582 -582
- tapps_agents/experts/knowledge/api-design-integration/grpc-best-practices.md +499 -499
- tapps_agents/experts/knowledge/api-design-integration/mqtt-patterns.md +455 -455
- tapps_agents/experts/knowledge/api-design-integration/rate-limiting.md +507 -507
- tapps_agents/experts/knowledge/api-design-integration/restful-api-design.md +618 -618
- tapps_agents/experts/knowledge/api-design-integration/websocket-patterns.md +480 -480
- tapps_agents/experts/knowledge/cloud-infrastructure/cloud-native-patterns.md +175 -175
- tapps_agents/experts/knowledge/cloud-infrastructure/container-health-checks.md +261 -261
- tapps_agents/experts/knowledge/cloud-infrastructure/containerization.md +222 -222
- tapps_agents/experts/knowledge/cloud-infrastructure/cost-optimization.md +122 -122
- tapps_agents/experts/knowledge/cloud-infrastructure/disaster-recovery.md +153 -153
- tapps_agents/experts/knowledge/cloud-infrastructure/dockerfile-patterns.md +285 -285
- tapps_agents/experts/knowledge/cloud-infrastructure/infrastructure-as-code.md +187 -187
- tapps_agents/experts/knowledge/cloud-infrastructure/kubernetes-patterns.md +253 -253
- tapps_agents/experts/knowledge/cloud-infrastructure/multi-cloud-strategies.md +155 -155
- tapps_agents/experts/knowledge/cloud-infrastructure/serverless-architecture.md +200 -200
- tapps_agents/experts/knowledge/code-quality-analysis/README.md +16 -16
- tapps_agents/experts/knowledge/code-quality-analysis/code-metrics.md +137 -137
- tapps_agents/experts/knowledge/code-quality-analysis/complexity-analysis.md +181 -181
- tapps_agents/experts/knowledge/code-quality-analysis/technical-debt-patterns.md +191 -191
- tapps_agents/experts/knowledge/data-privacy-compliance/anonymization.md +313 -313
- tapps_agents/experts/knowledge/data-privacy-compliance/ccpa.md +255 -255
- tapps_agents/experts/knowledge/data-privacy-compliance/consent-management.md +282 -282
- tapps_agents/experts/knowledge/data-privacy-compliance/data-minimization.md +275 -275
- tapps_agents/experts/knowledge/data-privacy-compliance/data-retention.md +297 -297
- tapps_agents/experts/knowledge/data-privacy-compliance/data-subject-rights.md +383 -383
- tapps_agents/experts/knowledge/data-privacy-compliance/encryption-privacy.md +285 -285
- tapps_agents/experts/knowledge/data-privacy-compliance/gdpr.md +344 -344
- tapps_agents/experts/knowledge/data-privacy-compliance/hipaa.md +385 -385
- tapps_agents/experts/knowledge/data-privacy-compliance/privacy-by-design.md +280 -280
- tapps_agents/experts/knowledge/database-data-management/acid-vs-cap.md +164 -164
- tapps_agents/experts/knowledge/database-data-management/backup-and-recovery.md +182 -182
- tapps_agents/experts/knowledge/database-data-management/data-modeling.md +172 -172
- tapps_agents/experts/knowledge/database-data-management/database-design.md +187 -187
- tapps_agents/experts/knowledge/database-data-management/flux-query-optimization.md +342 -342
- tapps_agents/experts/knowledge/database-data-management/influxdb-connection-patterns.md +432 -432
- tapps_agents/experts/knowledge/database-data-management/influxdb-patterns.md +442 -442
- tapps_agents/experts/knowledge/database-data-management/migration-strategies.md +216 -216
- tapps_agents/experts/knowledge/database-data-management/nosql-patterns.md +259 -259
- tapps_agents/experts/knowledge/database-data-management/scalability-patterns.md +184 -184
- tapps_agents/experts/knowledge/database-data-management/sql-optimization.md +175 -175
- tapps_agents/experts/knowledge/database-data-management/time-series-modeling.md +444 -444
- tapps_agents/experts/knowledge/development-workflow/README.md +16 -16
- tapps_agents/experts/knowledge/development-workflow/automation-best-practices.md +216 -216
- tapps_agents/experts/knowledge/development-workflow/build-strategies.md +198 -198
- tapps_agents/experts/knowledge/development-workflow/deployment-patterns.md +205 -205
- tapps_agents/experts/knowledge/development-workflow/git-workflows.md +205 -205
- tapps_agents/experts/knowledge/documentation-knowledge-management/README.md +16 -16
- tapps_agents/experts/knowledge/documentation-knowledge-management/api-documentation-patterns.md +231 -231
- tapps_agents/experts/knowledge/documentation-knowledge-management/documentation-standards.md +191 -191
- tapps_agents/experts/knowledge/documentation-knowledge-management/knowledge-management.md +171 -171
- tapps_agents/experts/knowledge/documentation-knowledge-management/technical-writing-guide.md +192 -192
- tapps_agents/experts/knowledge/observability-monitoring/alerting-patterns.md +461 -461
- tapps_agents/experts/knowledge/observability-monitoring/apm-tools.md +459 -459
- tapps_agents/experts/knowledge/observability-monitoring/distributed-tracing.md +367 -367
- tapps_agents/experts/knowledge/observability-monitoring/logging-strategies.md +478 -478
- tapps_agents/experts/knowledge/observability-monitoring/metrics-and-monitoring.md +510 -510
- tapps_agents/experts/knowledge/observability-monitoring/observability-best-practices.md +492 -492
- tapps_agents/experts/knowledge/observability-monitoring/open-telemetry.md +573 -573
- tapps_agents/experts/knowledge/observability-monitoring/slo-sli-sla.md +419 -419
- tapps_agents/experts/knowledge/performance/anti-patterns.md +284 -284
- tapps_agents/experts/knowledge/performance/api-performance.md +256 -256
- tapps_agents/experts/knowledge/performance/caching.md +327 -327
- tapps_agents/experts/knowledge/performance/database-performance.md +252 -252
- tapps_agents/experts/knowledge/performance/optimization-patterns.md +327 -327
- tapps_agents/experts/knowledge/performance/profiling.md +297 -297
- tapps_agents/experts/knowledge/performance/resource-management.md +293 -293
- tapps_agents/experts/knowledge/performance/scalability.md +306 -306
- tapps_agents/experts/knowledge/security/owasp-top10.md +209 -209
- tapps_agents/experts/knowledge/security/secure-coding-practices.md +207 -207
- tapps_agents/experts/knowledge/security/threat-modeling.md +220 -220
- tapps_agents/experts/knowledge/security/vulnerability-patterns.md +342 -342
- tapps_agents/experts/knowledge/software-architecture/docker-compose-patterns.md +314 -314
- tapps_agents/experts/knowledge/software-architecture/microservices-patterns.md +379 -379
- tapps_agents/experts/knowledge/software-architecture/service-communication.md +316 -316
- tapps_agents/experts/knowledge/testing/best-practices.md +310 -310
- tapps_agents/experts/knowledge/testing/coverage-analysis.md +293 -293
- tapps_agents/experts/knowledge/testing/mocking.md +256 -256
- tapps_agents/experts/knowledge/testing/test-automation.md +276 -276
- tapps_agents/experts/knowledge/testing/test-data.md +271 -271
- tapps_agents/experts/knowledge/testing/test-design-patterns.md +280 -280
- tapps_agents/experts/knowledge/testing/test-maintenance.md +236 -236
- tapps_agents/experts/knowledge/testing/test-strategies.md +311 -311
- tapps_agents/experts/knowledge/user-experience/information-architecture.md +325 -325
- tapps_agents/experts/knowledge/user-experience/interaction-design.md +363 -363
- tapps_agents/experts/knowledge/user-experience/prototyping.md +293 -293
- tapps_agents/experts/knowledge/user-experience/usability-heuristics.md +337 -337
- tapps_agents/experts/knowledge/user-experience/usability-testing.md +311 -311
- tapps_agents/experts/knowledge/user-experience/user-journeys.md +296 -296
- tapps_agents/experts/knowledge/user-experience/user-research.md +373 -373
- tapps_agents/experts/knowledge/user-experience/ux-principles.md +340 -340
- tapps_agents/experts/knowledge_freshness.py +321 -321
- tapps_agents/experts/knowledge_ingestion.py +438 -438
- tapps_agents/experts/knowledge_need_detector.py +93 -93
- tapps_agents/experts/knowledge_validator.py +382 -382
- tapps_agents/experts/observability.py +440 -440
- tapps_agents/experts/passive_notifier.py +238 -238
- tapps_agents/experts/proactive_orchestrator.py +32 -32
- tapps_agents/experts/rag_chunker.py +205 -205
- tapps_agents/experts/rag_embedder.py +152 -152
- tapps_agents/experts/rag_evaluation.py +299 -299
- tapps_agents/experts/rag_index.py +303 -303
- tapps_agents/experts/rag_metrics.py +293 -293
- tapps_agents/experts/rag_safety.py +263 -263
- tapps_agents/experts/report_generator.py +296 -296
- tapps_agents/experts/setup_wizard.py +441 -441
- tapps_agents/experts/simple_rag.py +431 -431
- tapps_agents/experts/vector_rag.py +354 -354
- tapps_agents/experts/weight_distributor.py +304 -304
- tapps_agents/health/__init__.py +24 -24
- tapps_agents/health/base.py +75 -75
- tapps_agents/health/checks/__init__.py +22 -22
- tapps_agents/health/checks/automation.py +127 -127
- tapps_agents/health/checks/context7_cache.py +210 -210
- tapps_agents/health/checks/environment.py +116 -116
- tapps_agents/health/checks/execution.py +170 -170
- tapps_agents/health/checks/knowledge_base.py +187 -187
- tapps_agents/health/checks/outcomes.py +324 -324
- tapps_agents/health/collector.py +280 -280
- tapps_agents/health/dashboard.py +137 -137
- tapps_agents/health/metrics.py +151 -151
- tapps_agents/health/orchestrator.py +271 -271
- tapps_agents/health/registry.py +166 -166
- tapps_agents/hooks/__init__.py +33 -33
- tapps_agents/hooks/config.py +140 -140
- tapps_agents/hooks/events.py +135 -135
- tapps_agents/hooks/executor.py +128 -128
- tapps_agents/hooks/manager.py +143 -143
- tapps_agents/integration/__init__.py +8 -8
- tapps_agents/integration/service_integrator.py +121 -121
- tapps_agents/integrations/__init__.py +10 -10
- tapps_agents/integrations/clawdbot.py +525 -525
- tapps_agents/integrations/memory_bridge.py +356 -356
- tapps_agents/mcp/__init__.py +18 -18
- tapps_agents/mcp/gateway.py +112 -112
- tapps_agents/mcp/servers/__init__.py +13 -13
- tapps_agents/mcp/servers/analysis.py +204 -204
- tapps_agents/mcp/servers/context7.py +198 -198
- tapps_agents/mcp/servers/filesystem.py +218 -218
- tapps_agents/mcp/servers/git.py +201 -201
- tapps_agents/mcp/tool_registry.py +115 -115
- tapps_agents/quality/__init__.py +54 -54
- tapps_agents/quality/coverage_analyzer.py +379 -379
- tapps_agents/quality/enforcement.py +82 -82
- tapps_agents/quality/gates/__init__.py +37 -37
- tapps_agents/quality/gates/approval_gate.py +255 -255
- tapps_agents/quality/gates/base.py +84 -84
- tapps_agents/quality/gates/exceptions.py +43 -43
- tapps_agents/quality/gates/policy_gate.py +195 -195
- tapps_agents/quality/gates/registry.py +239 -239
- tapps_agents/quality/gates/security_gate.py +156 -156
- tapps_agents/quality/quality_gates.py +369 -369
- tapps_agents/quality/secret_scanner.py +335 -335
- tapps_agents/session/__init__.py +19 -19
- tapps_agents/session/manager.py +256 -256
- tapps_agents/simple_mode/__init__.py +66 -66
- tapps_agents/simple_mode/agent_contracts.py +357 -357
- tapps_agents/simple_mode/beads_hooks.py +151 -151
- tapps_agents/simple_mode/code_snippet_handler.py +382 -382
- tapps_agents/simple_mode/documentation_manager.py +395 -395
- tapps_agents/simple_mode/documentation_reader.py +187 -187
- tapps_agents/simple_mode/file_inference.py +292 -292
- tapps_agents/simple_mode/framework_change_detector.py +268 -268
- tapps_agents/simple_mode/intent_parser.py +510 -510
- tapps_agents/simple_mode/learning_progression.py +358 -358
- tapps_agents/simple_mode/nl_handler.py +700 -700
- tapps_agents/simple_mode/onboarding.py +253 -253
- tapps_agents/simple_mode/orchestrators/__init__.py +38 -38
- tapps_agents/simple_mode/orchestrators/base.py +185 -185
- tapps_agents/simple_mode/orchestrators/breakdown_orchestrator.py +49 -49
- tapps_agents/simple_mode/orchestrators/brownfield_orchestrator.py +135 -135
- tapps_agents/simple_mode/orchestrators/build_orchestrator.py +2700 -2667
- tapps_agents/simple_mode/orchestrators/deliverable_checklist.py +349 -349
- tapps_agents/simple_mode/orchestrators/enhance_orchestrator.py +53 -53
- tapps_agents/simple_mode/orchestrators/epic_orchestrator.py +122 -122
- tapps_agents/simple_mode/orchestrators/explore_orchestrator.py +184 -184
- tapps_agents/simple_mode/orchestrators/fix_orchestrator.py +723 -723
- tapps_agents/simple_mode/orchestrators/plan_analysis_orchestrator.py +206 -206
- tapps_agents/simple_mode/orchestrators/pr_orchestrator.py +237 -237
- tapps_agents/simple_mode/orchestrators/refactor_orchestrator.py +222 -222
- tapps_agents/simple_mode/orchestrators/requirements_tracer.py +262 -262
- tapps_agents/simple_mode/orchestrators/resume_orchestrator.py +210 -210
- tapps_agents/simple_mode/orchestrators/review_orchestrator.py +161 -161
- tapps_agents/simple_mode/orchestrators/test_orchestrator.py +82 -82
- tapps_agents/simple_mode/output_aggregator.py +340 -340
- tapps_agents/simple_mode/result_formatters.py +598 -598
- tapps_agents/simple_mode/step_dependencies.py +382 -382
- tapps_agents/simple_mode/step_results.py +276 -276
- tapps_agents/simple_mode/streaming.py +388 -388
- tapps_agents/simple_mode/variations.py +129 -129
- tapps_agents/simple_mode/visual_feedback.py +238 -238
- tapps_agents/simple_mode/zero_config.py +274 -274
- tapps_agents/suggestions/__init__.py +8 -8
- tapps_agents/suggestions/inline_suggester.py +52 -52
- tapps_agents/templates/__init__.py +8 -8
- tapps_agents/templates/microservice_generator.py +274 -274
- tapps_agents/utils/env_validator.py +291 -291
- tapps_agents/workflow/__init__.py +171 -171
- tapps_agents/workflow/acceptance_verifier.py +132 -132
- tapps_agents/workflow/agent_handlers/__init__.py +41 -41
- tapps_agents/workflow/agent_handlers/analyst_handler.py +75 -75
- tapps_agents/workflow/agent_handlers/architect_handler.py +107 -107
- tapps_agents/workflow/agent_handlers/base.py +84 -84
- tapps_agents/workflow/agent_handlers/debugger_handler.py +100 -100
- tapps_agents/workflow/agent_handlers/designer_handler.py +110 -110
- tapps_agents/workflow/agent_handlers/documenter_handler.py +94 -94
- tapps_agents/workflow/agent_handlers/implementer_handler.py +235 -235
- tapps_agents/workflow/agent_handlers/ops_handler.py +62 -62
- tapps_agents/workflow/agent_handlers/orchestrator_handler.py +43 -43
- tapps_agents/workflow/agent_handlers/planner_handler.py +98 -98
- tapps_agents/workflow/agent_handlers/registry.py +119 -119
- tapps_agents/workflow/agent_handlers/reviewer_handler.py +119 -119
- tapps_agents/workflow/agent_handlers/tester_handler.py +69 -69
- tapps_agents/workflow/analytics_accessor.py +337 -337
- tapps_agents/workflow/analytics_alerts.py +416 -416
- tapps_agents/workflow/analytics_dashboard_cursor.py +281 -281
- tapps_agents/workflow/analytics_dual_write.py +103 -103
- tapps_agents/workflow/analytics_integration.py +119 -119
- tapps_agents/workflow/analytics_query_parser.py +278 -278
- tapps_agents/workflow/analytics_visualizer.py +259 -259
- tapps_agents/workflow/artifact_helper.py +204 -204
- tapps_agents/workflow/audit_logger.py +263 -263
- tapps_agents/workflow/auto_execution_config.py +340 -340
- tapps_agents/workflow/auto_progression.py +586 -586
- tapps_agents/workflow/branch_cleanup.py +349 -349
- tapps_agents/workflow/checkpoint.py +256 -256
- tapps_agents/workflow/checkpoint_manager.py +178 -178
- tapps_agents/workflow/code_artifact.py +179 -179
- tapps_agents/workflow/common_enums.py +96 -96
- tapps_agents/workflow/confirmation_handler.py +130 -130
- tapps_agents/workflow/context_analyzer.py +222 -222
- tapps_agents/workflow/context_artifact.py +230 -230
- tapps_agents/workflow/cursor_chat.py +94 -94
- tapps_agents/workflow/cursor_executor.py +2337 -2196
- tapps_agents/workflow/cursor_skill_helper.py +516 -516
- tapps_agents/workflow/dependency_resolver.py +244 -244
- tapps_agents/workflow/design_artifact.py +156 -156
- tapps_agents/workflow/detector.py +751 -751
- tapps_agents/workflow/direct_execution_fallback.py +301 -301
- tapps_agents/workflow/docs_artifact.py +168 -168
- tapps_agents/workflow/enforcer.py +389 -389
- tapps_agents/workflow/enhancement_artifact.py +142 -142
- tapps_agents/workflow/error_recovery.py +806 -806
- tapps_agents/workflow/event_bus.py +183 -183
- tapps_agents/workflow/event_log.py +612 -612
- tapps_agents/workflow/events.py +63 -63
- tapps_agents/workflow/exceptions.py +43 -43
- tapps_agents/workflow/execution_graph.py +498 -498
- tapps_agents/workflow/execution_plan.py +126 -126
- tapps_agents/workflow/file_utils.py +186 -186
- tapps_agents/workflow/gate_evaluator.py +182 -182
- tapps_agents/workflow/gate_integration.py +200 -200
- tapps_agents/workflow/graph_visualizer.py +130 -130
- tapps_agents/workflow/health_checker.py +206 -206
- tapps_agents/workflow/logging_helper.py +243 -243
- tapps_agents/workflow/manifest.py +582 -582
- tapps_agents/workflow/marker_writer.py +250 -250
- tapps_agents/workflow/message_formatter.py +188 -188
- tapps_agents/workflow/messaging.py +325 -325
- tapps_agents/workflow/metadata_models.py +91 -91
- tapps_agents/workflow/metrics_integration.py +226 -226
- tapps_agents/workflow/migration_utils.py +116 -116
- tapps_agents/workflow/models.py +148 -111
- tapps_agents/workflow/nlp_config.py +198 -198
- tapps_agents/workflow/nlp_error_handler.py +207 -207
- tapps_agents/workflow/nlp_executor.py +163 -163
- tapps_agents/workflow/nlp_parser.py +528 -528
- tapps_agents/workflow/observability_dashboard.py +451 -451
- tapps_agents/workflow/observer.py +170 -170
- tapps_agents/workflow/ops_artifact.py +257 -257
- tapps_agents/workflow/output_passing.py +214 -214
- tapps_agents/workflow/parallel_executor.py +463 -463
- tapps_agents/workflow/planning_artifact.py +179 -179
- tapps_agents/workflow/preset_loader.py +285 -285
- tapps_agents/workflow/preset_recommender.py +270 -270
- tapps_agents/workflow/progress_logger.py +145 -145
- tapps_agents/workflow/progress_manager.py +303 -303
- tapps_agents/workflow/progress_monitor.py +186 -186
- tapps_agents/workflow/progress_updates.py +423 -423
- tapps_agents/workflow/quality_artifact.py +158 -158
- tapps_agents/workflow/quality_loopback.py +101 -101
- tapps_agents/workflow/recommender.py +387 -387
- tapps_agents/workflow/remediation_loop.py +166 -166
- tapps_agents/workflow/result_aggregator.py +300 -300
- tapps_agents/workflow/review_artifact.py +185 -185
- tapps_agents/workflow/schema_validator.py +522 -522
- tapps_agents/workflow/session_handoff.py +178 -178
- tapps_agents/workflow/skill_invoker.py +648 -648
- tapps_agents/workflow/state_manager.py +756 -756
- tapps_agents/workflow/state_persistence_config.py +331 -331
- tapps_agents/workflow/status_monitor.py +449 -449
- tapps_agents/workflow/step_checkpoint.py +314 -314
- tapps_agents/workflow/step_details.py +201 -201
- tapps_agents/workflow/story_models.py +147 -147
- tapps_agents/workflow/streaming.py +416 -416
- tapps_agents/workflow/suggestion_engine.py +552 -552
- tapps_agents/workflow/testing_artifact.py +186 -186
- tapps_agents/workflow/timeline.py +158 -158
- tapps_agents/workflow/token_integration.py +209 -209
- tapps_agents/workflow/validation.py +217 -217
- tapps_agents/workflow/visual_feedback.py +391 -391
- tapps_agents/workflow/workflow_chain.py +95 -95
- tapps_agents/workflow/workflow_summary.py +219 -219
- tapps_agents/workflow/worktree_manager.py +724 -724
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/METADATA +672 -672
- tapps_agents-3.6.0.dist-info/RECORD +758 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/licenses/LICENSE +22 -22
- tapps_agents/health/checks/outcomes.backup_20260204_064058.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +0 -324
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +0 -324
- tapps_agents-3.5.40.dist-info/RECORD +0 -760
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/WHEEL +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.5.40.dist-info → tapps_agents-3.6.0.dist-info}/top_level.txt +0 -0
|
@@ -1,806 +1,806 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Error Recovery and Suggestion System
|
|
3
|
-
|
|
4
|
-
Epic 14: Error Recovery and Suggestions
|
|
5
|
-
Provides intelligent error analysis, recovery suggestions, and automatic retry with learning.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import json
|
|
11
|
-
import logging
|
|
12
|
-
import re
|
|
13
|
-
from dataclasses import dataclass, field
|
|
14
|
-
from datetime import datetime
|
|
15
|
-
from enum import Enum
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
from typing import Any
|
|
18
|
-
|
|
19
|
-
from ..core.error_envelope import ErrorEnvelope, ErrorEnvelopeBuilder
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class ErrorSeverity(Enum):
|
|
25
|
-
"""Error severity levels."""
|
|
26
|
-
|
|
27
|
-
LOW = "low" # Minor issue, workflow can continue
|
|
28
|
-
MEDIUM = "medium" # Moderate issue, may need attention
|
|
29
|
-
HIGH = "high" # Significant issue, workflow may be blocked
|
|
30
|
-
CRITICAL = "critical" # Critical issue, workflow must stop
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class ErrorType(Enum):
|
|
34
|
-
"""Detailed error types for better categorization."""
|
|
35
|
-
|
|
36
|
-
# Configuration errors
|
|
37
|
-
MISSING_CONFIG = "missing_config"
|
|
38
|
-
INVALID_CONFIG = "invalid_config"
|
|
39
|
-
ENV_VAR_MISSING = "env_var_missing"
|
|
40
|
-
|
|
41
|
-
# File system errors
|
|
42
|
-
FILE_NOT_FOUND = "file_not_found"
|
|
43
|
-
PERMISSION_DENIED = "permission_denied"
|
|
44
|
-
DISK_FULL = "disk_full"
|
|
45
|
-
PATH_INVALID = "path_invalid"
|
|
46
|
-
|
|
47
|
-
# Network/external errors
|
|
48
|
-
CONNECTION_ERROR = "connection_error"
|
|
49
|
-
TIMEOUT = "timeout"
|
|
50
|
-
SERVICE_UNAVAILABLE = "service_unavailable"
|
|
51
|
-
RATE_LIMIT = "rate_limit"
|
|
52
|
-
|
|
53
|
-
# Validation errors
|
|
54
|
-
INVALID_INPUT = "invalid_input"
|
|
55
|
-
MISSING_REQUIRED = "missing_required"
|
|
56
|
-
TYPE_MISMATCH = "type_mismatch"
|
|
57
|
-
|
|
58
|
-
# Execution errors
|
|
59
|
-
SYNTAX_ERROR = "syntax_error"
|
|
60
|
-
RUNTIME_ERROR = "runtime_error"
|
|
61
|
-
IMPORT_ERROR = "import_error"
|
|
62
|
-
DEPENDENCY_MISSING = "dependency_missing"
|
|
63
|
-
|
|
64
|
-
# Workflow-specific errors
|
|
65
|
-
STEP_FAILED = "step_failed"
|
|
66
|
-
GATE_FAILED = "gate_failed"
|
|
67
|
-
DEPENDENCY_BLOCKED = "dependency_blocked"
|
|
68
|
-
|
|
69
|
-
# Unknown
|
|
70
|
-
UNKNOWN = "unknown"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@dataclass
|
|
74
|
-
class ErrorContext:
|
|
75
|
-
"""Context information about when/where an error occurred."""
|
|
76
|
-
|
|
77
|
-
workflow_id: str | None = None
|
|
78
|
-
step_id: str | None = None
|
|
79
|
-
agent: str | None = None
|
|
80
|
-
action: str | None = None
|
|
81
|
-
timestamp: datetime = field(default_factory=datetime.now)
|
|
82
|
-
step_number: int | None = None
|
|
83
|
-
total_steps: int | None = None
|
|
84
|
-
workflow_status: str | None = None
|
|
85
|
-
recent_changes: list[str] = field(default_factory=list)
|
|
86
|
-
environment: dict[str, Any] = field(default_factory=dict)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@dataclass
|
|
90
|
-
class ErrorAnalysis:
|
|
91
|
-
"""Comprehensive error analysis."""
|
|
92
|
-
|
|
93
|
-
error_envelope: ErrorEnvelope
|
|
94
|
-
error_type: ErrorType
|
|
95
|
-
severity: ErrorSeverity
|
|
96
|
-
context: ErrorContext
|
|
97
|
-
pattern_match: str | None = None # Matched error pattern
|
|
98
|
-
similar_errors: list[dict[str, Any]] = field(default_factory=list)
|
|
99
|
-
metadata: dict[str, Any] = field(default_factory=dict)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@dataclass
|
|
103
|
-
class RecoverySuggestion:
|
|
104
|
-
"""A recovery suggestion with ranking and explanation."""
|
|
105
|
-
|
|
106
|
-
action: str # What to do
|
|
107
|
-
description: str # Detailed description
|
|
108
|
-
confidence: float # 0.0-1.0 confidence score
|
|
109
|
-
explanation: str # Why this suggestion
|
|
110
|
-
steps: list[str] = field(default_factory=list) # Step-by-step instructions
|
|
111
|
-
requires_manual: bool = False # Whether manual intervention is needed
|
|
112
|
-
metadata: dict[str, Any] = field(default_factory=dict)
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
class ErrorAnalyzer:
|
|
116
|
-
"""
|
|
117
|
-
Analyzes errors to understand why they occurred and categorize them.
|
|
118
|
-
|
|
119
|
-
Epic 14: Story 14.1
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
def __init__(self):
|
|
123
|
-
"""Initialize error analyzer."""
|
|
124
|
-
self.patterns = self._load_error_patterns()
|
|
125
|
-
|
|
126
|
-
def analyze(
|
|
127
|
-
self,
|
|
128
|
-
error: Exception | ErrorEnvelope | str,
|
|
129
|
-
context: ErrorContext | None = None,
|
|
130
|
-
) -> ErrorAnalysis:
|
|
131
|
-
"""
|
|
132
|
-
Analyze an error and return comprehensive analysis.
|
|
133
|
-
|
|
134
|
-
Args:
|
|
135
|
-
error: Exception, ErrorEnvelope, or error message string
|
|
136
|
-
context: Optional context about when/where error occurred
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
ErrorAnalysis with categorization, severity, and pattern matching
|
|
140
|
-
"""
|
|
141
|
-
# Convert to ErrorEnvelope if needed
|
|
142
|
-
if isinstance(error, ErrorEnvelope):
|
|
143
|
-
envelope = error
|
|
144
|
-
elif isinstance(error, Exception):
|
|
145
|
-
envelope = ErrorEnvelopeBuilder.from_exception(error)
|
|
146
|
-
else:
|
|
147
|
-
# String error message
|
|
148
|
-
envelope = ErrorEnvelope(
|
|
149
|
-
code="unknown_error",
|
|
150
|
-
message=str(error),
|
|
151
|
-
category="execution",
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
# Create context if not provided
|
|
155
|
-
if context is None:
|
|
156
|
-
context = ErrorContext(
|
|
157
|
-
workflow_id=envelope.workflow_id,
|
|
158
|
-
step_id=envelope.step_id,
|
|
159
|
-
agent=envelope.agent,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
# Determine error type
|
|
163
|
-
error_type = self._determine_error_type(envelope, error if isinstance(error, Exception) else None)
|
|
164
|
-
|
|
165
|
-
# Determine severity
|
|
166
|
-
severity = self._determine_severity(envelope, error_type)
|
|
167
|
-
|
|
168
|
-
# Pattern matching
|
|
169
|
-
pattern_match = self._match_pattern(envelope)
|
|
170
|
-
|
|
171
|
-
# Find similar errors (for learning)
|
|
172
|
-
similar_errors = self._find_similar_errors(envelope, pattern_match)
|
|
173
|
-
|
|
174
|
-
return ErrorAnalysis(
|
|
175
|
-
error_envelope=envelope,
|
|
176
|
-
error_type=error_type,
|
|
177
|
-
severity=severity,
|
|
178
|
-
context=context,
|
|
179
|
-
pattern_match=pattern_match,
|
|
180
|
-
similar_errors=similar_errors,
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
def _determine_error_type(
|
|
184
|
-
self, envelope: ErrorEnvelope, exc: Exception | None
|
|
185
|
-
) -> ErrorType:
|
|
186
|
-
"""Determine detailed error type."""
|
|
187
|
-
# Check error code first
|
|
188
|
-
code = envelope.code.lower()
|
|
189
|
-
message = envelope.message.lower()
|
|
190
|
-
|
|
191
|
-
# Configuration errors
|
|
192
|
-
if "config" in code or "config" in message:
|
|
193
|
-
if "missing" in message or "not found" in message:
|
|
194
|
-
return ErrorType.MISSING_CONFIG
|
|
195
|
-
return ErrorType.INVALID_CONFIG
|
|
196
|
-
if "env" in code or "environment" in message:
|
|
197
|
-
return ErrorType.ENV_VAR_MISSING
|
|
198
|
-
|
|
199
|
-
# File system errors
|
|
200
|
-
if "file_not_found" in code or "file not found" in message:
|
|
201
|
-
return ErrorType.FILE_NOT_FOUND
|
|
202
|
-
if "permission" in code or "permission" in message:
|
|
203
|
-
return ErrorType.PERMISSION_DENIED
|
|
204
|
-
if "disk full" in message or "no space" in message:
|
|
205
|
-
return ErrorType.DISK_FULL
|
|
206
|
-
if "invalid path" in message or "path not found" in message:
|
|
207
|
-
return ErrorType.PATH_INVALID
|
|
208
|
-
|
|
209
|
-
# Network errors
|
|
210
|
-
if "connection" in code or "connection" in message:
|
|
211
|
-
return ErrorType.CONNECTION_ERROR
|
|
212
|
-
if "timeout" in code or "timeout" in message:
|
|
213
|
-
return ErrorType.TIMEOUT
|
|
214
|
-
if "unavailable" in message or "503" in message:
|
|
215
|
-
return ErrorType.SERVICE_UNAVAILABLE
|
|
216
|
-
if "rate limit" in message or "429" in message:
|
|
217
|
-
return ErrorType.RATE_LIMIT
|
|
218
|
-
|
|
219
|
-
# Validation errors
|
|
220
|
-
if "validation" in code or "invalid" in message:
|
|
221
|
-
if "required" in message or "missing" in message:
|
|
222
|
-
return ErrorType.MISSING_REQUIRED
|
|
223
|
-
if "type" in message:
|
|
224
|
-
return ErrorType.TYPE_MISMATCH
|
|
225
|
-
return ErrorType.INVALID_INPUT
|
|
226
|
-
|
|
227
|
-
# Execution errors
|
|
228
|
-
if exc:
|
|
229
|
-
if isinstance(exc, SyntaxError):
|
|
230
|
-
return ErrorType.SYNTAX_ERROR
|
|
231
|
-
if isinstance(exc, ImportError):
|
|
232
|
-
return ErrorType.IMPORT_ERROR
|
|
233
|
-
if isinstance(exc, RuntimeError):
|
|
234
|
-
return ErrorType.RUNTIME_ERROR
|
|
235
|
-
|
|
236
|
-
if "import" in message or "module not found" in message:
|
|
237
|
-
return ErrorType.IMPORT_ERROR
|
|
238
|
-
if "dependency" in message or "package not found" in message:
|
|
239
|
-
return ErrorType.DEPENDENCY_MISSING
|
|
240
|
-
if "syntax" in message:
|
|
241
|
-
return ErrorType.SYNTAX_ERROR
|
|
242
|
-
|
|
243
|
-
# Workflow-specific
|
|
244
|
-
if "step" in code and "failed" in message:
|
|
245
|
-
return ErrorType.STEP_FAILED
|
|
246
|
-
if "gate" in code or "gate" in message:
|
|
247
|
-
return ErrorType.GATE_FAILED
|
|
248
|
-
if "dependency" in code and "blocked" in message:
|
|
249
|
-
return ErrorType.DEPENDENCY_BLOCKED
|
|
250
|
-
|
|
251
|
-
return ErrorType.UNKNOWN
|
|
252
|
-
|
|
253
|
-
def _determine_severity(
|
|
254
|
-
self, envelope: ErrorEnvelope, error_type: ErrorType
|
|
255
|
-
) -> ErrorSeverity:
|
|
256
|
-
"""Determine error severity."""
|
|
257
|
-
# Critical errors
|
|
258
|
-
if error_type in (
|
|
259
|
-
ErrorType.DISK_FULL,
|
|
260
|
-
ErrorType.DEPENDENCY_BLOCKED,
|
|
261
|
-
):
|
|
262
|
-
return ErrorSeverity.CRITICAL
|
|
263
|
-
|
|
264
|
-
# High severity
|
|
265
|
-
if error_type in (
|
|
266
|
-
ErrorType.SYNTAX_ERROR,
|
|
267
|
-
ErrorType.IMPORT_ERROR,
|
|
268
|
-
ErrorType.STEP_FAILED,
|
|
269
|
-
ErrorType.GATE_FAILED,
|
|
270
|
-
):
|
|
271
|
-
return ErrorSeverity.HIGH
|
|
272
|
-
|
|
273
|
-
# Medium severity
|
|
274
|
-
if error_type in (
|
|
275
|
-
ErrorType.CONNECTION_ERROR,
|
|
276
|
-
ErrorType.SERVICE_UNAVAILABLE,
|
|
277
|
-
ErrorType.TIMEOUT,
|
|
278
|
-
ErrorType.INVALID_CONFIG,
|
|
279
|
-
):
|
|
280
|
-
return ErrorSeverity.MEDIUM
|
|
281
|
-
|
|
282
|
-
# Low severity (often recoverable)
|
|
283
|
-
if error_type in (
|
|
284
|
-
ErrorType.RATE_LIMIT,
|
|
285
|
-
ErrorType.TIMEOUT,
|
|
286
|
-
ErrorType.FILE_NOT_FOUND,
|
|
287
|
-
ErrorType.PERMISSION_DENIED,
|
|
288
|
-
) and envelope.recoverable:
|
|
289
|
-
return ErrorSeverity.LOW
|
|
290
|
-
|
|
291
|
-
return ErrorSeverity.MEDIUM
|
|
292
|
-
|
|
293
|
-
def _load_error_patterns(self) -> dict[str, dict[str, Any]]:
|
|
294
|
-
"""Load error patterns for matching."""
|
|
295
|
-
# Common error patterns with regex
|
|
296
|
-
return {
|
|
297
|
-
"file_not_found": {
|
|
298
|
-
"pattern": r"file.*not found|no such file|file does not exist",
|
|
299
|
-
"type": ErrorType.FILE_NOT_FOUND,
|
|
300
|
-
},
|
|
301
|
-
"permission_denied": {
|
|
302
|
-
"pattern": r"permission denied|access denied|permission error",
|
|
303
|
-
"type": ErrorType.PERMISSION_DENIED,
|
|
304
|
-
},
|
|
305
|
-
"connection_error": {
|
|
306
|
-
"pattern": r"connection.*refused|connection.*failed|could not connect",
|
|
307
|
-
"type": ErrorType.CONNECTION_ERROR,
|
|
308
|
-
},
|
|
309
|
-
"timeout": {
|
|
310
|
-
"pattern": r"timeout|timed out|operation.*too long",
|
|
311
|
-
"type": ErrorType.TIMEOUT,
|
|
312
|
-
},
|
|
313
|
-
"import_error": {
|
|
314
|
-
"pattern": r"no module named|import.*error|cannot import",
|
|
315
|
-
"type": ErrorType.IMPORT_ERROR,
|
|
316
|
-
},
|
|
317
|
-
"syntax_error": {
|
|
318
|
-
"pattern": r"syntax error|invalid syntax|parse error",
|
|
319
|
-
"type": ErrorType.SYNTAX_ERROR,
|
|
320
|
-
},
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
def _match_pattern(self, envelope: ErrorEnvelope) -> str | None:
|
|
324
|
-
"""Match error against known patterns."""
|
|
325
|
-
message = envelope.message.lower()
|
|
326
|
-
for pattern_name, pattern_info in self.patterns.items():
|
|
327
|
-
if re.search(pattern_info["pattern"], message, re.IGNORECASE):
|
|
328
|
-
return pattern_name
|
|
329
|
-
return None
|
|
330
|
-
|
|
331
|
-
def _find_similar_errors(
|
|
332
|
-
self, envelope: ErrorEnvelope, pattern: str | None
|
|
333
|
-
) -> list[dict[str, Any]]:
|
|
334
|
-
"""Find similar errors from history (for learning)."""
|
|
335
|
-
# This would query error history database
|
|
336
|
-
# For now, return empty list
|
|
337
|
-
return []
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
class RecoverySuggestionEngine:
|
|
341
|
-
"""
|
|
342
|
-
Generates recovery suggestions based on error analysis.
|
|
343
|
-
|
|
344
|
-
Epic 14: Story 14.2
|
|
345
|
-
"""
|
|
346
|
-
|
|
347
|
-
def __init__(self, learning_data_path: Path | None = None):
|
|
348
|
-
"""
|
|
349
|
-
Initialize recovery suggestion engine.
|
|
350
|
-
|
|
351
|
-
Args:
|
|
352
|
-
learning_data_path: Path to learning data file
|
|
353
|
-
"""
|
|
354
|
-
self.learning_data_path = learning_data_path or Path(
|
|
355
|
-
".tapps-agents/error_learning.json"
|
|
356
|
-
)
|
|
357
|
-
self.learning_data = self._load_learning_data()
|
|
358
|
-
self.suggestion_db = self._load_suggestion_database()
|
|
359
|
-
|
|
360
|
-
def generate_suggestions(
|
|
361
|
-
self, analysis: ErrorAnalysis, max_suggestions: int = 5
|
|
362
|
-
) -> list[RecoverySuggestion]:
|
|
363
|
-
"""
|
|
364
|
-
Generate recovery suggestions for an error.
|
|
365
|
-
|
|
366
|
-
Args:
|
|
367
|
-
analysis: Error analysis
|
|
368
|
-
max_suggestions: Maximum number of suggestions to return
|
|
369
|
-
|
|
370
|
-
Returns:
|
|
371
|
-
List of recovery suggestions ranked by confidence
|
|
372
|
-
"""
|
|
373
|
-
suggestions = []
|
|
374
|
-
|
|
375
|
-
# Get suggestions from database
|
|
376
|
-
db_suggestions = self.suggestion_db.get(analysis.error_type.value, [])
|
|
377
|
-
for suggestion_data in db_suggestions:
|
|
378
|
-
confidence = self._calculate_confidence(
|
|
379
|
-
suggestion_data, analysis, self.learning_data
|
|
380
|
-
)
|
|
381
|
-
suggestions.append(
|
|
382
|
-
RecoverySuggestion(
|
|
383
|
-
action=suggestion_data["action"],
|
|
384
|
-
description=suggestion_data["description"],
|
|
385
|
-
confidence=confidence,
|
|
386
|
-
explanation=suggestion_data.get("explanation", ""),
|
|
387
|
-
steps=suggestion_data.get("steps", []),
|
|
388
|
-
requires_manual=suggestion_data.get("requires_manual", False),
|
|
389
|
-
)
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
# Add generic suggestions if no specific ones found
|
|
393
|
-
if not suggestions:
|
|
394
|
-
suggestions.extend(self._generate_generic_suggestions(analysis))
|
|
395
|
-
|
|
396
|
-
# Sort by confidence (highest first)
|
|
397
|
-
suggestions.sort(key=lambda s: s.confidence, reverse=True)
|
|
398
|
-
|
|
399
|
-
return suggestions[:max_suggestions]
|
|
400
|
-
|
|
401
|
-
def _load_suggestion_database(self) -> dict[str, list[dict[str, Any]]]:
|
|
402
|
-
"""Load suggestion database with common errors and fixes."""
|
|
403
|
-
return {
|
|
404
|
-
ErrorType.FILE_NOT_FOUND.value: [
|
|
405
|
-
{
|
|
406
|
-
"action": "Check file path",
|
|
407
|
-
"description": "Verify the file path is correct and the file exists",
|
|
408
|
-
"explanation": "The file may have been moved, deleted, or the path is incorrect",
|
|
409
|
-
"steps": [
|
|
410
|
-
"Check if the file exists at the specified path",
|
|
411
|
-
"Verify file permissions",
|
|
412
|
-
"Check if the path is relative vs absolute",
|
|
413
|
-
],
|
|
414
|
-
"requires_manual": False,
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
"action": "Create missing file",
|
|
418
|
-
"description": "Create the file if it's expected to exist",
|
|
419
|
-
"explanation": "The file may be required but doesn't exist yet",
|
|
420
|
-
"steps": [
|
|
421
|
-
"Check if the file should be created",
|
|
422
|
-
"Create the file with appropriate content",
|
|
423
|
-
"Retry the operation",
|
|
424
|
-
],
|
|
425
|
-
"requires_manual": True,
|
|
426
|
-
},
|
|
427
|
-
],
|
|
428
|
-
ErrorType.PERMISSION_DENIED.value: [
|
|
429
|
-
{
|
|
430
|
-
"action": "Fix file permissions",
|
|
431
|
-
"description": "Check and fix file/directory permissions",
|
|
432
|
-
"explanation": "The operation requires permissions that are not available",
|
|
433
|
-
"steps": [
|
|
434
|
-
"Check file permissions (chmod)",
|
|
435
|
-
"Check directory permissions",
|
|
436
|
-
"Verify user has required access",
|
|
437
|
-
],
|
|
438
|
-
"requires_manual": True,
|
|
439
|
-
},
|
|
440
|
-
],
|
|
441
|
-
ErrorType.CONNECTION_ERROR.value: [
|
|
442
|
-
{
|
|
443
|
-
"action": "Check network connection",
|
|
444
|
-
"description": "Verify network connectivity and service availability",
|
|
445
|
-
"explanation": "The service may be temporarily unavailable",
|
|
446
|
-
"steps": [
|
|
447
|
-
"Check internet connection",
|
|
448
|
-
"Verify service is running",
|
|
449
|
-
"Check firewall settings",
|
|
450
|
-
],
|
|
451
|
-
"requires_manual": False,
|
|
452
|
-
},
|
|
453
|
-
{
|
|
454
|
-
"action": "Retry with backoff",
|
|
455
|
-
"description": "Retry the operation after a short delay",
|
|
456
|
-
"explanation": "Connection errors are often transient",
|
|
457
|
-
"steps": [
|
|
458
|
-
"Wait a few seconds",
|
|
459
|
-
"Retry the operation",
|
|
460
|
-
],
|
|
461
|
-
"requires_manual": False,
|
|
462
|
-
},
|
|
463
|
-
],
|
|
464
|
-
ErrorType.TIMEOUT.value: [
|
|
465
|
-
{
|
|
466
|
-
"action": "Increase timeout",
|
|
467
|
-
"description": "Increase the timeout setting for the operation",
|
|
468
|
-
"explanation": "The operation may need more time to complete",
|
|
469
|
-
"steps": [
|
|
470
|
-
"Check current timeout setting",
|
|
471
|
-
"Increase timeout value",
|
|
472
|
-
"Retry the operation",
|
|
473
|
-
],
|
|
474
|
-
"requires_manual": False,
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
"action": "Optimize operation",
|
|
478
|
-
"description": "Optimize the operation to complete faster",
|
|
479
|
-
"explanation": "The operation may be too slow",
|
|
480
|
-
"steps": [
|
|
481
|
-
"Review operation complexity",
|
|
482
|
-
"Optimize slow parts",
|
|
483
|
-
"Consider breaking into smaller operations",
|
|
484
|
-
],
|
|
485
|
-
"requires_manual": True,
|
|
486
|
-
},
|
|
487
|
-
],
|
|
488
|
-
ErrorType.IMPORT_ERROR.value: [
|
|
489
|
-
{
|
|
490
|
-
"action": "Install missing dependency",
|
|
491
|
-
"description": "Install the required Python package",
|
|
492
|
-
"explanation": "The module is not installed or not in Python path",
|
|
493
|
-
"steps": [
|
|
494
|
-
"Check if package is installed (pip list)",
|
|
495
|
-
"Install missing package (pip install)",
|
|
496
|
-
"Verify Python path includes package location",
|
|
497
|
-
],
|
|
498
|
-
"requires_manual": False,
|
|
499
|
-
},
|
|
500
|
-
],
|
|
501
|
-
ErrorType.SYNTAX_ERROR.value: [
|
|
502
|
-
{
|
|
503
|
-
"action": "Fix syntax error",
|
|
504
|
-
"description": "Review and fix the syntax error in the code",
|
|
505
|
-
"explanation": "There is a syntax error in the code that needs to be fixed",
|
|
506
|
-
"steps": [
|
|
507
|
-
"Check error message for file and line number",
|
|
508
|
-
"Review code at that location",
|
|
509
|
-
"Fix syntax error",
|
|
510
|
-
],
|
|
511
|
-
"requires_manual": True,
|
|
512
|
-
},
|
|
513
|
-
],
|
|
514
|
-
ErrorType.MISSING_CONFIG.value: [
|
|
515
|
-
{
|
|
516
|
-
"action": "Add missing configuration",
|
|
517
|
-
"description": "Add the required configuration value",
|
|
518
|
-
"explanation": "A required configuration value is missing",
|
|
519
|
-
"steps": [
|
|
520
|
-
"Check configuration file",
|
|
521
|
-
"Add missing configuration value",
|
|
522
|
-
"Verify configuration format",
|
|
523
|
-
],
|
|
524
|
-
"requires_manual": True,
|
|
525
|
-
},
|
|
526
|
-
],
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
def _generate_generic_suggestions(
|
|
530
|
-
self, analysis: ErrorAnalysis
|
|
531
|
-
) -> list[RecoverySuggestion]:
|
|
532
|
-
"""Generate generic suggestions when no specific ones are available."""
|
|
533
|
-
suggestions = []
|
|
534
|
-
|
|
535
|
-
if analysis.error_envelope.recoverable:
|
|
536
|
-
suggestions.append(
|
|
537
|
-
RecoverySuggestion(
|
|
538
|
-
action="Retry operation",
|
|
539
|
-
description="The error may be transient, try again",
|
|
540
|
-
confidence=0.5,
|
|
541
|
-
explanation="This error is marked as recoverable",
|
|
542
|
-
steps=["Wait a moment", "Retry the operation"],
|
|
543
|
-
requires_manual=False,
|
|
544
|
-
)
|
|
545
|
-
)
|
|
546
|
-
|
|
547
|
-
suggestions.append(
|
|
548
|
-
RecoverySuggestion(
|
|
549
|
-
action="Check logs",
|
|
550
|
-
description="Review detailed error logs for more information",
|
|
551
|
-
confidence=0.3,
|
|
552
|
-
explanation="Logs may contain additional context about the error",
|
|
553
|
-
steps=[
|
|
554
|
-
"Check workflow logs",
|
|
555
|
-
"Review error details",
|
|
556
|
-
"Look for related errors",
|
|
557
|
-
],
|
|
558
|
-
requires_manual=True,
|
|
559
|
-
)
|
|
560
|
-
)
|
|
561
|
-
|
|
562
|
-
return suggestions
|
|
563
|
-
|
|
564
|
-
def _calculate_confidence(
|
|
565
|
-
self,
|
|
566
|
-
suggestion_data: dict[str, Any],
|
|
567
|
-
analysis: ErrorAnalysis,
|
|
568
|
-
learning_data: dict[str, Any],
|
|
569
|
-
) -> float:
|
|
570
|
-
"""Calculate confidence score for a suggestion."""
|
|
571
|
-
base_confidence = suggestion_data.get("base_confidence", 0.7)
|
|
572
|
-
|
|
573
|
-
# Boost confidence if we've seen this pattern before and suggestion worked
|
|
574
|
-
pattern_key = analysis.pattern_match or analysis.error_type.value
|
|
575
|
-
if pattern_key in learning_data.get("successful_suggestions", {}):
|
|
576
|
-
success_rate = learning_data["successful_suggestions"][pattern_key].get(
|
|
577
|
-
suggestion_data["action"], 0.0
|
|
578
|
-
)
|
|
579
|
-
base_confidence = min(1.0, base_confidence + success_rate * 0.2)
|
|
580
|
-
|
|
581
|
-
return base_confidence
|
|
582
|
-
|
|
583
|
-
def _load_learning_data(self) -> dict[str, Any]:
|
|
584
|
-
"""Load learning data from file."""
|
|
585
|
-
if self.learning_data_path.exists():
|
|
586
|
-
try:
|
|
587
|
-
with open(self.learning_data_path) as f:
|
|
588
|
-
return json.load(f)
|
|
589
|
-
except Exception as e:
|
|
590
|
-
logger.warning(f"Failed to load learning data: {e}")
|
|
591
|
-
return {
|
|
592
|
-
"successful_suggestions": {},
|
|
593
|
-
"error_patterns": {},
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
def record_suggestion_feedback(
|
|
597
|
-
self,
|
|
598
|
-
analysis: ErrorAnalysis,
|
|
599
|
-
suggestion: RecoverySuggestion,
|
|
600
|
-
worked: bool,
|
|
601
|
-
) -> None:
|
|
602
|
-
"""
|
|
603
|
-
Record feedback about whether a suggestion worked.
|
|
604
|
-
|
|
605
|
-
Args:
|
|
606
|
-
analysis: Error analysis
|
|
607
|
-
suggestion: Suggestion that was tried
|
|
608
|
-
worked: Whether the suggestion worked
|
|
609
|
-
"""
|
|
610
|
-
pattern_key = analysis.pattern_match or analysis.error_type.value
|
|
611
|
-
action_key = suggestion.action
|
|
612
|
-
|
|
613
|
-
if "successful_suggestions" not in self.learning_data:
|
|
614
|
-
self.learning_data["successful_suggestions"] = {}
|
|
615
|
-
|
|
616
|
-
if pattern_key not in self.learning_data["successful_suggestions"]:
|
|
617
|
-
self.learning_data["successful_suggestions"][pattern_key] = {}
|
|
618
|
-
|
|
619
|
-
if action_key not in self.learning_data["successful_suggestions"][pattern_key]:
|
|
620
|
-
self.learning_data["successful_suggestions"][pattern_key][action_key] = {
|
|
621
|
-
"attempts": 0,
|
|
622
|
-
"successes": 0,
|
|
623
|
-
"rate": 0.0,
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
stats = self.learning_data["successful_suggestions"][pattern_key][action_key]
|
|
627
|
-
stats["attempts"] += 1
|
|
628
|
-
if worked:
|
|
629
|
-
stats["successes"] += 1
|
|
630
|
-
stats["rate"] = stats["successes"] / stats["attempts"]
|
|
631
|
-
|
|
632
|
-
# Save learning data
|
|
633
|
-
self.learning_data_path.parent.mkdir(parents=True, exist_ok=True)
|
|
634
|
-
with open(self.learning_data_path, "w") as f:
|
|
635
|
-
json.dump(self.learning_data, f, indent=2)
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
class ErrorRecoveryManager:
|
|
639
|
-
"""
|
|
640
|
-
Manages error recovery with suggestions and automatic retry.
|
|
641
|
-
|
|
642
|
-
Epic 14: Stories 14.1-14.5
|
|
643
|
-
"""
|
|
644
|
-
|
|
645
|
-
def __init__(
|
|
646
|
-
self,
|
|
647
|
-
enable_auto_retry: bool = True,
|
|
648
|
-
max_retries: int = 3,
|
|
649
|
-
learning_data_path: Path | None = None,
|
|
650
|
-
):
|
|
651
|
-
"""
|
|
652
|
-
Initialize error recovery manager.
|
|
653
|
-
|
|
654
|
-
Args:
|
|
655
|
-
enable_auto_retry: Whether to enable automatic retry
|
|
656
|
-
max_retries: Maximum retry attempts
|
|
657
|
-
learning_data_path: Path to learning data file
|
|
658
|
-
"""
|
|
659
|
-
self.enable_auto_retry = enable_auto_retry
|
|
660
|
-
self.max_retries = max_retries
|
|
661
|
-
self.analyzer = ErrorAnalyzer()
|
|
662
|
-
self.suggestion_engine = RecoverySuggestionEngine(learning_data_path)
|
|
663
|
-
|
|
664
|
-
def handle_error(
|
|
665
|
-
self,
|
|
666
|
-
error: Exception | ErrorEnvelope | str,
|
|
667
|
-
context: ErrorContext | None = None,
|
|
668
|
-
attempt: int = 1,
|
|
669
|
-
) -> dict[str, Any]:
|
|
670
|
-
"""
|
|
671
|
-
Handle an error with analysis and suggestions.
|
|
672
|
-
|
|
673
|
-
Args:
|
|
674
|
-
error: Error to handle
|
|
675
|
-
context: Error context
|
|
676
|
-
attempt: Current attempt number
|
|
677
|
-
|
|
678
|
-
Returns:
|
|
679
|
-
Dictionary with analysis, suggestions, and recovery plan
|
|
680
|
-
"""
|
|
681
|
-
# Analyze error
|
|
682
|
-
analysis = self.analyzer.analyze(error, context)
|
|
683
|
-
|
|
684
|
-
# Generate suggestions
|
|
685
|
-
suggestions = self.suggestion_engine.generate_suggestions(analysis)
|
|
686
|
-
|
|
687
|
-
# Determine if should retry
|
|
688
|
-
should_retry = self._should_retry(analysis, attempt, suggestions)
|
|
689
|
-
|
|
690
|
-
# Format user-friendly message
|
|
691
|
-
user_message = self._format_user_message(analysis, suggestions)
|
|
692
|
-
|
|
693
|
-
return {
|
|
694
|
-
"analysis": analysis,
|
|
695
|
-
"suggestions": suggestions,
|
|
696
|
-
"should_retry": should_retry,
|
|
697
|
-
"user_message": user_message,
|
|
698
|
-
"retry_after": self._calculate_retry_delay(attempt) if should_retry else None,
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
def _should_retry(
|
|
702
|
-
self,
|
|
703
|
-
analysis: ErrorAnalysis,
|
|
704
|
-
attempt: int,
|
|
705
|
-
suggestions: list[RecoverySuggestion],
|
|
706
|
-
) -> bool:
|
|
707
|
-
"""Determine if error should be retried."""
|
|
708
|
-
if not self.enable_auto_retry:
|
|
709
|
-
return False
|
|
710
|
-
|
|
711
|
-
if attempt >= self.max_retries:
|
|
712
|
-
return False
|
|
713
|
-
|
|
714
|
-
# Don't retry critical errors
|
|
715
|
-
if analysis.severity == ErrorSeverity.CRITICAL:
|
|
716
|
-
return False
|
|
717
|
-
|
|
718
|
-
# Retry if error is recoverable and we have suggestions
|
|
719
|
-
if analysis.error_envelope.recoverable:
|
|
720
|
-
# Check if we have auto-applicable suggestions
|
|
721
|
-
auto_suggestions = [s for s in suggestions if not s.requires_manual]
|
|
722
|
-
if auto_suggestions:
|
|
723
|
-
return True
|
|
724
|
-
|
|
725
|
-
# Retry transient errors
|
|
726
|
-
if analysis.error_type in (
|
|
727
|
-
ErrorType.CONNECTION_ERROR,
|
|
728
|
-
ErrorType.TIMEOUT,
|
|
729
|
-
ErrorType.SERVICE_UNAVAILABLE,
|
|
730
|
-
ErrorType.RATE_LIMIT,
|
|
731
|
-
):
|
|
732
|
-
return True
|
|
733
|
-
|
|
734
|
-
return False
|
|
735
|
-
|
|
736
|
-
def _calculate_retry_delay(self, attempt: int) -> float:
|
|
737
|
-
"""Calculate retry delay with exponential backoff."""
|
|
738
|
-
base_delay = 2.0
|
|
739
|
-
max_delay = 60.0
|
|
740
|
-
delay = min(base_delay * (2 ** (attempt - 1)), max_delay)
|
|
741
|
-
return delay
|
|
742
|
-
|
|
743
|
-
def _format_user_message(
|
|
744
|
-
self,
|
|
745
|
-
analysis: ErrorAnalysis,
|
|
746
|
-
suggestions: list[RecoverySuggestion],
|
|
747
|
-
) -> str:
|
|
748
|
-
"""
|
|
749
|
-
Format user-friendly error message.
|
|
750
|
-
|
|
751
|
-
Epic 14: Story 14.4
|
|
752
|
-
"""
|
|
753
|
-
lines = []
|
|
754
|
-
|
|
755
|
-
# Simplified error message
|
|
756
|
-
error_msg = analysis.error_envelope.message
|
|
757
|
-
# Remove technical jargon
|
|
758
|
-
error_msg = self._simplify_message(error_msg)
|
|
759
|
-
|
|
760
|
-
lines.append(f"**Error:** {error_msg}")
|
|
761
|
-
lines.append("")
|
|
762
|
-
|
|
763
|
-
# Add context
|
|
764
|
-
if analysis.context.step_id:
|
|
765
|
-
lines.append(f"**Step:** {analysis.context.step_id}")
|
|
766
|
-
if analysis.context.agent:
|
|
767
|
-
lines.append(f"**Agent:** {analysis.context.agent}")
|
|
768
|
-
|
|
769
|
-
lines.append("")
|
|
770
|
-
|
|
771
|
-
# Add suggestions
|
|
772
|
-
if suggestions:
|
|
773
|
-
lines.append("**Suggested Actions:**")
|
|
774
|
-
for i, suggestion in enumerate(suggestions[:3], 1):
|
|
775
|
-
lines.append(f"{i}. **{suggestion.action}**")
|
|
776
|
-
lines.append(f" {suggestion.description}")
|
|
777
|
-
if suggestion.explanation:
|
|
778
|
-
lines.append(f" *Why:* {suggestion.explanation}")
|
|
779
|
-
if suggestion.steps:
|
|
780
|
-
lines.append(" *Steps:*")
|
|
781
|
-
for step in suggestion.steps:
|
|
782
|
-
lines.append(f" - {step}")
|
|
783
|
-
lines.append("")
|
|
784
|
-
|
|
785
|
-
return "\n".join(lines)
|
|
786
|
-
|
|
787
|
-
def _simplify_message(self, message: str) -> str:
|
|
788
|
-
"""Simplify error message by removing technical jargon."""
|
|
789
|
-
# Replace common technical terms with simpler ones
|
|
790
|
-
replacements = {
|
|
791
|
-
r"FileNotFoundError": "File not found",
|
|
792
|
-
r"PermissionError": "Permission denied",
|
|
793
|
-
r"ConnectionError": "Connection failed",
|
|
794
|
-
r"TimeoutError": "Operation timed out",
|
|
795
|
-
r"ImportError": "Module not found",
|
|
796
|
-
r"SyntaxError": "Syntax error in code",
|
|
797
|
-
r"ValueError": "Invalid value",
|
|
798
|
-
r"KeyError": "Missing key",
|
|
799
|
-
r"AttributeError": "Attribute not found",
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
for pattern, replacement in replacements.items():
|
|
803
|
-
message = re.sub(pattern, replacement, message, flags=re.IGNORECASE)
|
|
804
|
-
|
|
805
|
-
return message
|
|
806
|
-
|
|
1
|
+
"""
|
|
2
|
+
Error Recovery and Suggestion System
|
|
3
|
+
|
|
4
|
+
Epic 14: Error Recovery and Suggestions
|
|
5
|
+
Provides intelligent error analysis, recovery suggestions, and automatic retry with learning.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
import re
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from enum import Enum
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from ..core.error_envelope import ErrorEnvelope, ErrorEnvelopeBuilder
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ErrorSeverity(Enum):
|
|
25
|
+
"""Error severity levels."""
|
|
26
|
+
|
|
27
|
+
LOW = "low" # Minor issue, workflow can continue
|
|
28
|
+
MEDIUM = "medium" # Moderate issue, may need attention
|
|
29
|
+
HIGH = "high" # Significant issue, workflow may be blocked
|
|
30
|
+
CRITICAL = "critical" # Critical issue, workflow must stop
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ErrorType(Enum):
|
|
34
|
+
"""Detailed error types for better categorization."""
|
|
35
|
+
|
|
36
|
+
# Configuration errors
|
|
37
|
+
MISSING_CONFIG = "missing_config"
|
|
38
|
+
INVALID_CONFIG = "invalid_config"
|
|
39
|
+
ENV_VAR_MISSING = "env_var_missing"
|
|
40
|
+
|
|
41
|
+
# File system errors
|
|
42
|
+
FILE_NOT_FOUND = "file_not_found"
|
|
43
|
+
PERMISSION_DENIED = "permission_denied"
|
|
44
|
+
DISK_FULL = "disk_full"
|
|
45
|
+
PATH_INVALID = "path_invalid"
|
|
46
|
+
|
|
47
|
+
# Network/external errors
|
|
48
|
+
CONNECTION_ERROR = "connection_error"
|
|
49
|
+
TIMEOUT = "timeout"
|
|
50
|
+
SERVICE_UNAVAILABLE = "service_unavailable"
|
|
51
|
+
RATE_LIMIT = "rate_limit"
|
|
52
|
+
|
|
53
|
+
# Validation errors
|
|
54
|
+
INVALID_INPUT = "invalid_input"
|
|
55
|
+
MISSING_REQUIRED = "missing_required"
|
|
56
|
+
TYPE_MISMATCH = "type_mismatch"
|
|
57
|
+
|
|
58
|
+
# Execution errors
|
|
59
|
+
SYNTAX_ERROR = "syntax_error"
|
|
60
|
+
RUNTIME_ERROR = "runtime_error"
|
|
61
|
+
IMPORT_ERROR = "import_error"
|
|
62
|
+
DEPENDENCY_MISSING = "dependency_missing"
|
|
63
|
+
|
|
64
|
+
# Workflow-specific errors
|
|
65
|
+
STEP_FAILED = "step_failed"
|
|
66
|
+
GATE_FAILED = "gate_failed"
|
|
67
|
+
DEPENDENCY_BLOCKED = "dependency_blocked"
|
|
68
|
+
|
|
69
|
+
# Unknown
|
|
70
|
+
UNKNOWN = "unknown"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class ErrorContext:
|
|
75
|
+
"""Context information about when/where an error occurred."""
|
|
76
|
+
|
|
77
|
+
workflow_id: str | None = None
|
|
78
|
+
step_id: str | None = None
|
|
79
|
+
agent: str | None = None
|
|
80
|
+
action: str | None = None
|
|
81
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
82
|
+
step_number: int | None = None
|
|
83
|
+
total_steps: int | None = None
|
|
84
|
+
workflow_status: str | None = None
|
|
85
|
+
recent_changes: list[str] = field(default_factory=list)
|
|
86
|
+
environment: dict[str, Any] = field(default_factory=dict)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass
|
|
90
|
+
class ErrorAnalysis:
|
|
91
|
+
"""Comprehensive error analysis."""
|
|
92
|
+
|
|
93
|
+
error_envelope: ErrorEnvelope
|
|
94
|
+
error_type: ErrorType
|
|
95
|
+
severity: ErrorSeverity
|
|
96
|
+
context: ErrorContext
|
|
97
|
+
pattern_match: str | None = None # Matched error pattern
|
|
98
|
+
similar_errors: list[dict[str, Any]] = field(default_factory=list)
|
|
99
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass
|
|
103
|
+
class RecoverySuggestion:
|
|
104
|
+
"""A recovery suggestion with ranking and explanation."""
|
|
105
|
+
|
|
106
|
+
action: str # What to do
|
|
107
|
+
description: str # Detailed description
|
|
108
|
+
confidence: float # 0.0-1.0 confidence score
|
|
109
|
+
explanation: str # Why this suggestion
|
|
110
|
+
steps: list[str] = field(default_factory=list) # Step-by-step instructions
|
|
111
|
+
requires_manual: bool = False # Whether manual intervention is needed
|
|
112
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class ErrorAnalyzer:
|
|
116
|
+
"""
|
|
117
|
+
Analyzes errors to understand why they occurred and categorize them.
|
|
118
|
+
|
|
119
|
+
Epic 14: Story 14.1
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
def __init__(self):
|
|
123
|
+
"""Initialize error analyzer."""
|
|
124
|
+
self.patterns = self._load_error_patterns()
|
|
125
|
+
|
|
126
|
+
def analyze(
|
|
127
|
+
self,
|
|
128
|
+
error: Exception | ErrorEnvelope | str,
|
|
129
|
+
context: ErrorContext | None = None,
|
|
130
|
+
) -> ErrorAnalysis:
|
|
131
|
+
"""
|
|
132
|
+
Analyze an error and return comprehensive analysis.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
error: Exception, ErrorEnvelope, or error message string
|
|
136
|
+
context: Optional context about when/where error occurred
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
ErrorAnalysis with categorization, severity, and pattern matching
|
|
140
|
+
"""
|
|
141
|
+
# Convert to ErrorEnvelope if needed
|
|
142
|
+
if isinstance(error, ErrorEnvelope):
|
|
143
|
+
envelope = error
|
|
144
|
+
elif isinstance(error, Exception):
|
|
145
|
+
envelope = ErrorEnvelopeBuilder.from_exception(error)
|
|
146
|
+
else:
|
|
147
|
+
# String error message
|
|
148
|
+
envelope = ErrorEnvelope(
|
|
149
|
+
code="unknown_error",
|
|
150
|
+
message=str(error),
|
|
151
|
+
category="execution",
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
# Create context if not provided
|
|
155
|
+
if context is None:
|
|
156
|
+
context = ErrorContext(
|
|
157
|
+
workflow_id=envelope.workflow_id,
|
|
158
|
+
step_id=envelope.step_id,
|
|
159
|
+
agent=envelope.agent,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Determine error type
|
|
163
|
+
error_type = self._determine_error_type(envelope, error if isinstance(error, Exception) else None)
|
|
164
|
+
|
|
165
|
+
# Determine severity
|
|
166
|
+
severity = self._determine_severity(envelope, error_type)
|
|
167
|
+
|
|
168
|
+
# Pattern matching
|
|
169
|
+
pattern_match = self._match_pattern(envelope)
|
|
170
|
+
|
|
171
|
+
# Find similar errors (for learning)
|
|
172
|
+
similar_errors = self._find_similar_errors(envelope, pattern_match)
|
|
173
|
+
|
|
174
|
+
return ErrorAnalysis(
|
|
175
|
+
error_envelope=envelope,
|
|
176
|
+
error_type=error_type,
|
|
177
|
+
severity=severity,
|
|
178
|
+
context=context,
|
|
179
|
+
pattern_match=pattern_match,
|
|
180
|
+
similar_errors=similar_errors,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def _determine_error_type(
|
|
184
|
+
self, envelope: ErrorEnvelope, exc: Exception | None
|
|
185
|
+
) -> ErrorType:
|
|
186
|
+
"""Determine detailed error type."""
|
|
187
|
+
# Check error code first
|
|
188
|
+
code = envelope.code.lower()
|
|
189
|
+
message = envelope.message.lower()
|
|
190
|
+
|
|
191
|
+
# Configuration errors
|
|
192
|
+
if "config" in code or "config" in message:
|
|
193
|
+
if "missing" in message or "not found" in message:
|
|
194
|
+
return ErrorType.MISSING_CONFIG
|
|
195
|
+
return ErrorType.INVALID_CONFIG
|
|
196
|
+
if "env" in code or "environment" in message:
|
|
197
|
+
return ErrorType.ENV_VAR_MISSING
|
|
198
|
+
|
|
199
|
+
# File system errors
|
|
200
|
+
if "file_not_found" in code or "file not found" in message:
|
|
201
|
+
return ErrorType.FILE_NOT_FOUND
|
|
202
|
+
if "permission" in code or "permission" in message:
|
|
203
|
+
return ErrorType.PERMISSION_DENIED
|
|
204
|
+
if "disk full" in message or "no space" in message:
|
|
205
|
+
return ErrorType.DISK_FULL
|
|
206
|
+
if "invalid path" in message or "path not found" in message:
|
|
207
|
+
return ErrorType.PATH_INVALID
|
|
208
|
+
|
|
209
|
+
# Network errors
|
|
210
|
+
if "connection" in code or "connection" in message:
|
|
211
|
+
return ErrorType.CONNECTION_ERROR
|
|
212
|
+
if "timeout" in code or "timeout" in message:
|
|
213
|
+
return ErrorType.TIMEOUT
|
|
214
|
+
if "unavailable" in message or "503" in message:
|
|
215
|
+
return ErrorType.SERVICE_UNAVAILABLE
|
|
216
|
+
if "rate limit" in message or "429" in message:
|
|
217
|
+
return ErrorType.RATE_LIMIT
|
|
218
|
+
|
|
219
|
+
# Validation errors
|
|
220
|
+
if "validation" in code or "invalid" in message:
|
|
221
|
+
if "required" in message or "missing" in message:
|
|
222
|
+
return ErrorType.MISSING_REQUIRED
|
|
223
|
+
if "type" in message:
|
|
224
|
+
return ErrorType.TYPE_MISMATCH
|
|
225
|
+
return ErrorType.INVALID_INPUT
|
|
226
|
+
|
|
227
|
+
# Execution errors
|
|
228
|
+
if exc:
|
|
229
|
+
if isinstance(exc, SyntaxError):
|
|
230
|
+
return ErrorType.SYNTAX_ERROR
|
|
231
|
+
if isinstance(exc, ImportError):
|
|
232
|
+
return ErrorType.IMPORT_ERROR
|
|
233
|
+
if isinstance(exc, RuntimeError):
|
|
234
|
+
return ErrorType.RUNTIME_ERROR
|
|
235
|
+
|
|
236
|
+
if "import" in message or "module not found" in message:
|
|
237
|
+
return ErrorType.IMPORT_ERROR
|
|
238
|
+
if "dependency" in message or "package not found" in message:
|
|
239
|
+
return ErrorType.DEPENDENCY_MISSING
|
|
240
|
+
if "syntax" in message:
|
|
241
|
+
return ErrorType.SYNTAX_ERROR
|
|
242
|
+
|
|
243
|
+
# Workflow-specific
|
|
244
|
+
if "step" in code and "failed" in message:
|
|
245
|
+
return ErrorType.STEP_FAILED
|
|
246
|
+
if "gate" in code or "gate" in message:
|
|
247
|
+
return ErrorType.GATE_FAILED
|
|
248
|
+
if "dependency" in code and "blocked" in message:
|
|
249
|
+
return ErrorType.DEPENDENCY_BLOCKED
|
|
250
|
+
|
|
251
|
+
return ErrorType.UNKNOWN
|
|
252
|
+
|
|
253
|
+
def _determine_severity(
|
|
254
|
+
self, envelope: ErrorEnvelope, error_type: ErrorType
|
|
255
|
+
) -> ErrorSeverity:
|
|
256
|
+
"""Determine error severity."""
|
|
257
|
+
# Critical errors
|
|
258
|
+
if error_type in (
|
|
259
|
+
ErrorType.DISK_FULL,
|
|
260
|
+
ErrorType.DEPENDENCY_BLOCKED,
|
|
261
|
+
):
|
|
262
|
+
return ErrorSeverity.CRITICAL
|
|
263
|
+
|
|
264
|
+
# High severity
|
|
265
|
+
if error_type in (
|
|
266
|
+
ErrorType.SYNTAX_ERROR,
|
|
267
|
+
ErrorType.IMPORT_ERROR,
|
|
268
|
+
ErrorType.STEP_FAILED,
|
|
269
|
+
ErrorType.GATE_FAILED,
|
|
270
|
+
):
|
|
271
|
+
return ErrorSeverity.HIGH
|
|
272
|
+
|
|
273
|
+
# Medium severity
|
|
274
|
+
if error_type in (
|
|
275
|
+
ErrorType.CONNECTION_ERROR,
|
|
276
|
+
ErrorType.SERVICE_UNAVAILABLE,
|
|
277
|
+
ErrorType.TIMEOUT,
|
|
278
|
+
ErrorType.INVALID_CONFIG,
|
|
279
|
+
):
|
|
280
|
+
return ErrorSeverity.MEDIUM
|
|
281
|
+
|
|
282
|
+
# Low severity (often recoverable)
|
|
283
|
+
if error_type in (
|
|
284
|
+
ErrorType.RATE_LIMIT,
|
|
285
|
+
ErrorType.TIMEOUT,
|
|
286
|
+
ErrorType.FILE_NOT_FOUND,
|
|
287
|
+
ErrorType.PERMISSION_DENIED,
|
|
288
|
+
) and envelope.recoverable:
|
|
289
|
+
return ErrorSeverity.LOW
|
|
290
|
+
|
|
291
|
+
return ErrorSeverity.MEDIUM
|
|
292
|
+
|
|
293
|
+
def _load_error_patterns(self) -> dict[str, dict[str, Any]]:
|
|
294
|
+
"""Load error patterns for matching."""
|
|
295
|
+
# Common error patterns with regex
|
|
296
|
+
return {
|
|
297
|
+
"file_not_found": {
|
|
298
|
+
"pattern": r"file.*not found|no such file|file does not exist",
|
|
299
|
+
"type": ErrorType.FILE_NOT_FOUND,
|
|
300
|
+
},
|
|
301
|
+
"permission_denied": {
|
|
302
|
+
"pattern": r"permission denied|access denied|permission error",
|
|
303
|
+
"type": ErrorType.PERMISSION_DENIED,
|
|
304
|
+
},
|
|
305
|
+
"connection_error": {
|
|
306
|
+
"pattern": r"connection.*refused|connection.*failed|could not connect",
|
|
307
|
+
"type": ErrorType.CONNECTION_ERROR,
|
|
308
|
+
},
|
|
309
|
+
"timeout": {
|
|
310
|
+
"pattern": r"timeout|timed out|operation.*too long",
|
|
311
|
+
"type": ErrorType.TIMEOUT,
|
|
312
|
+
},
|
|
313
|
+
"import_error": {
|
|
314
|
+
"pattern": r"no module named|import.*error|cannot import",
|
|
315
|
+
"type": ErrorType.IMPORT_ERROR,
|
|
316
|
+
},
|
|
317
|
+
"syntax_error": {
|
|
318
|
+
"pattern": r"syntax error|invalid syntax|parse error",
|
|
319
|
+
"type": ErrorType.SYNTAX_ERROR,
|
|
320
|
+
},
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
def _match_pattern(self, envelope: ErrorEnvelope) -> str | None:
|
|
324
|
+
"""Match error against known patterns."""
|
|
325
|
+
message = envelope.message.lower()
|
|
326
|
+
for pattern_name, pattern_info in self.patterns.items():
|
|
327
|
+
if re.search(pattern_info["pattern"], message, re.IGNORECASE):
|
|
328
|
+
return pattern_name
|
|
329
|
+
return None
|
|
330
|
+
|
|
331
|
+
def _find_similar_errors(
|
|
332
|
+
self, envelope: ErrorEnvelope, pattern: str | None
|
|
333
|
+
) -> list[dict[str, Any]]:
|
|
334
|
+
"""Find similar errors from history (for learning)."""
|
|
335
|
+
# This would query error history database
|
|
336
|
+
# For now, return empty list
|
|
337
|
+
return []
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class RecoverySuggestionEngine:
|
|
341
|
+
"""
|
|
342
|
+
Generates recovery suggestions based on error analysis.
|
|
343
|
+
|
|
344
|
+
Epic 14: Story 14.2
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
def __init__(self, learning_data_path: Path | None = None):
|
|
348
|
+
"""
|
|
349
|
+
Initialize recovery suggestion engine.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
learning_data_path: Path to learning data file
|
|
353
|
+
"""
|
|
354
|
+
self.learning_data_path = learning_data_path or Path(
|
|
355
|
+
".tapps-agents/error_learning.json"
|
|
356
|
+
)
|
|
357
|
+
self.learning_data = self._load_learning_data()
|
|
358
|
+
self.suggestion_db = self._load_suggestion_database()
|
|
359
|
+
|
|
360
|
+
def generate_suggestions(
|
|
361
|
+
self, analysis: ErrorAnalysis, max_suggestions: int = 5
|
|
362
|
+
) -> list[RecoverySuggestion]:
|
|
363
|
+
"""
|
|
364
|
+
Generate recovery suggestions for an error.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
analysis: Error analysis
|
|
368
|
+
max_suggestions: Maximum number of suggestions to return
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
List of recovery suggestions ranked by confidence
|
|
372
|
+
"""
|
|
373
|
+
suggestions = []
|
|
374
|
+
|
|
375
|
+
# Get suggestions from database
|
|
376
|
+
db_suggestions = self.suggestion_db.get(analysis.error_type.value, [])
|
|
377
|
+
for suggestion_data in db_suggestions:
|
|
378
|
+
confidence = self._calculate_confidence(
|
|
379
|
+
suggestion_data, analysis, self.learning_data
|
|
380
|
+
)
|
|
381
|
+
suggestions.append(
|
|
382
|
+
RecoverySuggestion(
|
|
383
|
+
action=suggestion_data["action"],
|
|
384
|
+
description=suggestion_data["description"],
|
|
385
|
+
confidence=confidence,
|
|
386
|
+
explanation=suggestion_data.get("explanation", ""),
|
|
387
|
+
steps=suggestion_data.get("steps", []),
|
|
388
|
+
requires_manual=suggestion_data.get("requires_manual", False),
|
|
389
|
+
)
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
# Add generic suggestions if no specific ones found
|
|
393
|
+
if not suggestions:
|
|
394
|
+
suggestions.extend(self._generate_generic_suggestions(analysis))
|
|
395
|
+
|
|
396
|
+
# Sort by confidence (highest first)
|
|
397
|
+
suggestions.sort(key=lambda s: s.confidence, reverse=True)
|
|
398
|
+
|
|
399
|
+
return suggestions[:max_suggestions]
|
|
400
|
+
|
|
401
|
+
def _load_suggestion_database(self) -> dict[str, list[dict[str, Any]]]:
|
|
402
|
+
"""Load suggestion database with common errors and fixes."""
|
|
403
|
+
return {
|
|
404
|
+
ErrorType.FILE_NOT_FOUND.value: [
|
|
405
|
+
{
|
|
406
|
+
"action": "Check file path",
|
|
407
|
+
"description": "Verify the file path is correct and the file exists",
|
|
408
|
+
"explanation": "The file may have been moved, deleted, or the path is incorrect",
|
|
409
|
+
"steps": [
|
|
410
|
+
"Check if the file exists at the specified path",
|
|
411
|
+
"Verify file permissions",
|
|
412
|
+
"Check if the path is relative vs absolute",
|
|
413
|
+
],
|
|
414
|
+
"requires_manual": False,
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"action": "Create missing file",
|
|
418
|
+
"description": "Create the file if it's expected to exist",
|
|
419
|
+
"explanation": "The file may be required but doesn't exist yet",
|
|
420
|
+
"steps": [
|
|
421
|
+
"Check if the file should be created",
|
|
422
|
+
"Create the file with appropriate content",
|
|
423
|
+
"Retry the operation",
|
|
424
|
+
],
|
|
425
|
+
"requires_manual": True,
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
ErrorType.PERMISSION_DENIED.value: [
|
|
429
|
+
{
|
|
430
|
+
"action": "Fix file permissions",
|
|
431
|
+
"description": "Check and fix file/directory permissions",
|
|
432
|
+
"explanation": "The operation requires permissions that are not available",
|
|
433
|
+
"steps": [
|
|
434
|
+
"Check file permissions (chmod)",
|
|
435
|
+
"Check directory permissions",
|
|
436
|
+
"Verify user has required access",
|
|
437
|
+
],
|
|
438
|
+
"requires_manual": True,
|
|
439
|
+
},
|
|
440
|
+
],
|
|
441
|
+
ErrorType.CONNECTION_ERROR.value: [
|
|
442
|
+
{
|
|
443
|
+
"action": "Check network connection",
|
|
444
|
+
"description": "Verify network connectivity and service availability",
|
|
445
|
+
"explanation": "The service may be temporarily unavailable",
|
|
446
|
+
"steps": [
|
|
447
|
+
"Check internet connection",
|
|
448
|
+
"Verify service is running",
|
|
449
|
+
"Check firewall settings",
|
|
450
|
+
],
|
|
451
|
+
"requires_manual": False,
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"action": "Retry with backoff",
|
|
455
|
+
"description": "Retry the operation after a short delay",
|
|
456
|
+
"explanation": "Connection errors are often transient",
|
|
457
|
+
"steps": [
|
|
458
|
+
"Wait a few seconds",
|
|
459
|
+
"Retry the operation",
|
|
460
|
+
],
|
|
461
|
+
"requires_manual": False,
|
|
462
|
+
},
|
|
463
|
+
],
|
|
464
|
+
ErrorType.TIMEOUT.value: [
|
|
465
|
+
{
|
|
466
|
+
"action": "Increase timeout",
|
|
467
|
+
"description": "Increase the timeout setting for the operation",
|
|
468
|
+
"explanation": "The operation may need more time to complete",
|
|
469
|
+
"steps": [
|
|
470
|
+
"Check current timeout setting",
|
|
471
|
+
"Increase timeout value",
|
|
472
|
+
"Retry the operation",
|
|
473
|
+
],
|
|
474
|
+
"requires_manual": False,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"action": "Optimize operation",
|
|
478
|
+
"description": "Optimize the operation to complete faster",
|
|
479
|
+
"explanation": "The operation may be too slow",
|
|
480
|
+
"steps": [
|
|
481
|
+
"Review operation complexity",
|
|
482
|
+
"Optimize slow parts",
|
|
483
|
+
"Consider breaking into smaller operations",
|
|
484
|
+
],
|
|
485
|
+
"requires_manual": True,
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
ErrorType.IMPORT_ERROR.value: [
|
|
489
|
+
{
|
|
490
|
+
"action": "Install missing dependency",
|
|
491
|
+
"description": "Install the required Python package",
|
|
492
|
+
"explanation": "The module is not installed or not in Python path",
|
|
493
|
+
"steps": [
|
|
494
|
+
"Check if package is installed (pip list)",
|
|
495
|
+
"Install missing package (pip install)",
|
|
496
|
+
"Verify Python path includes package location",
|
|
497
|
+
],
|
|
498
|
+
"requires_manual": False,
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
ErrorType.SYNTAX_ERROR.value: [
|
|
502
|
+
{
|
|
503
|
+
"action": "Fix syntax error",
|
|
504
|
+
"description": "Review and fix the syntax error in the code",
|
|
505
|
+
"explanation": "There is a syntax error in the code that needs to be fixed",
|
|
506
|
+
"steps": [
|
|
507
|
+
"Check error message for file and line number",
|
|
508
|
+
"Review code at that location",
|
|
509
|
+
"Fix syntax error",
|
|
510
|
+
],
|
|
511
|
+
"requires_manual": True,
|
|
512
|
+
},
|
|
513
|
+
],
|
|
514
|
+
ErrorType.MISSING_CONFIG.value: [
|
|
515
|
+
{
|
|
516
|
+
"action": "Add missing configuration",
|
|
517
|
+
"description": "Add the required configuration value",
|
|
518
|
+
"explanation": "A required configuration value is missing",
|
|
519
|
+
"steps": [
|
|
520
|
+
"Check configuration file",
|
|
521
|
+
"Add missing configuration value",
|
|
522
|
+
"Verify configuration format",
|
|
523
|
+
],
|
|
524
|
+
"requires_manual": True,
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
def _generate_generic_suggestions(
|
|
530
|
+
self, analysis: ErrorAnalysis
|
|
531
|
+
) -> list[RecoverySuggestion]:
|
|
532
|
+
"""Generate generic suggestions when no specific ones are available."""
|
|
533
|
+
suggestions = []
|
|
534
|
+
|
|
535
|
+
if analysis.error_envelope.recoverable:
|
|
536
|
+
suggestions.append(
|
|
537
|
+
RecoverySuggestion(
|
|
538
|
+
action="Retry operation",
|
|
539
|
+
description="The error may be transient, try again",
|
|
540
|
+
confidence=0.5,
|
|
541
|
+
explanation="This error is marked as recoverable",
|
|
542
|
+
steps=["Wait a moment", "Retry the operation"],
|
|
543
|
+
requires_manual=False,
|
|
544
|
+
)
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
suggestions.append(
|
|
548
|
+
RecoverySuggestion(
|
|
549
|
+
action="Check logs",
|
|
550
|
+
description="Review detailed error logs for more information",
|
|
551
|
+
confidence=0.3,
|
|
552
|
+
explanation="Logs may contain additional context about the error",
|
|
553
|
+
steps=[
|
|
554
|
+
"Check workflow logs",
|
|
555
|
+
"Review error details",
|
|
556
|
+
"Look for related errors",
|
|
557
|
+
],
|
|
558
|
+
requires_manual=True,
|
|
559
|
+
)
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
return suggestions
|
|
563
|
+
|
|
564
|
+
def _calculate_confidence(
|
|
565
|
+
self,
|
|
566
|
+
suggestion_data: dict[str, Any],
|
|
567
|
+
analysis: ErrorAnalysis,
|
|
568
|
+
learning_data: dict[str, Any],
|
|
569
|
+
) -> float:
|
|
570
|
+
"""Calculate confidence score for a suggestion."""
|
|
571
|
+
base_confidence = suggestion_data.get("base_confidence", 0.7)
|
|
572
|
+
|
|
573
|
+
# Boost confidence if we've seen this pattern before and suggestion worked
|
|
574
|
+
pattern_key = analysis.pattern_match or analysis.error_type.value
|
|
575
|
+
if pattern_key in learning_data.get("successful_suggestions", {}):
|
|
576
|
+
success_rate = learning_data["successful_suggestions"][pattern_key].get(
|
|
577
|
+
suggestion_data["action"], 0.0
|
|
578
|
+
)
|
|
579
|
+
base_confidence = min(1.0, base_confidence + success_rate * 0.2)
|
|
580
|
+
|
|
581
|
+
return base_confidence
|
|
582
|
+
|
|
583
|
+
def _load_learning_data(self) -> dict[str, Any]:
|
|
584
|
+
"""Load learning data from file."""
|
|
585
|
+
if self.learning_data_path.exists():
|
|
586
|
+
try:
|
|
587
|
+
with open(self.learning_data_path) as f:
|
|
588
|
+
return json.load(f)
|
|
589
|
+
except Exception as e:
|
|
590
|
+
logger.warning(f"Failed to load learning data: {e}")
|
|
591
|
+
return {
|
|
592
|
+
"successful_suggestions": {},
|
|
593
|
+
"error_patterns": {},
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
def record_suggestion_feedback(
|
|
597
|
+
self,
|
|
598
|
+
analysis: ErrorAnalysis,
|
|
599
|
+
suggestion: RecoverySuggestion,
|
|
600
|
+
worked: bool,
|
|
601
|
+
) -> None:
|
|
602
|
+
"""
|
|
603
|
+
Record feedback about whether a suggestion worked.
|
|
604
|
+
|
|
605
|
+
Args:
|
|
606
|
+
analysis: Error analysis
|
|
607
|
+
suggestion: Suggestion that was tried
|
|
608
|
+
worked: Whether the suggestion worked
|
|
609
|
+
"""
|
|
610
|
+
pattern_key = analysis.pattern_match or analysis.error_type.value
|
|
611
|
+
action_key = suggestion.action
|
|
612
|
+
|
|
613
|
+
if "successful_suggestions" not in self.learning_data:
|
|
614
|
+
self.learning_data["successful_suggestions"] = {}
|
|
615
|
+
|
|
616
|
+
if pattern_key not in self.learning_data["successful_suggestions"]:
|
|
617
|
+
self.learning_data["successful_suggestions"][pattern_key] = {}
|
|
618
|
+
|
|
619
|
+
if action_key not in self.learning_data["successful_suggestions"][pattern_key]:
|
|
620
|
+
self.learning_data["successful_suggestions"][pattern_key][action_key] = {
|
|
621
|
+
"attempts": 0,
|
|
622
|
+
"successes": 0,
|
|
623
|
+
"rate": 0.0,
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
stats = self.learning_data["successful_suggestions"][pattern_key][action_key]
|
|
627
|
+
stats["attempts"] += 1
|
|
628
|
+
if worked:
|
|
629
|
+
stats["successes"] += 1
|
|
630
|
+
stats["rate"] = stats["successes"] / stats["attempts"]
|
|
631
|
+
|
|
632
|
+
# Save learning data
|
|
633
|
+
self.learning_data_path.parent.mkdir(parents=True, exist_ok=True)
|
|
634
|
+
with open(self.learning_data_path, "w") as f:
|
|
635
|
+
json.dump(self.learning_data, f, indent=2)
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
class ErrorRecoveryManager:
|
|
639
|
+
"""
|
|
640
|
+
Manages error recovery with suggestions and automatic retry.
|
|
641
|
+
|
|
642
|
+
Epic 14: Stories 14.1-14.5
|
|
643
|
+
"""
|
|
644
|
+
|
|
645
|
+
def __init__(
|
|
646
|
+
self,
|
|
647
|
+
enable_auto_retry: bool = True,
|
|
648
|
+
max_retries: int = 3,
|
|
649
|
+
learning_data_path: Path | None = None,
|
|
650
|
+
):
|
|
651
|
+
"""
|
|
652
|
+
Initialize error recovery manager.
|
|
653
|
+
|
|
654
|
+
Args:
|
|
655
|
+
enable_auto_retry: Whether to enable automatic retry
|
|
656
|
+
max_retries: Maximum retry attempts
|
|
657
|
+
learning_data_path: Path to learning data file
|
|
658
|
+
"""
|
|
659
|
+
self.enable_auto_retry = enable_auto_retry
|
|
660
|
+
self.max_retries = max_retries
|
|
661
|
+
self.analyzer = ErrorAnalyzer()
|
|
662
|
+
self.suggestion_engine = RecoverySuggestionEngine(learning_data_path)
|
|
663
|
+
|
|
664
|
+
def handle_error(
|
|
665
|
+
self,
|
|
666
|
+
error: Exception | ErrorEnvelope | str,
|
|
667
|
+
context: ErrorContext | None = None,
|
|
668
|
+
attempt: int = 1,
|
|
669
|
+
) -> dict[str, Any]:
|
|
670
|
+
"""
|
|
671
|
+
Handle an error with analysis and suggestions.
|
|
672
|
+
|
|
673
|
+
Args:
|
|
674
|
+
error: Error to handle
|
|
675
|
+
context: Error context
|
|
676
|
+
attempt: Current attempt number
|
|
677
|
+
|
|
678
|
+
Returns:
|
|
679
|
+
Dictionary with analysis, suggestions, and recovery plan
|
|
680
|
+
"""
|
|
681
|
+
# Analyze error
|
|
682
|
+
analysis = self.analyzer.analyze(error, context)
|
|
683
|
+
|
|
684
|
+
# Generate suggestions
|
|
685
|
+
suggestions = self.suggestion_engine.generate_suggestions(analysis)
|
|
686
|
+
|
|
687
|
+
# Determine if should retry
|
|
688
|
+
should_retry = self._should_retry(analysis, attempt, suggestions)
|
|
689
|
+
|
|
690
|
+
# Format user-friendly message
|
|
691
|
+
user_message = self._format_user_message(analysis, suggestions)
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
"analysis": analysis,
|
|
695
|
+
"suggestions": suggestions,
|
|
696
|
+
"should_retry": should_retry,
|
|
697
|
+
"user_message": user_message,
|
|
698
|
+
"retry_after": self._calculate_retry_delay(attempt) if should_retry else None,
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
def _should_retry(
|
|
702
|
+
self,
|
|
703
|
+
analysis: ErrorAnalysis,
|
|
704
|
+
attempt: int,
|
|
705
|
+
suggestions: list[RecoverySuggestion],
|
|
706
|
+
) -> bool:
|
|
707
|
+
"""Determine if error should be retried."""
|
|
708
|
+
if not self.enable_auto_retry:
|
|
709
|
+
return False
|
|
710
|
+
|
|
711
|
+
if attempt >= self.max_retries:
|
|
712
|
+
return False
|
|
713
|
+
|
|
714
|
+
# Don't retry critical errors
|
|
715
|
+
if analysis.severity == ErrorSeverity.CRITICAL:
|
|
716
|
+
return False
|
|
717
|
+
|
|
718
|
+
# Retry if error is recoverable and we have suggestions
|
|
719
|
+
if analysis.error_envelope.recoverable:
|
|
720
|
+
# Check if we have auto-applicable suggestions
|
|
721
|
+
auto_suggestions = [s for s in suggestions if not s.requires_manual]
|
|
722
|
+
if auto_suggestions:
|
|
723
|
+
return True
|
|
724
|
+
|
|
725
|
+
# Retry transient errors
|
|
726
|
+
if analysis.error_type in (
|
|
727
|
+
ErrorType.CONNECTION_ERROR,
|
|
728
|
+
ErrorType.TIMEOUT,
|
|
729
|
+
ErrorType.SERVICE_UNAVAILABLE,
|
|
730
|
+
ErrorType.RATE_LIMIT,
|
|
731
|
+
):
|
|
732
|
+
return True
|
|
733
|
+
|
|
734
|
+
return False
|
|
735
|
+
|
|
736
|
+
def _calculate_retry_delay(self, attempt: int) -> float:
|
|
737
|
+
"""Calculate retry delay with exponential backoff."""
|
|
738
|
+
base_delay = 2.0
|
|
739
|
+
max_delay = 60.0
|
|
740
|
+
delay = min(base_delay * (2 ** (attempt - 1)), max_delay)
|
|
741
|
+
return delay
|
|
742
|
+
|
|
743
|
+
def _format_user_message(
|
|
744
|
+
self,
|
|
745
|
+
analysis: ErrorAnalysis,
|
|
746
|
+
suggestions: list[RecoverySuggestion],
|
|
747
|
+
) -> str:
|
|
748
|
+
"""
|
|
749
|
+
Format user-friendly error message.
|
|
750
|
+
|
|
751
|
+
Epic 14: Story 14.4
|
|
752
|
+
"""
|
|
753
|
+
lines = []
|
|
754
|
+
|
|
755
|
+
# Simplified error message
|
|
756
|
+
error_msg = analysis.error_envelope.message
|
|
757
|
+
# Remove technical jargon
|
|
758
|
+
error_msg = self._simplify_message(error_msg)
|
|
759
|
+
|
|
760
|
+
lines.append(f"**Error:** {error_msg}")
|
|
761
|
+
lines.append("")
|
|
762
|
+
|
|
763
|
+
# Add context
|
|
764
|
+
if analysis.context.step_id:
|
|
765
|
+
lines.append(f"**Step:** {analysis.context.step_id}")
|
|
766
|
+
if analysis.context.agent:
|
|
767
|
+
lines.append(f"**Agent:** {analysis.context.agent}")
|
|
768
|
+
|
|
769
|
+
lines.append("")
|
|
770
|
+
|
|
771
|
+
# Add suggestions
|
|
772
|
+
if suggestions:
|
|
773
|
+
lines.append("**Suggested Actions:**")
|
|
774
|
+
for i, suggestion in enumerate(suggestions[:3], 1):
|
|
775
|
+
lines.append(f"{i}. **{suggestion.action}**")
|
|
776
|
+
lines.append(f" {suggestion.description}")
|
|
777
|
+
if suggestion.explanation:
|
|
778
|
+
lines.append(f" *Why:* {suggestion.explanation}")
|
|
779
|
+
if suggestion.steps:
|
|
780
|
+
lines.append(" *Steps:*")
|
|
781
|
+
for step in suggestion.steps:
|
|
782
|
+
lines.append(f" - {step}")
|
|
783
|
+
lines.append("")
|
|
784
|
+
|
|
785
|
+
return "\n".join(lines)
|
|
786
|
+
|
|
787
|
+
def _simplify_message(self, message: str) -> str:
|
|
788
|
+
"""Simplify error message by removing technical jargon."""
|
|
789
|
+
# Replace common technical terms with simpler ones
|
|
790
|
+
replacements = {
|
|
791
|
+
r"FileNotFoundError": "File not found",
|
|
792
|
+
r"PermissionError": "Permission denied",
|
|
793
|
+
r"ConnectionError": "Connection failed",
|
|
794
|
+
r"TimeoutError": "Operation timed out",
|
|
795
|
+
r"ImportError": "Module not found",
|
|
796
|
+
r"SyntaxError": "Syntax error in code",
|
|
797
|
+
r"ValueError": "Invalid value",
|
|
798
|
+
r"KeyError": "Missing key",
|
|
799
|
+
r"AttributeError": "Attribute not found",
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
for pattern, replacement in replacements.items():
|
|
803
|
+
message = re.sub(pattern, replacement, message, flags=re.IGNORECASE)
|
|
804
|
+
|
|
805
|
+
return message
|
|
806
|
+
|