tapps-agents 3.6.0__py3-none-any.whl → 3.6.1__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/service_discovery.py +534 -534
- 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/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 -227
- tapps_agents/cli/commands/tester.py +191 -191
- 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/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/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.backup_20260204_064058.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064256.py +324 -0
- tapps_agents/health/checks/outcomes.backup_20260204_064600.py +324 -0
- 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/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/resources/__init__.py +5 -0
- tapps_agents/resources/claude/__init__.py +1 -0
- tapps_agents/resources/claude/commands/README.md +156 -0
- tapps_agents/resources/claude/commands/__init__.py +1 -0
- tapps_agents/resources/claude/commands/build-fix.md +22 -0
- tapps_agents/resources/claude/commands/build.md +77 -0
- tapps_agents/resources/claude/commands/debug.md +53 -0
- tapps_agents/resources/claude/commands/design.md +68 -0
- tapps_agents/resources/claude/commands/docs.md +53 -0
- tapps_agents/resources/claude/commands/e2e.md +22 -0
- tapps_agents/resources/claude/commands/fix.md +54 -0
- tapps_agents/resources/claude/commands/implement.md +53 -0
- tapps_agents/resources/claude/commands/improve.md +53 -0
- tapps_agents/resources/claude/commands/library-docs.md +64 -0
- tapps_agents/resources/claude/commands/lint.md +52 -0
- tapps_agents/resources/claude/commands/plan.md +65 -0
- tapps_agents/resources/claude/commands/refactor-clean.md +21 -0
- tapps_agents/resources/claude/commands/refactor.md +55 -0
- tapps_agents/resources/claude/commands/review.md +67 -0
- tapps_agents/resources/claude/commands/score.md +60 -0
- tapps_agents/resources/claude/commands/security-review.md +22 -0
- tapps_agents/resources/claude/commands/security-scan.md +54 -0
- tapps_agents/resources/claude/commands/tdd.md +24 -0
- tapps_agents/resources/claude/commands/test-coverage.md +21 -0
- tapps_agents/resources/claude/commands/test.md +54 -0
- tapps_agents/resources/claude/commands/update-codemaps.md +20 -0
- tapps_agents/resources/claude/commands/update-docs.md +21 -0
- tapps_agents/resources/claude/skills/__init__.py +1 -0
- tapps_agents/resources/claude/skills/analyst/SKILL.md +272 -0
- tapps_agents/resources/claude/skills/analyst/__init__.py +1 -0
- tapps_agents/resources/claude/skills/architect/SKILL.md +282 -0
- tapps_agents/resources/claude/skills/architect/__init__.py +1 -0
- tapps_agents/resources/claude/skills/backend-patterns/SKILL.md +30 -0
- tapps_agents/resources/claude/skills/backend-patterns/__init__.py +1 -0
- tapps_agents/resources/claude/skills/coding-standards/SKILL.md +29 -0
- tapps_agents/resources/claude/skills/coding-standards/__init__.py +1 -0
- tapps_agents/resources/claude/skills/debugger/SKILL.md +203 -0
- tapps_agents/resources/claude/skills/debugger/__init__.py +1 -0
- tapps_agents/resources/claude/skills/designer/SKILL.md +243 -0
- tapps_agents/resources/claude/skills/designer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/documenter/SKILL.md +252 -0
- tapps_agents/resources/claude/skills/documenter/__init__.py +1 -0
- tapps_agents/resources/claude/skills/enhancer/SKILL.md +307 -0
- tapps_agents/resources/claude/skills/enhancer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/evaluator/SKILL.md +204 -0
- tapps_agents/resources/claude/skills/evaluator/__init__.py +1 -0
- tapps_agents/resources/claude/skills/frontend-patterns/SKILL.md +29 -0
- tapps_agents/resources/claude/skills/frontend-patterns/__init__.py +1 -0
- tapps_agents/resources/claude/skills/implementer/SKILL.md +188 -0
- tapps_agents/resources/claude/skills/implementer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/improver/SKILL.md +218 -0
- tapps_agents/resources/claude/skills/improver/__init__.py +1 -0
- tapps_agents/resources/claude/skills/ops/SKILL.md +281 -0
- tapps_agents/resources/claude/skills/ops/__init__.py +1 -0
- tapps_agents/resources/claude/skills/orchestrator/SKILL.md +390 -0
- tapps_agents/resources/claude/skills/orchestrator/__init__.py +1 -0
- tapps_agents/resources/claude/skills/planner/SKILL.md +254 -0
- tapps_agents/resources/claude/skills/planner/__init__.py +1 -0
- tapps_agents/resources/claude/skills/reviewer/SKILL.md +434 -0
- tapps_agents/resources/claude/skills/reviewer/__init__.py +1 -0
- tapps_agents/resources/claude/skills/security-review/SKILL.md +31 -0
- tapps_agents/resources/claude/skills/security-review/__init__.py +1 -0
- tapps_agents/resources/claude/skills/simple-mode/SKILL.md +695 -0
- tapps_agents/resources/claude/skills/simple-mode/__init__.py +1 -0
- tapps_agents/resources/claude/skills/tester/SKILL.md +219 -0
- tapps_agents/resources/claude/skills/tester/__init__.py +1 -0
- tapps_agents/resources/cursor/.cursorignore +35 -0
- tapps_agents/resources/cursor/__init__.py +1 -0
- tapps_agents/resources/cursor/commands/__init__.py +1 -0
- tapps_agents/resources/cursor/commands/build-fix.md +11 -0
- tapps_agents/resources/cursor/commands/build.md +11 -0
- tapps_agents/resources/cursor/commands/e2e.md +11 -0
- tapps_agents/resources/cursor/commands/fix.md +11 -0
- tapps_agents/resources/cursor/commands/refactor-clean.md +11 -0
- tapps_agents/resources/cursor/commands/review.md +11 -0
- tapps_agents/resources/cursor/commands/security-review.md +11 -0
- tapps_agents/resources/cursor/commands/tdd.md +11 -0
- tapps_agents/resources/cursor/commands/test-coverage.md +11 -0
- tapps_agents/resources/cursor/commands/test.md +11 -0
- tapps_agents/resources/cursor/commands/update-codemaps.md +10 -0
- tapps_agents/resources/cursor/commands/update-docs.md +11 -0
- tapps_agents/resources/cursor/rules/__init__.py +1 -0
- tapps_agents/resources/cursor/rules/agent-capabilities.mdc +687 -0
- tapps_agents/resources/cursor/rules/coding-style.mdc +31 -0
- tapps_agents/resources/cursor/rules/command-reference.mdc +2081 -0
- tapps_agents/resources/cursor/rules/cursor-mode-usage.mdc +125 -0
- tapps_agents/resources/cursor/rules/git-workflow.mdc +29 -0
- tapps_agents/resources/cursor/rules/performance.mdc +29 -0
- tapps_agents/resources/cursor/rules/project-context.mdc +163 -0
- tapps_agents/resources/cursor/rules/project-profiling.mdc +197 -0
- tapps_agents/resources/cursor/rules/quick-reference.mdc +630 -0
- tapps_agents/resources/cursor/rules/security.mdc +32 -0
- tapps_agents/resources/cursor/rules/simple-mode.mdc +500 -0
- tapps_agents/resources/cursor/rules/testing.mdc +31 -0
- tapps_agents/resources/cursor/rules/when-to-use.mdc +156 -0
- tapps_agents/resources/cursor/rules/workflow-presets.mdc +179 -0
- tapps_agents/resources/customizations/__init__.py +1 -0
- tapps_agents/resources/customizations/example-custom.yaml +83 -0
- tapps_agents/resources/hooks/__init__.py +1 -0
- tapps_agents/resources/hooks/templates/README.md +5 -0
- tapps_agents/resources/hooks/templates/__init__.py +1 -0
- tapps_agents/resources/hooks/templates/add-project-context.yaml +8 -0
- tapps_agents/resources/hooks/templates/auto-format-js.yaml +10 -0
- tapps_agents/resources/hooks/templates/auto-format-python.yaml +10 -0
- tapps_agents/resources/hooks/templates/git-commit-check.yaml +7 -0
- tapps_agents/resources/hooks/templates/notify-on-complete.yaml +8 -0
- tapps_agents/resources/hooks/templates/quality-gate.yaml +8 -0
- tapps_agents/resources/hooks/templates/security-scan-on-edit.yaml +10 -0
- tapps_agents/resources/hooks/templates/session-end-log.yaml +7 -0
- tapps_agents/resources/hooks/templates/show-beads-ready.yaml +8 -0
- tapps_agents/resources/hooks/templates/test-on-edit.yaml +10 -0
- tapps_agents/resources/hooks/templates/update-docs-on-complete.yaml +8 -0
- tapps_agents/resources/hooks/templates/user-prompt-log.yaml +7 -0
- tapps_agents/resources/scripts/__init__.py +1 -0
- tapps_agents/resources/scripts/set_bd_path.ps1 +51 -0
- tapps_agents/resources/workflows/__init__.py +1 -0
- tapps_agents/resources/workflows/presets/__init__.py +1 -0
- tapps_agents/resources/workflows/presets/brownfield-analysis.yaml +235 -0
- tapps_agents/resources/workflows/presets/fix.yaml +78 -0
- tapps_agents/resources/workflows/presets/full-sdlc.yaml +122 -0
- tapps_agents/resources/workflows/presets/quality.yaml +82 -0
- tapps_agents/resources/workflows/presets/rapid-dev.yaml +84 -0
- 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/breakdown_orchestrator.py +49 -49
- tapps_agents/simple_mode/orchestrators/brownfield_orchestrator.py +135 -135
- 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/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_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/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 -148
- 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.6.0.dist-info → tapps_agents-3.6.1.dist-info}/METADATA +672 -672
- tapps_agents-3.6.1.dist-info/RECORD +883 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/licenses/LICENSE +22 -22
- tapps_agents-3.6.0.dist-info/RECORD +0 -758
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/WHEEL +0 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/entry_points.txt +0 -0
- {tapps_agents-3.6.0.dist-info → tapps_agents-3.6.1.dist-info}/top_level.txt +0 -0
|
@@ -1,498 +1,498 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Execution Graph Generator
|
|
3
|
-
|
|
4
|
-
Converts workflow event log traces into graph structures for visualization.
|
|
5
|
-
Supports DOT/Graphviz export and Mermaid diagram generation.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
from dataclasses import dataclass, field
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import Any
|
|
14
|
-
|
|
15
|
-
from .event_log import WorkflowEventLog
|
|
16
|
-
from .exceptions import (
|
|
17
|
-
EmptyWorkflowError,
|
|
18
|
-
GraphGenerationError,
|
|
19
|
-
InvalidTraceError,
|
|
20
|
-
)
|
|
21
|
-
from ..core.exceptions import WorkflowNotFoundError
|
|
22
|
-
|
|
23
|
-
logger = logging.getLogger(__name__)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@dataclass
|
|
27
|
-
class GraphNode:
|
|
28
|
-
"""A node in the execution graph."""
|
|
29
|
-
|
|
30
|
-
id: str
|
|
31
|
-
label: str
|
|
32
|
-
agent: str | None = None
|
|
33
|
-
action: str | None = None
|
|
34
|
-
status: str | None = None
|
|
35
|
-
duration_ms: float | None = None
|
|
36
|
-
error: str | None = None
|
|
37
|
-
metadata: dict[str, Any] = field(default_factory=dict)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass
|
|
41
|
-
class GraphEdge:
|
|
42
|
-
"""An edge in the execution graph."""
|
|
43
|
-
|
|
44
|
-
source: str
|
|
45
|
-
target: str
|
|
46
|
-
label: str | None = None
|
|
47
|
-
edge_type: str = "default" # default, gate_pass, gate_fail, dependency
|
|
48
|
-
metadata: dict[str, Any] = field(default_factory=dict)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@dataclass
|
|
52
|
-
class ExecutionGraph:
|
|
53
|
-
"""Execution graph structure."""
|
|
54
|
-
|
|
55
|
-
workflow_id: str
|
|
56
|
-
nodes: list[GraphNode] = field(default_factory=list)
|
|
57
|
-
edges: list[GraphEdge] = field(default_factory=list)
|
|
58
|
-
metadata: dict[str, Any] = field(default_factory=dict)
|
|
59
|
-
|
|
60
|
-
def to_dot(self) -> str:
|
|
61
|
-
"""
|
|
62
|
-
Export graph to DOT format for Graphviz.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
DOT format string
|
|
66
|
-
"""
|
|
67
|
-
lines = ["digraph ExecutionGraph {", " rankdir=LR;", " node [shape=box];"]
|
|
68
|
-
|
|
69
|
-
# Add nodes
|
|
70
|
-
for node in self.nodes:
|
|
71
|
-
label = node.label.replace('"', '\\"')
|
|
72
|
-
color = self._get_node_color(node.status)
|
|
73
|
-
style = "filled" if node.error else "solid"
|
|
74
|
-
|
|
75
|
-
node_attrs = [
|
|
76
|
-
f'label="{label}"',
|
|
77
|
-
f'fillcolor="{color}"',
|
|
78
|
-
f'style="{style}"',
|
|
79
|
-
]
|
|
80
|
-
|
|
81
|
-
if node.duration_ms:
|
|
82
|
-
node_attrs.append(f'tooltip="Duration: {node.duration_ms:.0f}ms"')
|
|
83
|
-
|
|
84
|
-
if node.error:
|
|
85
|
-
node_attrs.append('fontcolor="red"')
|
|
86
|
-
|
|
87
|
-
lines.append(f' "{node.id}" [{", ".join(node_attrs)}];')
|
|
88
|
-
|
|
89
|
-
# Add edges
|
|
90
|
-
for edge in self.edges:
|
|
91
|
-
edge_attrs = []
|
|
92
|
-
|
|
93
|
-
if edge.label:
|
|
94
|
-
edge_attrs.append(f'label="{edge.label.replace(chr(34), chr(92)+chr(34))}"')
|
|
95
|
-
|
|
96
|
-
color = self._get_edge_color(edge.edge_type)
|
|
97
|
-
if color:
|
|
98
|
-
edge_attrs.append(f'color="{color}"')
|
|
99
|
-
|
|
100
|
-
style = self._get_edge_style(edge.edge_type)
|
|
101
|
-
if style:
|
|
102
|
-
edge_attrs.append(f'style="{style}"')
|
|
103
|
-
|
|
104
|
-
attrs_str = f" [{', '.join(edge_attrs)}]" if edge_attrs else ""
|
|
105
|
-
lines.append(f' "{edge.source}" -> "{edge.target}"{attrs_str};')
|
|
106
|
-
|
|
107
|
-
lines.append("}")
|
|
108
|
-
return "\n".join(lines)
|
|
109
|
-
|
|
110
|
-
def to_mermaid(self) -> str:
|
|
111
|
-
"""
|
|
112
|
-
Export graph to Mermaid diagram format.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
Mermaid diagram string
|
|
116
|
-
"""
|
|
117
|
-
lines = ["graph LR"]
|
|
118
|
-
|
|
119
|
-
# Add nodes with styling
|
|
120
|
-
for node in self.nodes:
|
|
121
|
-
label = node.label.replace('"', "'")
|
|
122
|
-
shape = self._get_mermaid_shape(node.status)
|
|
123
|
-
lines.append(f' {node.id}["{label}"]')
|
|
124
|
-
|
|
125
|
-
# Add edges
|
|
126
|
-
for edge in self.edges:
|
|
127
|
-
label_str = f'|"{edge.label}"|' if edge.label else "|"
|
|
128
|
-
style = self._get_mermaid_edge_style(edge.edge_type)
|
|
129
|
-
lines.append(f" {edge.source} {label_str} {edge.target}{style}")
|
|
130
|
-
|
|
131
|
-
return "\n".join(lines)
|
|
132
|
-
|
|
133
|
-
def _get_node_color(self, status: str | None) -> str:
|
|
134
|
-
"""Get node color based on status."""
|
|
135
|
-
color_map = {
|
|
136
|
-
"completed": "lightgreen",
|
|
137
|
-
"failed": "lightcoral",
|
|
138
|
-
"running": "lightblue",
|
|
139
|
-
"skipped": "lightgray",
|
|
140
|
-
None: "white",
|
|
141
|
-
}
|
|
142
|
-
return color_map.get(status, "white")
|
|
143
|
-
|
|
144
|
-
def _get_edge_color(self, edge_type: str) -> str | None:
|
|
145
|
-
"""Get edge color based on type."""
|
|
146
|
-
color_map = {
|
|
147
|
-
"gate_pass": "green",
|
|
148
|
-
"gate_fail": "red",
|
|
149
|
-
"dependency": "blue",
|
|
150
|
-
"default": None,
|
|
151
|
-
}
|
|
152
|
-
return color_map.get(edge_type)
|
|
153
|
-
|
|
154
|
-
def _get_edge_style(self, edge_type: str) -> str | None:
|
|
155
|
-
"""Get edge style based on type."""
|
|
156
|
-
style_map = {
|
|
157
|
-
"gate_pass": "solid",
|
|
158
|
-
"gate_fail": "dashed",
|
|
159
|
-
"dependency": "dotted",
|
|
160
|
-
"default": None,
|
|
161
|
-
}
|
|
162
|
-
return style_map.get(edge_type)
|
|
163
|
-
|
|
164
|
-
def _get_mermaid_shape(self, status: str | None) -> str:
|
|
165
|
-
"""Get Mermaid shape based on status."""
|
|
166
|
-
# Mermaid shapes are handled via classDef, but for simplicity
|
|
167
|
-
# we'll use standard shapes
|
|
168
|
-
return ""
|
|
169
|
-
|
|
170
|
-
def _get_mermaid_edge_style(self, edge_type: str) -> str:
|
|
171
|
-
"""Get Mermaid edge style."""
|
|
172
|
-
style_map = {
|
|
173
|
-
"gate_pass": ':::gatePass',
|
|
174
|
-
"gate_fail": ':::gateFail',
|
|
175
|
-
"dependency": ':::dependency',
|
|
176
|
-
"default": "",
|
|
177
|
-
}
|
|
178
|
-
return style_map.get(edge_type, "")
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
class ExecutionGraphGenerator:
|
|
182
|
-
"""Generates execution graphs from workflow event logs."""
|
|
183
|
-
|
|
184
|
-
def __init__(self, event_log: WorkflowEventLog | None = None):
|
|
185
|
-
"""
|
|
186
|
-
Initialize graph generator.
|
|
187
|
-
|
|
188
|
-
Args:
|
|
189
|
-
event_log: Optional WorkflowEventLog instance
|
|
190
|
-
"""
|
|
191
|
-
self.event_log = event_log
|
|
192
|
-
|
|
193
|
-
def generate_graph(
|
|
194
|
-
self, workflow_id: str, event_log: WorkflowEventLog | None = None
|
|
195
|
-
) -> ExecutionGraph:
|
|
196
|
-
"""
|
|
197
|
-
Generate execution graph from workflow event log.
|
|
198
|
-
|
|
199
|
-
Args:
|
|
200
|
-
workflow_id: Workflow ID
|
|
201
|
-
event_log: Optional WorkflowEventLog instance (uses self.event_log if not provided)
|
|
202
|
-
|
|
203
|
-
Returns:
|
|
204
|
-
ExecutionGraph instance
|
|
205
|
-
|
|
206
|
-
Raises:
|
|
207
|
-
ValueError: If workflow_id is invalid
|
|
208
|
-
WorkflowNotFoundError: If workflow does not exist
|
|
209
|
-
GraphGenerationError: If graph generation fails
|
|
210
|
-
InvalidTraceError: If trace structure is invalid
|
|
211
|
-
EmptyWorkflowError: If workflow has no steps
|
|
212
|
-
"""
|
|
213
|
-
# Validate inputs
|
|
214
|
-
if not workflow_id or not isinstance(workflow_id, str):
|
|
215
|
-
raise ValueError("workflow_id must be a non-empty string")
|
|
216
|
-
|
|
217
|
-
log = event_log or self.event_log
|
|
218
|
-
if not log:
|
|
219
|
-
raise ValueError("WorkflowEventLog instance required")
|
|
220
|
-
|
|
221
|
-
# Validate workflow exists
|
|
222
|
-
if not self._workflow_exists(workflow_id, log):
|
|
223
|
-
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found")
|
|
224
|
-
|
|
225
|
-
# Get execution trace with error handling
|
|
226
|
-
try:
|
|
227
|
-
trace = log.get_execution_trace(workflow_id)
|
|
228
|
-
except FileNotFoundError as e:
|
|
229
|
-
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found") from e
|
|
230
|
-
except Exception as e:
|
|
231
|
-
raise GraphGenerationError(f"Failed to load trace for workflow {workflow_id}: {e}") from e
|
|
232
|
-
|
|
233
|
-
# Validate trace structure
|
|
234
|
-
if not trace or not isinstance(trace, dict):
|
|
235
|
-
raise InvalidTraceError(f"Invalid trace structure for workflow {workflow_id}")
|
|
236
|
-
|
|
237
|
-
if not trace.get("steps"):
|
|
238
|
-
raise EmptyWorkflowError(f"Workflow {workflow_id} has no steps")
|
|
239
|
-
|
|
240
|
-
# Read events for additional context (non-critical, continue if fails)
|
|
241
|
-
try:
|
|
242
|
-
events = log.read_events(workflow_id)
|
|
243
|
-
except Exception as e:
|
|
244
|
-
logger.warning(f"Failed to read events for workflow {workflow_id}: {e}")
|
|
245
|
-
events = []
|
|
246
|
-
|
|
247
|
-
# Build graph with error handling
|
|
248
|
-
try:
|
|
249
|
-
graph = ExecutionGraph(workflow_id=workflow_id)
|
|
250
|
-
|
|
251
|
-
# Create nodes from steps
|
|
252
|
-
steps = trace.get("steps", [])
|
|
253
|
-
if not steps:
|
|
254
|
-
raise EmptyWorkflowError(f"Workflow {workflow_id} has no steps")
|
|
255
|
-
|
|
256
|
-
for step in steps:
|
|
257
|
-
if not isinstance(step, dict):
|
|
258
|
-
logger.warning(f"Invalid step structure in workflow {workflow_id}, skipping")
|
|
259
|
-
continue
|
|
260
|
-
|
|
261
|
-
step_id = step.get("step_id")
|
|
262
|
-
if not step_id:
|
|
263
|
-
logger.warning(f"Step missing step_id in workflow {workflow_id}, skipping")
|
|
264
|
-
continue
|
|
265
|
-
|
|
266
|
-
try:
|
|
267
|
-
node = GraphNode(
|
|
268
|
-
id=step_id,
|
|
269
|
-
label=self._format_node_label(step),
|
|
270
|
-
agent=step.get("agent"),
|
|
271
|
-
action=step.get("action"),
|
|
272
|
-
status=step.get("status"),
|
|
273
|
-
duration_ms=step.get("duration_ms"),
|
|
274
|
-
error=step.get("error"),
|
|
275
|
-
metadata={
|
|
276
|
-
"skill_name": step.get("skill_name"),
|
|
277
|
-
"artifact_paths": step.get("artifact_paths", []),
|
|
278
|
-
},
|
|
279
|
-
)
|
|
280
|
-
graph.nodes.append(node)
|
|
281
|
-
except Exception as e:
|
|
282
|
-
logger.warning(f"Failed to create node for step {step_id}: {e}")
|
|
283
|
-
continue
|
|
284
|
-
|
|
285
|
-
if not graph.nodes:
|
|
286
|
-
raise EmptyWorkflowError(f"Workflow {workflow_id} has no valid steps")
|
|
287
|
-
|
|
288
|
-
# Create edges from workflow structure and events
|
|
289
|
-
try:
|
|
290
|
-
edges = self._build_edges(trace, events)
|
|
291
|
-
graph.edges.extend(edges)
|
|
292
|
-
except Exception as e:
|
|
293
|
-
logger.warning(f"Failed to build edges for workflow {workflow_id}: {e}")
|
|
294
|
-
# Continue with empty edges rather than failing
|
|
295
|
-
|
|
296
|
-
# Add metadata
|
|
297
|
-
graph.metadata = {
|
|
298
|
-
"started_at": trace.get("started_at"),
|
|
299
|
-
"ended_at": trace.get("ended_at"),
|
|
300
|
-
"total_steps": len(graph.nodes),
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return graph
|
|
304
|
-
except (EmptyWorkflowError, InvalidTraceError):
|
|
305
|
-
# Re-raise these specific errors
|
|
306
|
-
raise
|
|
307
|
-
except Exception as e:
|
|
308
|
-
raise GraphGenerationError(f"Failed to generate graph for workflow {workflow_id}: {e}") from e
|
|
309
|
-
|
|
310
|
-
def _format_node_label(self, step: dict[str, Any]) -> str:
|
|
311
|
-
"""Format node label from step data."""
|
|
312
|
-
step_id = step.get("step_id", "unknown")
|
|
313
|
-
agent = step.get("agent", "unknown")
|
|
314
|
-
action = step.get("action", "")
|
|
315
|
-
|
|
316
|
-
# Create readable label
|
|
317
|
-
if action:
|
|
318
|
-
label = f"{step_id}\\n{agent}: {action}"
|
|
319
|
-
else:
|
|
320
|
-
label = f"{step_id}\\n{agent}"
|
|
321
|
-
|
|
322
|
-
# Add status indicator
|
|
323
|
-
status = step.get("status", "")
|
|
324
|
-
if status and status != "completed":
|
|
325
|
-
label += f"\\n[{status}]"
|
|
326
|
-
|
|
327
|
-
return label
|
|
328
|
-
|
|
329
|
-
def _build_edges(
|
|
330
|
-
self, trace: dict[str, Any], events: list[Any]
|
|
331
|
-
) -> list[GraphEdge]:
|
|
332
|
-
"""
|
|
333
|
-
Build edges from trace and events, handling parallel execution and dependencies.
|
|
334
|
-
|
|
335
|
-
Args:
|
|
336
|
-
trace: Execution trace dictionary
|
|
337
|
-
events: List of workflow events
|
|
338
|
-
|
|
339
|
-
Returns:
|
|
340
|
-
List of GraphEdge instances
|
|
341
|
-
"""
|
|
342
|
-
edges: list[GraphEdge] = []
|
|
343
|
-
steps = trace.get("steps", [])
|
|
344
|
-
|
|
345
|
-
if not steps:
|
|
346
|
-
return edges
|
|
347
|
-
|
|
348
|
-
# Build step dependency graph from step.requires fields
|
|
349
|
-
step_deps: dict[str, list[str]] = {}
|
|
350
|
-
step_map: dict[str, dict[str, Any]] = {}
|
|
351
|
-
|
|
352
|
-
for step in steps:
|
|
353
|
-
step_id = step.get("step_id")
|
|
354
|
-
if not step_id:
|
|
355
|
-
continue
|
|
356
|
-
|
|
357
|
-
step_map[step_id] = step
|
|
358
|
-
requires = step.get("requires", [])
|
|
359
|
-
if requires:
|
|
360
|
-
step_deps[step_id] = requires
|
|
361
|
-
|
|
362
|
-
# Create dependency edges from step.requires
|
|
363
|
-
for step_id, deps in step_deps.items():
|
|
364
|
-
for dep in deps:
|
|
365
|
-
# Only create edge if dependency step exists
|
|
366
|
-
if dep in step_map:
|
|
367
|
-
edges.append(GraphEdge(
|
|
368
|
-
source=dep,
|
|
369
|
-
target=step_id,
|
|
370
|
-
edge_type="dependency",
|
|
371
|
-
label="requires"
|
|
372
|
-
))
|
|
373
|
-
|
|
374
|
-
# Build step order from events (for sequential fallback)
|
|
375
|
-
step_order: list[str] = []
|
|
376
|
-
for event in events:
|
|
377
|
-
if hasattr(event, "event_type") and event.event_type == "step_start":
|
|
378
|
-
step_id = getattr(event, "step_id", None)
|
|
379
|
-
if step_id and step_id not in step_order:
|
|
380
|
-
step_order.append(step_id)
|
|
381
|
-
|
|
382
|
-
# Create sequential edges from event order (fallback when no dependencies)
|
|
383
|
-
for i in range(len(step_order) - 1):
|
|
384
|
-
source = step_order[i]
|
|
385
|
-
target = step_order[i + 1]
|
|
386
|
-
|
|
387
|
-
# Skip if dependency edge already exists
|
|
388
|
-
if any(e.source == source and e.target == target for e in edges):
|
|
389
|
-
continue
|
|
390
|
-
|
|
391
|
-
# Check if this is a gate transition
|
|
392
|
-
edge_type = "default"
|
|
393
|
-
label = None
|
|
394
|
-
|
|
395
|
-
# Look for gate events between steps
|
|
396
|
-
source_step = step_map.get(source)
|
|
397
|
-
if source_step:
|
|
398
|
-
status = source_step.get("status")
|
|
399
|
-
if status == "completed":
|
|
400
|
-
# Check if gate passed
|
|
401
|
-
edge_type = "gate_pass"
|
|
402
|
-
label = "pass"
|
|
403
|
-
elif status == "failed":
|
|
404
|
-
edge_type = "gate_fail"
|
|
405
|
-
label = "fail"
|
|
406
|
-
|
|
407
|
-
edges.append(GraphEdge(
|
|
408
|
-
source=source,
|
|
409
|
-
target=target,
|
|
410
|
-
label=label,
|
|
411
|
-
edge_type=edge_type,
|
|
412
|
-
))
|
|
413
|
-
|
|
414
|
-
return edges
|
|
415
|
-
|
|
416
|
-
def _workflow_exists(self, workflow_id: str, event_log: WorkflowEventLog) -> bool:
|
|
417
|
-
"""
|
|
418
|
-
Check if workflow exists in event log.
|
|
419
|
-
|
|
420
|
-
Args:
|
|
421
|
-
workflow_id: Workflow ID to check
|
|
422
|
-
event_log: WorkflowEventLog instance
|
|
423
|
-
|
|
424
|
-
Returns:
|
|
425
|
-
True if workflow exists, False otherwise
|
|
426
|
-
"""
|
|
427
|
-
try:
|
|
428
|
-
# Try to get trace - if it succeeds, workflow exists
|
|
429
|
-
trace = event_log.get_execution_trace(workflow_id)
|
|
430
|
-
return trace is not None and isinstance(trace, dict)
|
|
431
|
-
except (FileNotFoundError, KeyError):
|
|
432
|
-
return False
|
|
433
|
-
except Exception:
|
|
434
|
-
# For other exceptions, assume workflow might exist
|
|
435
|
-
# Let the actual operation handle the error
|
|
436
|
-
return True
|
|
437
|
-
|
|
438
|
-
def save_dot(self, graph: ExecutionGraph, output_path: Path) -> None:
|
|
439
|
-
"""
|
|
440
|
-
Save graph to DOT file.
|
|
441
|
-
|
|
442
|
-
Args:
|
|
443
|
-
graph: ExecutionGraph instance
|
|
444
|
-
output_path: Output file path
|
|
445
|
-
|
|
446
|
-
Raises:
|
|
447
|
-
ValueError: If graph or output_path is invalid
|
|
448
|
-
OSError: If file cannot be written
|
|
449
|
-
"""
|
|
450
|
-
if not graph:
|
|
451
|
-
raise ValueError("Graph instance required")
|
|
452
|
-
|
|
453
|
-
if not output_path:
|
|
454
|
-
raise ValueError("Output path required")
|
|
455
|
-
|
|
456
|
-
try:
|
|
457
|
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
458
|
-
except OSError as e:
|
|
459
|
-
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
460
|
-
|
|
461
|
-
try:
|
|
462
|
-
dot_content = graph.to_dot()
|
|
463
|
-
output_path.write_text(dot_content, encoding="utf-8")
|
|
464
|
-
except OSError as e:
|
|
465
|
-
raise OSError(f"Cannot write DOT file to {output_path}: {e}") from e
|
|
466
|
-
except Exception as e:
|
|
467
|
-
raise GraphGenerationError(f"Failed to save DOT file: {e}") from e
|
|
468
|
-
|
|
469
|
-
def save_mermaid(self, graph: ExecutionGraph, output_path: Path) -> None:
|
|
470
|
-
"""
|
|
471
|
-
Save graph to Mermaid file.
|
|
472
|
-
|
|
473
|
-
Args:
|
|
474
|
-
graph: ExecutionGraph instance
|
|
475
|
-
output_path: Output file path
|
|
476
|
-
|
|
477
|
-
Raises:
|
|
478
|
-
ValueError: If graph or output_path is invalid
|
|
479
|
-
OSError: If file cannot be written
|
|
480
|
-
"""
|
|
481
|
-
if not graph:
|
|
482
|
-
raise ValueError("Graph instance required")
|
|
483
|
-
|
|
484
|
-
if not output_path:
|
|
485
|
-
raise ValueError("Output path required")
|
|
486
|
-
|
|
487
|
-
try:
|
|
488
|
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
489
|
-
except OSError as e:
|
|
490
|
-
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
491
|
-
|
|
492
|
-
try:
|
|
493
|
-
mermaid_content = graph.to_mermaid()
|
|
494
|
-
output_path.write_text(mermaid_content, encoding="utf-8")
|
|
495
|
-
except OSError as e:
|
|
496
|
-
raise OSError(f"Cannot write Mermaid file to {output_path}: {e}") from e
|
|
497
|
-
except Exception as e:
|
|
498
|
-
raise GraphGenerationError(f"Failed to save Mermaid file: {e}") from e
|
|
1
|
+
"""
|
|
2
|
+
Execution Graph Generator
|
|
3
|
+
|
|
4
|
+
Converts workflow event log traces into graph structures for visualization.
|
|
5
|
+
Supports DOT/Graphviz export and Mermaid diagram generation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from .event_log import WorkflowEventLog
|
|
16
|
+
from .exceptions import (
|
|
17
|
+
EmptyWorkflowError,
|
|
18
|
+
GraphGenerationError,
|
|
19
|
+
InvalidTraceError,
|
|
20
|
+
)
|
|
21
|
+
from ..core.exceptions import WorkflowNotFoundError
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class GraphNode:
|
|
28
|
+
"""A node in the execution graph."""
|
|
29
|
+
|
|
30
|
+
id: str
|
|
31
|
+
label: str
|
|
32
|
+
agent: str | None = None
|
|
33
|
+
action: str | None = None
|
|
34
|
+
status: str | None = None
|
|
35
|
+
duration_ms: float | None = None
|
|
36
|
+
error: str | None = None
|
|
37
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class GraphEdge:
|
|
42
|
+
"""An edge in the execution graph."""
|
|
43
|
+
|
|
44
|
+
source: str
|
|
45
|
+
target: str
|
|
46
|
+
label: str | None = None
|
|
47
|
+
edge_type: str = "default" # default, gate_pass, gate_fail, dependency
|
|
48
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class ExecutionGraph:
|
|
53
|
+
"""Execution graph structure."""
|
|
54
|
+
|
|
55
|
+
workflow_id: str
|
|
56
|
+
nodes: list[GraphNode] = field(default_factory=list)
|
|
57
|
+
edges: list[GraphEdge] = field(default_factory=list)
|
|
58
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
59
|
+
|
|
60
|
+
def to_dot(self) -> str:
|
|
61
|
+
"""
|
|
62
|
+
Export graph to DOT format for Graphviz.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
DOT format string
|
|
66
|
+
"""
|
|
67
|
+
lines = ["digraph ExecutionGraph {", " rankdir=LR;", " node [shape=box];"]
|
|
68
|
+
|
|
69
|
+
# Add nodes
|
|
70
|
+
for node in self.nodes:
|
|
71
|
+
label = node.label.replace('"', '\\"')
|
|
72
|
+
color = self._get_node_color(node.status)
|
|
73
|
+
style = "filled" if node.error else "solid"
|
|
74
|
+
|
|
75
|
+
node_attrs = [
|
|
76
|
+
f'label="{label}"',
|
|
77
|
+
f'fillcolor="{color}"',
|
|
78
|
+
f'style="{style}"',
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
if node.duration_ms:
|
|
82
|
+
node_attrs.append(f'tooltip="Duration: {node.duration_ms:.0f}ms"')
|
|
83
|
+
|
|
84
|
+
if node.error:
|
|
85
|
+
node_attrs.append('fontcolor="red"')
|
|
86
|
+
|
|
87
|
+
lines.append(f' "{node.id}" [{", ".join(node_attrs)}];')
|
|
88
|
+
|
|
89
|
+
# Add edges
|
|
90
|
+
for edge in self.edges:
|
|
91
|
+
edge_attrs = []
|
|
92
|
+
|
|
93
|
+
if edge.label:
|
|
94
|
+
edge_attrs.append(f'label="{edge.label.replace(chr(34), chr(92)+chr(34))}"')
|
|
95
|
+
|
|
96
|
+
color = self._get_edge_color(edge.edge_type)
|
|
97
|
+
if color:
|
|
98
|
+
edge_attrs.append(f'color="{color}"')
|
|
99
|
+
|
|
100
|
+
style = self._get_edge_style(edge.edge_type)
|
|
101
|
+
if style:
|
|
102
|
+
edge_attrs.append(f'style="{style}"')
|
|
103
|
+
|
|
104
|
+
attrs_str = f" [{', '.join(edge_attrs)}]" if edge_attrs else ""
|
|
105
|
+
lines.append(f' "{edge.source}" -> "{edge.target}"{attrs_str};')
|
|
106
|
+
|
|
107
|
+
lines.append("}")
|
|
108
|
+
return "\n".join(lines)
|
|
109
|
+
|
|
110
|
+
def to_mermaid(self) -> str:
|
|
111
|
+
"""
|
|
112
|
+
Export graph to Mermaid diagram format.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Mermaid diagram string
|
|
116
|
+
"""
|
|
117
|
+
lines = ["graph LR"]
|
|
118
|
+
|
|
119
|
+
# Add nodes with styling
|
|
120
|
+
for node in self.nodes:
|
|
121
|
+
label = node.label.replace('"', "'")
|
|
122
|
+
shape = self._get_mermaid_shape(node.status)
|
|
123
|
+
lines.append(f' {node.id}["{label}"]')
|
|
124
|
+
|
|
125
|
+
# Add edges
|
|
126
|
+
for edge in self.edges:
|
|
127
|
+
label_str = f'|"{edge.label}"|' if edge.label else "|"
|
|
128
|
+
style = self._get_mermaid_edge_style(edge.edge_type)
|
|
129
|
+
lines.append(f" {edge.source} {label_str} {edge.target}{style}")
|
|
130
|
+
|
|
131
|
+
return "\n".join(lines)
|
|
132
|
+
|
|
133
|
+
def _get_node_color(self, status: str | None) -> str:
|
|
134
|
+
"""Get node color based on status."""
|
|
135
|
+
color_map = {
|
|
136
|
+
"completed": "lightgreen",
|
|
137
|
+
"failed": "lightcoral",
|
|
138
|
+
"running": "lightblue",
|
|
139
|
+
"skipped": "lightgray",
|
|
140
|
+
None: "white",
|
|
141
|
+
}
|
|
142
|
+
return color_map.get(status, "white")
|
|
143
|
+
|
|
144
|
+
def _get_edge_color(self, edge_type: str) -> str | None:
|
|
145
|
+
"""Get edge color based on type."""
|
|
146
|
+
color_map = {
|
|
147
|
+
"gate_pass": "green",
|
|
148
|
+
"gate_fail": "red",
|
|
149
|
+
"dependency": "blue",
|
|
150
|
+
"default": None,
|
|
151
|
+
}
|
|
152
|
+
return color_map.get(edge_type)
|
|
153
|
+
|
|
154
|
+
def _get_edge_style(self, edge_type: str) -> str | None:
|
|
155
|
+
"""Get edge style based on type."""
|
|
156
|
+
style_map = {
|
|
157
|
+
"gate_pass": "solid",
|
|
158
|
+
"gate_fail": "dashed",
|
|
159
|
+
"dependency": "dotted",
|
|
160
|
+
"default": None,
|
|
161
|
+
}
|
|
162
|
+
return style_map.get(edge_type)
|
|
163
|
+
|
|
164
|
+
def _get_mermaid_shape(self, status: str | None) -> str:
|
|
165
|
+
"""Get Mermaid shape based on status."""
|
|
166
|
+
# Mermaid shapes are handled via classDef, but for simplicity
|
|
167
|
+
# we'll use standard shapes
|
|
168
|
+
return ""
|
|
169
|
+
|
|
170
|
+
def _get_mermaid_edge_style(self, edge_type: str) -> str:
|
|
171
|
+
"""Get Mermaid edge style."""
|
|
172
|
+
style_map = {
|
|
173
|
+
"gate_pass": ':::gatePass',
|
|
174
|
+
"gate_fail": ':::gateFail',
|
|
175
|
+
"dependency": ':::dependency',
|
|
176
|
+
"default": "",
|
|
177
|
+
}
|
|
178
|
+
return style_map.get(edge_type, "")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class ExecutionGraphGenerator:
|
|
182
|
+
"""Generates execution graphs from workflow event logs."""
|
|
183
|
+
|
|
184
|
+
def __init__(self, event_log: WorkflowEventLog | None = None):
|
|
185
|
+
"""
|
|
186
|
+
Initialize graph generator.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
event_log: Optional WorkflowEventLog instance
|
|
190
|
+
"""
|
|
191
|
+
self.event_log = event_log
|
|
192
|
+
|
|
193
|
+
def generate_graph(
|
|
194
|
+
self, workflow_id: str, event_log: WorkflowEventLog | None = None
|
|
195
|
+
) -> ExecutionGraph:
|
|
196
|
+
"""
|
|
197
|
+
Generate execution graph from workflow event log.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
workflow_id: Workflow ID
|
|
201
|
+
event_log: Optional WorkflowEventLog instance (uses self.event_log if not provided)
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
ExecutionGraph instance
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
ValueError: If workflow_id is invalid
|
|
208
|
+
WorkflowNotFoundError: If workflow does not exist
|
|
209
|
+
GraphGenerationError: If graph generation fails
|
|
210
|
+
InvalidTraceError: If trace structure is invalid
|
|
211
|
+
EmptyWorkflowError: If workflow has no steps
|
|
212
|
+
"""
|
|
213
|
+
# Validate inputs
|
|
214
|
+
if not workflow_id or not isinstance(workflow_id, str):
|
|
215
|
+
raise ValueError("workflow_id must be a non-empty string")
|
|
216
|
+
|
|
217
|
+
log = event_log or self.event_log
|
|
218
|
+
if not log:
|
|
219
|
+
raise ValueError("WorkflowEventLog instance required")
|
|
220
|
+
|
|
221
|
+
# Validate workflow exists
|
|
222
|
+
if not self._workflow_exists(workflow_id, log):
|
|
223
|
+
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found")
|
|
224
|
+
|
|
225
|
+
# Get execution trace with error handling
|
|
226
|
+
try:
|
|
227
|
+
trace = log.get_execution_trace(workflow_id)
|
|
228
|
+
except FileNotFoundError as e:
|
|
229
|
+
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found") from e
|
|
230
|
+
except Exception as e:
|
|
231
|
+
raise GraphGenerationError(f"Failed to load trace for workflow {workflow_id}: {e}") from e
|
|
232
|
+
|
|
233
|
+
# Validate trace structure
|
|
234
|
+
if not trace or not isinstance(trace, dict):
|
|
235
|
+
raise InvalidTraceError(f"Invalid trace structure for workflow {workflow_id}")
|
|
236
|
+
|
|
237
|
+
if not trace.get("steps"):
|
|
238
|
+
raise EmptyWorkflowError(f"Workflow {workflow_id} has no steps")
|
|
239
|
+
|
|
240
|
+
# Read events for additional context (non-critical, continue if fails)
|
|
241
|
+
try:
|
|
242
|
+
events = log.read_events(workflow_id)
|
|
243
|
+
except Exception as e:
|
|
244
|
+
logger.warning(f"Failed to read events for workflow {workflow_id}: {e}")
|
|
245
|
+
events = []
|
|
246
|
+
|
|
247
|
+
# Build graph with error handling
|
|
248
|
+
try:
|
|
249
|
+
graph = ExecutionGraph(workflow_id=workflow_id)
|
|
250
|
+
|
|
251
|
+
# Create nodes from steps
|
|
252
|
+
steps = trace.get("steps", [])
|
|
253
|
+
if not steps:
|
|
254
|
+
raise EmptyWorkflowError(f"Workflow {workflow_id} has no steps")
|
|
255
|
+
|
|
256
|
+
for step in steps:
|
|
257
|
+
if not isinstance(step, dict):
|
|
258
|
+
logger.warning(f"Invalid step structure in workflow {workflow_id}, skipping")
|
|
259
|
+
continue
|
|
260
|
+
|
|
261
|
+
step_id = step.get("step_id")
|
|
262
|
+
if not step_id:
|
|
263
|
+
logger.warning(f"Step missing step_id in workflow {workflow_id}, skipping")
|
|
264
|
+
continue
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
node = GraphNode(
|
|
268
|
+
id=step_id,
|
|
269
|
+
label=self._format_node_label(step),
|
|
270
|
+
agent=step.get("agent"),
|
|
271
|
+
action=step.get("action"),
|
|
272
|
+
status=step.get("status"),
|
|
273
|
+
duration_ms=step.get("duration_ms"),
|
|
274
|
+
error=step.get("error"),
|
|
275
|
+
metadata={
|
|
276
|
+
"skill_name": step.get("skill_name"),
|
|
277
|
+
"artifact_paths": step.get("artifact_paths", []),
|
|
278
|
+
},
|
|
279
|
+
)
|
|
280
|
+
graph.nodes.append(node)
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logger.warning(f"Failed to create node for step {step_id}: {e}")
|
|
283
|
+
continue
|
|
284
|
+
|
|
285
|
+
if not graph.nodes:
|
|
286
|
+
raise EmptyWorkflowError(f"Workflow {workflow_id} has no valid steps")
|
|
287
|
+
|
|
288
|
+
# Create edges from workflow structure and events
|
|
289
|
+
try:
|
|
290
|
+
edges = self._build_edges(trace, events)
|
|
291
|
+
graph.edges.extend(edges)
|
|
292
|
+
except Exception as e:
|
|
293
|
+
logger.warning(f"Failed to build edges for workflow {workflow_id}: {e}")
|
|
294
|
+
# Continue with empty edges rather than failing
|
|
295
|
+
|
|
296
|
+
# Add metadata
|
|
297
|
+
graph.metadata = {
|
|
298
|
+
"started_at": trace.get("started_at"),
|
|
299
|
+
"ended_at": trace.get("ended_at"),
|
|
300
|
+
"total_steps": len(graph.nodes),
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return graph
|
|
304
|
+
except (EmptyWorkflowError, InvalidTraceError):
|
|
305
|
+
# Re-raise these specific errors
|
|
306
|
+
raise
|
|
307
|
+
except Exception as e:
|
|
308
|
+
raise GraphGenerationError(f"Failed to generate graph for workflow {workflow_id}: {e}") from e
|
|
309
|
+
|
|
310
|
+
def _format_node_label(self, step: dict[str, Any]) -> str:
|
|
311
|
+
"""Format node label from step data."""
|
|
312
|
+
step_id = step.get("step_id", "unknown")
|
|
313
|
+
agent = step.get("agent", "unknown")
|
|
314
|
+
action = step.get("action", "")
|
|
315
|
+
|
|
316
|
+
# Create readable label
|
|
317
|
+
if action:
|
|
318
|
+
label = f"{step_id}\\n{agent}: {action}"
|
|
319
|
+
else:
|
|
320
|
+
label = f"{step_id}\\n{agent}"
|
|
321
|
+
|
|
322
|
+
# Add status indicator
|
|
323
|
+
status = step.get("status", "")
|
|
324
|
+
if status and status != "completed":
|
|
325
|
+
label += f"\\n[{status}]"
|
|
326
|
+
|
|
327
|
+
return label
|
|
328
|
+
|
|
329
|
+
def _build_edges(
|
|
330
|
+
self, trace: dict[str, Any], events: list[Any]
|
|
331
|
+
) -> list[GraphEdge]:
|
|
332
|
+
"""
|
|
333
|
+
Build edges from trace and events, handling parallel execution and dependencies.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
trace: Execution trace dictionary
|
|
337
|
+
events: List of workflow events
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
List of GraphEdge instances
|
|
341
|
+
"""
|
|
342
|
+
edges: list[GraphEdge] = []
|
|
343
|
+
steps = trace.get("steps", [])
|
|
344
|
+
|
|
345
|
+
if not steps:
|
|
346
|
+
return edges
|
|
347
|
+
|
|
348
|
+
# Build step dependency graph from step.requires fields
|
|
349
|
+
step_deps: dict[str, list[str]] = {}
|
|
350
|
+
step_map: dict[str, dict[str, Any]] = {}
|
|
351
|
+
|
|
352
|
+
for step in steps:
|
|
353
|
+
step_id = step.get("step_id")
|
|
354
|
+
if not step_id:
|
|
355
|
+
continue
|
|
356
|
+
|
|
357
|
+
step_map[step_id] = step
|
|
358
|
+
requires = step.get("requires", [])
|
|
359
|
+
if requires:
|
|
360
|
+
step_deps[step_id] = requires
|
|
361
|
+
|
|
362
|
+
# Create dependency edges from step.requires
|
|
363
|
+
for step_id, deps in step_deps.items():
|
|
364
|
+
for dep in deps:
|
|
365
|
+
# Only create edge if dependency step exists
|
|
366
|
+
if dep in step_map:
|
|
367
|
+
edges.append(GraphEdge(
|
|
368
|
+
source=dep,
|
|
369
|
+
target=step_id,
|
|
370
|
+
edge_type="dependency",
|
|
371
|
+
label="requires"
|
|
372
|
+
))
|
|
373
|
+
|
|
374
|
+
# Build step order from events (for sequential fallback)
|
|
375
|
+
step_order: list[str] = []
|
|
376
|
+
for event in events:
|
|
377
|
+
if hasattr(event, "event_type") and event.event_type == "step_start":
|
|
378
|
+
step_id = getattr(event, "step_id", None)
|
|
379
|
+
if step_id and step_id not in step_order:
|
|
380
|
+
step_order.append(step_id)
|
|
381
|
+
|
|
382
|
+
# Create sequential edges from event order (fallback when no dependencies)
|
|
383
|
+
for i in range(len(step_order) - 1):
|
|
384
|
+
source = step_order[i]
|
|
385
|
+
target = step_order[i + 1]
|
|
386
|
+
|
|
387
|
+
# Skip if dependency edge already exists
|
|
388
|
+
if any(e.source == source and e.target == target for e in edges):
|
|
389
|
+
continue
|
|
390
|
+
|
|
391
|
+
# Check if this is a gate transition
|
|
392
|
+
edge_type = "default"
|
|
393
|
+
label = None
|
|
394
|
+
|
|
395
|
+
# Look for gate events between steps
|
|
396
|
+
source_step = step_map.get(source)
|
|
397
|
+
if source_step:
|
|
398
|
+
status = source_step.get("status")
|
|
399
|
+
if status == "completed":
|
|
400
|
+
# Check if gate passed
|
|
401
|
+
edge_type = "gate_pass"
|
|
402
|
+
label = "pass"
|
|
403
|
+
elif status == "failed":
|
|
404
|
+
edge_type = "gate_fail"
|
|
405
|
+
label = "fail"
|
|
406
|
+
|
|
407
|
+
edges.append(GraphEdge(
|
|
408
|
+
source=source,
|
|
409
|
+
target=target,
|
|
410
|
+
label=label,
|
|
411
|
+
edge_type=edge_type,
|
|
412
|
+
))
|
|
413
|
+
|
|
414
|
+
return edges
|
|
415
|
+
|
|
416
|
+
def _workflow_exists(self, workflow_id: str, event_log: WorkflowEventLog) -> bool:
|
|
417
|
+
"""
|
|
418
|
+
Check if workflow exists in event log.
|
|
419
|
+
|
|
420
|
+
Args:
|
|
421
|
+
workflow_id: Workflow ID to check
|
|
422
|
+
event_log: WorkflowEventLog instance
|
|
423
|
+
|
|
424
|
+
Returns:
|
|
425
|
+
True if workflow exists, False otherwise
|
|
426
|
+
"""
|
|
427
|
+
try:
|
|
428
|
+
# Try to get trace - if it succeeds, workflow exists
|
|
429
|
+
trace = event_log.get_execution_trace(workflow_id)
|
|
430
|
+
return trace is not None and isinstance(trace, dict)
|
|
431
|
+
except (FileNotFoundError, KeyError):
|
|
432
|
+
return False
|
|
433
|
+
except Exception:
|
|
434
|
+
# For other exceptions, assume workflow might exist
|
|
435
|
+
# Let the actual operation handle the error
|
|
436
|
+
return True
|
|
437
|
+
|
|
438
|
+
def save_dot(self, graph: ExecutionGraph, output_path: Path) -> None:
|
|
439
|
+
"""
|
|
440
|
+
Save graph to DOT file.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
graph: ExecutionGraph instance
|
|
444
|
+
output_path: Output file path
|
|
445
|
+
|
|
446
|
+
Raises:
|
|
447
|
+
ValueError: If graph or output_path is invalid
|
|
448
|
+
OSError: If file cannot be written
|
|
449
|
+
"""
|
|
450
|
+
if not graph:
|
|
451
|
+
raise ValueError("Graph instance required")
|
|
452
|
+
|
|
453
|
+
if not output_path:
|
|
454
|
+
raise ValueError("Output path required")
|
|
455
|
+
|
|
456
|
+
try:
|
|
457
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
458
|
+
except OSError as e:
|
|
459
|
+
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
dot_content = graph.to_dot()
|
|
463
|
+
output_path.write_text(dot_content, encoding="utf-8")
|
|
464
|
+
except OSError as e:
|
|
465
|
+
raise OSError(f"Cannot write DOT file to {output_path}: {e}") from e
|
|
466
|
+
except Exception as e:
|
|
467
|
+
raise GraphGenerationError(f"Failed to save DOT file: {e}") from e
|
|
468
|
+
|
|
469
|
+
def save_mermaid(self, graph: ExecutionGraph, output_path: Path) -> None:
|
|
470
|
+
"""
|
|
471
|
+
Save graph to Mermaid file.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
graph: ExecutionGraph instance
|
|
475
|
+
output_path: Output file path
|
|
476
|
+
|
|
477
|
+
Raises:
|
|
478
|
+
ValueError: If graph or output_path is invalid
|
|
479
|
+
OSError: If file cannot be written
|
|
480
|
+
"""
|
|
481
|
+
if not graph:
|
|
482
|
+
raise ValueError("Graph instance required")
|
|
483
|
+
|
|
484
|
+
if not output_path:
|
|
485
|
+
raise ValueError("Output path required")
|
|
486
|
+
|
|
487
|
+
try:
|
|
488
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
489
|
+
except OSError as e:
|
|
490
|
+
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
mermaid_content = graph.to_mermaid()
|
|
494
|
+
output_path.write_text(mermaid_content, encoding="utf-8")
|
|
495
|
+
except OSError as e:
|
|
496
|
+
raise OSError(f"Cannot write Mermaid file to {output_path}: {e}") from e
|
|
497
|
+
except Exception as e:
|
|
498
|
+
raise GraphGenerationError(f"Failed to save Mermaid file: {e}") from e
|