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,451 +1,451 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Observability Dashboard
|
|
3
|
-
|
|
4
|
-
Correlates metrics, traces, and logs for comprehensive workflow observability.
|
|
5
|
-
Supports OpenTelemetry export for integration with external tools.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import json
|
|
11
|
-
import logging
|
|
12
|
-
from dataclasses import asdict
|
|
13
|
-
from datetime import datetime, UTC
|
|
14
|
-
from pathlib import Path
|
|
15
|
-
from typing import Any
|
|
16
|
-
|
|
17
|
-
from .event_log import WorkflowEventLog
|
|
18
|
-
from .execution_graph import ExecutionGraph, ExecutionGraphGenerator
|
|
19
|
-
from .execution_metrics import ExecutionMetricsCollector, ExecutionMetric
|
|
20
|
-
from .exceptions import (
|
|
21
|
-
DashboardGenerationError,
|
|
22
|
-
OpenTelemetryExportError,
|
|
23
|
-
)
|
|
24
|
-
from ..core.exceptions import WorkflowNotFoundError
|
|
25
|
-
|
|
26
|
-
logger = logging.getLogger(__name__)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class ObservabilityDashboard:
|
|
30
|
-
"""Observability dashboard that correlates metrics, traces, and logs."""
|
|
31
|
-
|
|
32
|
-
def __init__(
|
|
33
|
-
self,
|
|
34
|
-
project_root: Path | None = None,
|
|
35
|
-
event_log: WorkflowEventLog | None = None,
|
|
36
|
-
metrics_collector: ExecutionMetricsCollector | None = None,
|
|
37
|
-
):
|
|
38
|
-
"""
|
|
39
|
-
Initialize observability dashboard.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
project_root: Project root directory
|
|
43
|
-
event_log: Optional WorkflowEventLog instance
|
|
44
|
-
metrics_collector: Optional ExecutionMetricsCollector instance
|
|
45
|
-
"""
|
|
46
|
-
self.project_root = project_root or Path.cwd()
|
|
47
|
-
self.event_log = event_log
|
|
48
|
-
self.metrics_collector = metrics_collector
|
|
49
|
-
self.graph_generator = ExecutionGraphGenerator(event_log=event_log)
|
|
50
|
-
|
|
51
|
-
def generate_dashboard(
|
|
52
|
-
self, workflow_id: str | None = None
|
|
53
|
-
) -> dict[str, Any]:
|
|
54
|
-
"""
|
|
55
|
-
Generate comprehensive dashboard data.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
workflow_id: Optional workflow ID (if None, shows all workflows)
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
Dashboard data dictionary
|
|
62
|
-
|
|
63
|
-
Raises:
|
|
64
|
-
ValueError: If workflow_id format is invalid
|
|
65
|
-
DashboardGenerationError: If dashboard generation fails
|
|
66
|
-
"""
|
|
67
|
-
# Validate workflow_id format if provided
|
|
68
|
-
if workflow_id is not None:
|
|
69
|
-
if not isinstance(workflow_id, str) or not workflow_id.strip():
|
|
70
|
-
raise ValueError("workflow_id must be a non-empty string")
|
|
71
|
-
|
|
72
|
-
try:
|
|
73
|
-
dashboard: dict[str, Any] = {
|
|
74
|
-
"generated_at": datetime.now(UTC).isoformat() + "Z",
|
|
75
|
-
"workflow_id": workflow_id,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if workflow_id:
|
|
79
|
-
# Single workflow dashboard
|
|
80
|
-
dashboard.update(self._generate_workflow_dashboard(workflow_id))
|
|
81
|
-
else:
|
|
82
|
-
# Multi-workflow overview
|
|
83
|
-
dashboard.update(self._generate_overview_dashboard())
|
|
84
|
-
|
|
85
|
-
return dashboard
|
|
86
|
-
except (ValueError, WorkflowNotFoundError):
|
|
87
|
-
# Re-raise validation errors
|
|
88
|
-
raise
|
|
89
|
-
except Exception as e:
|
|
90
|
-
raise DashboardGenerationError(f"Failed to generate dashboard: {e}") from e
|
|
91
|
-
|
|
92
|
-
def _generate_workflow_dashboard(self, workflow_id: str) -> dict[str, Any]:
|
|
93
|
-
"""
|
|
94
|
-
Generate dashboard for a single workflow with graceful degradation.
|
|
95
|
-
|
|
96
|
-
Args:
|
|
97
|
-
workflow_id: Workflow ID
|
|
98
|
-
|
|
99
|
-
Returns:
|
|
100
|
-
Dashboard data dictionary with available data (partial if some sources unavailable)
|
|
101
|
-
"""
|
|
102
|
-
dashboard: dict[str, Any] = {}
|
|
103
|
-
|
|
104
|
-
# Get execution trace if available
|
|
105
|
-
trace = None
|
|
106
|
-
if self.event_log:
|
|
107
|
-
try:
|
|
108
|
-
trace = self.event_log.get_execution_trace(workflow_id)
|
|
109
|
-
dashboard["trace"] = trace
|
|
110
|
-
except (FileNotFoundError, KeyError) as e:
|
|
111
|
-
dashboard["trace_error"] = f"Trace not found: {e}"
|
|
112
|
-
logger.warning(f"Trace not found for workflow {workflow_id}: {e}")
|
|
113
|
-
except Exception as e:
|
|
114
|
-
dashboard["trace_error"] = f"Failed to load trace: {e}"
|
|
115
|
-
logger.warning(f"Failed to load trace for workflow {workflow_id}: {e}")
|
|
116
|
-
|
|
117
|
-
# Generate execution graph if trace available
|
|
118
|
-
if trace and self.graph_generator:
|
|
119
|
-
try:
|
|
120
|
-
graph = self.graph_generator.generate_graph(workflow_id)
|
|
121
|
-
dashboard["graph"] = {
|
|
122
|
-
"nodes": len(graph.nodes),
|
|
123
|
-
"edges": len(graph.edges),
|
|
124
|
-
"dot": graph.to_dot(),
|
|
125
|
-
"mermaid": graph.to_mermaid(),
|
|
126
|
-
}
|
|
127
|
-
except Exception as e:
|
|
128
|
-
dashboard["graph_error"] = str(e)
|
|
129
|
-
logger.warning(f"Failed to generate graph for workflow {workflow_id}: {e}")
|
|
130
|
-
|
|
131
|
-
# Get events if event_log available
|
|
132
|
-
if self.event_log:
|
|
133
|
-
try:
|
|
134
|
-
events = self.event_log.read_events(workflow_id)
|
|
135
|
-
dashboard["events"] = {
|
|
136
|
-
"total": len(events),
|
|
137
|
-
"by_type": self._count_events_by_type(events),
|
|
138
|
-
}
|
|
139
|
-
except Exception as e:
|
|
140
|
-
dashboard["events_error"] = str(e)
|
|
141
|
-
logger.warning(f"Failed to read events for workflow {workflow_id}: {e}")
|
|
142
|
-
|
|
143
|
-
# Get metrics if metrics_collector available
|
|
144
|
-
if self.metrics_collector:
|
|
145
|
-
try:
|
|
146
|
-
metrics = self.metrics_collector.get_metrics(
|
|
147
|
-
workflow_id=workflow_id, limit=1000
|
|
148
|
-
)
|
|
149
|
-
dashboard["metrics"] = self._aggregate_metrics(metrics)
|
|
150
|
-
except Exception as e:
|
|
151
|
-
dashboard["metrics_error"] = str(e)
|
|
152
|
-
logger.warning(f"Failed to get metrics for workflow {workflow_id}: {e}")
|
|
153
|
-
|
|
154
|
-
# Correlate data if both trace and metrics available
|
|
155
|
-
if trace and dashboard.get("metrics"):
|
|
156
|
-
try:
|
|
157
|
-
dashboard["correlation"] = self._correlate_data(
|
|
158
|
-
workflow_id, trace, dashboard["metrics"]
|
|
159
|
-
)
|
|
160
|
-
except Exception as e:
|
|
161
|
-
dashboard["correlation_error"] = str(e)
|
|
162
|
-
logger.warning(f"Failed to correlate data for workflow {workflow_id}: {e}")
|
|
163
|
-
|
|
164
|
-
return dashboard
|
|
165
|
-
|
|
166
|
-
def _generate_overview_dashboard(self) -> dict[str, Any]:
|
|
167
|
-
"""Generate overview dashboard for all workflows."""
|
|
168
|
-
dashboard: dict[str, Any] = {
|
|
169
|
-
"workflows": [],
|
|
170
|
-
"summary": {},
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
# Find all workflow event files
|
|
174
|
-
if self.event_log:
|
|
175
|
-
events_dir = self.event_log.events_dir
|
|
176
|
-
if events_dir.exists():
|
|
177
|
-
event_files = list(events_dir.glob("*.events.jsonl"))
|
|
178
|
-
workflow_ids = [
|
|
179
|
-
f.stem.replace(".events", "") for f in event_files
|
|
180
|
-
]
|
|
181
|
-
|
|
182
|
-
for wf_id in workflow_ids:
|
|
183
|
-
try:
|
|
184
|
-
wf_data = self._generate_workflow_dashboard(wf_id)
|
|
185
|
-
wf_data["workflow_id"] = wf_id
|
|
186
|
-
dashboard["workflows"].append(wf_data)
|
|
187
|
-
except Exception as e:
|
|
188
|
-
dashboard["workflows"].append(
|
|
189
|
-
{"workflow_id": wf_id, "error": str(e)}
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
# Generate summary
|
|
193
|
-
dashboard["summary"] = self._generate_summary(
|
|
194
|
-
dashboard["workflows"]
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
return dashboard
|
|
198
|
-
|
|
199
|
-
def _count_events_by_type(self, events: list[Any]) -> dict[str, int]:
|
|
200
|
-
"""Count events by type."""
|
|
201
|
-
counts: dict[str, int] = {}
|
|
202
|
-
for event in events:
|
|
203
|
-
event_type = event.event_type if hasattr(event, "event_type") else str(event.get("event_type", "unknown"))
|
|
204
|
-
counts[event_type] = counts.get(event_type, 0) + 1
|
|
205
|
-
return counts
|
|
206
|
-
|
|
207
|
-
def _aggregate_metrics(
|
|
208
|
-
self, metrics: list[ExecutionMetric]
|
|
209
|
-
) -> dict[str, Any]:
|
|
210
|
-
"""Aggregate metrics data."""
|
|
211
|
-
if not metrics:
|
|
212
|
-
return {}
|
|
213
|
-
|
|
214
|
-
total_duration = sum(m.duration_ms for m in metrics if m.duration_ms)
|
|
215
|
-
avg_duration = total_duration / len(metrics) if metrics else 0
|
|
216
|
-
|
|
217
|
-
status_counts: dict[str, int] = {}
|
|
218
|
-
for metric in metrics:
|
|
219
|
-
status = metric.status or "unknown"
|
|
220
|
-
status_counts[status] = status_counts.get(status, 0) + 1
|
|
221
|
-
|
|
222
|
-
return {
|
|
223
|
-
"total_executions": len(metrics),
|
|
224
|
-
"total_duration_ms": total_duration,
|
|
225
|
-
"avg_duration_ms": avg_duration,
|
|
226
|
-
"status_counts": status_counts,
|
|
227
|
-
"retry_count": sum(m.retry_count for m in metrics),
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
def _correlate_data(
|
|
231
|
-
self,
|
|
232
|
-
workflow_id: str,
|
|
233
|
-
trace: dict[str, Any] | None,
|
|
234
|
-
metrics: dict[str, Any] | None,
|
|
235
|
-
) -> dict[str, Any]:
|
|
236
|
-
"""Correlate trace and metrics data."""
|
|
237
|
-
correlation: dict[str, Any] = {}
|
|
238
|
-
|
|
239
|
-
if trace and metrics:
|
|
240
|
-
# Match steps with metrics
|
|
241
|
-
steps = trace.get("steps", [])
|
|
242
|
-
step_metrics: dict[str, list[dict[str, Any]]] = {}
|
|
243
|
-
|
|
244
|
-
if self.metrics_collector:
|
|
245
|
-
all_metrics = self.metrics_collector.get_metrics(
|
|
246
|
-
workflow_id=workflow_id, limit=1000
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
for step in steps:
|
|
250
|
-
step_id = step.get("step_id")
|
|
251
|
-
if step_id:
|
|
252
|
-
step_metrics[step_id] = [
|
|
253
|
-
asdict(m)
|
|
254
|
-
for m in all_metrics
|
|
255
|
-
if m.step_id == step_id
|
|
256
|
-
]
|
|
257
|
-
|
|
258
|
-
correlation["step_metrics"] = step_metrics
|
|
259
|
-
|
|
260
|
-
# Identify bottlenecks
|
|
261
|
-
if steps:
|
|
262
|
-
durations = [
|
|
263
|
-
s.get("duration_ms", 0) for s in steps if s.get("duration_ms")
|
|
264
|
-
]
|
|
265
|
-
if durations:
|
|
266
|
-
max_duration = max(durations)
|
|
267
|
-
bottleneck_step = next(
|
|
268
|
-
(
|
|
269
|
-
s
|
|
270
|
-
for s in steps
|
|
271
|
-
if s.get("duration_ms") == max_duration
|
|
272
|
-
),
|
|
273
|
-
None,
|
|
274
|
-
)
|
|
275
|
-
if bottleneck_step:
|
|
276
|
-
correlation["bottleneck"] = {
|
|
277
|
-
"step_id": bottleneck_step.get("step_id"),
|
|
278
|
-
"duration_ms": max_duration,
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return correlation
|
|
282
|
-
|
|
283
|
-
def _generate_summary(self, workflows: list[dict[str, Any]]) -> dict[str, Any]:
|
|
284
|
-
"""Generate summary statistics."""
|
|
285
|
-
total_workflows = len(workflows)
|
|
286
|
-
completed = sum(
|
|
287
|
-
1
|
|
288
|
-
for wf in workflows
|
|
289
|
-
if wf.get("trace", {}).get("ended_at") is not None
|
|
290
|
-
)
|
|
291
|
-
failed = sum(
|
|
292
|
-
1
|
|
293
|
-
for wf in workflows
|
|
294
|
-
if any(
|
|
295
|
-
step.get("status") == "failed"
|
|
296
|
-
for step in wf.get("trace", {}).get("steps", [])
|
|
297
|
-
)
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
total_steps = sum(
|
|
301
|
-
len(wf.get("trace", {}).get("steps", [])) for wf in workflows
|
|
302
|
-
)
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
"total_workflows": total_workflows,
|
|
306
|
-
"completed": completed,
|
|
307
|
-
"failed": failed,
|
|
308
|
-
"in_progress": total_workflows - completed,
|
|
309
|
-
"total_steps": total_steps,
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
def export_otel_trace(self, workflow_id: str) -> dict[str, Any]:
|
|
313
|
-
"""
|
|
314
|
-
Export workflow trace to OpenTelemetry format.
|
|
315
|
-
|
|
316
|
-
Args:
|
|
317
|
-
workflow_id: Workflow ID
|
|
318
|
-
|
|
319
|
-
Returns:
|
|
320
|
-
OpenTelemetry trace dictionary
|
|
321
|
-
|
|
322
|
-
Raises:
|
|
323
|
-
ValueError: If workflow_id is invalid
|
|
324
|
-
OpenTelemetryExportError: If export fails
|
|
325
|
-
"""
|
|
326
|
-
# Validate inputs
|
|
327
|
-
if not workflow_id or not isinstance(workflow_id, str):
|
|
328
|
-
raise ValueError("workflow_id must be a non-empty string")
|
|
329
|
-
|
|
330
|
-
if not self.event_log:
|
|
331
|
-
raise ValueError("WorkflowEventLog required for OpenTelemetry export")
|
|
332
|
-
|
|
333
|
-
try:
|
|
334
|
-
trace = self.event_log.get_execution_trace(workflow_id)
|
|
335
|
-
except FileNotFoundError as e:
|
|
336
|
-
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found") from e
|
|
337
|
-
except Exception as e:
|
|
338
|
-
raise OpenTelemetryExportError(f"Failed to load trace for workflow {workflow_id}: {e}") from e
|
|
339
|
-
|
|
340
|
-
if not trace or not isinstance(trace, dict):
|
|
341
|
-
raise OpenTelemetryExportError(f"Invalid trace structure for workflow {workflow_id}")
|
|
342
|
-
|
|
343
|
-
if not trace.get("steps"):
|
|
344
|
-
raise OpenTelemetryExportError(f"Workflow {workflow_id} has no steps to export")
|
|
345
|
-
|
|
346
|
-
# Convert to OpenTelemetry format
|
|
347
|
-
try:
|
|
348
|
-
otel_trace = {
|
|
349
|
-
"resourceSpans": [
|
|
350
|
-
{
|
|
351
|
-
"resource": {
|
|
352
|
-
"attributes": [
|
|
353
|
-
{"key": "service.name", "value": {"stringValue": "tapps-agents"}},
|
|
354
|
-
{"key": "workflow.id", "value": {"stringValue": workflow_id}},
|
|
355
|
-
]
|
|
356
|
-
},
|
|
357
|
-
"scopeSpans": [
|
|
358
|
-
{
|
|
359
|
-
"spans": self._convert_steps_to_spans(trace.get("steps", [])),
|
|
360
|
-
}
|
|
361
|
-
],
|
|
362
|
-
}
|
|
363
|
-
]
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
return otel_trace
|
|
367
|
-
except Exception as e:
|
|
368
|
-
raise OpenTelemetryExportError(f"Failed to convert trace to OpenTelemetry format: {e}") from e
|
|
369
|
-
|
|
370
|
-
def _convert_steps_to_spans(self, steps: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
371
|
-
"""Convert workflow steps to OpenTelemetry spans."""
|
|
372
|
-
spans = []
|
|
373
|
-
|
|
374
|
-
for step in steps:
|
|
375
|
-
span = {
|
|
376
|
-
"traceId": step.get("step_id", ""),
|
|
377
|
-
"spanId": step.get("step_id", ""),
|
|
378
|
-
"name": f"{step.get('agent', 'unknown')}.{step.get('action', 'unknown')}",
|
|
379
|
-
"startTimeUnixNano": self._iso_to_nanos(step.get("started_at")),
|
|
380
|
-
"endTimeUnixNano": self._iso_to_nanos(step.get("ended_at")),
|
|
381
|
-
"attributes": [
|
|
382
|
-
{"key": "step.id", "value": {"stringValue": step.get("step_id", "")}},
|
|
383
|
-
{"key": "agent", "value": {"stringValue": step.get("agent", "")}},
|
|
384
|
-
{"key": "action", "value": {"stringValue": step.get("action", "")}},
|
|
385
|
-
{"key": "status", "value": {"stringValue": step.get("status", "")}},
|
|
386
|
-
],
|
|
387
|
-
"status": {
|
|
388
|
-
"code": 1 if step.get("status") == "failed" else 2,
|
|
389
|
-
},
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if step.get("duration_ms"):
|
|
393
|
-
span["attributes"].append({
|
|
394
|
-
"key": "duration.ms",
|
|
395
|
-
"value": {"doubleValue": step.get("duration_ms")},
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
if step.get("error"):
|
|
399
|
-
span["status"]["message"] = step.get("error")
|
|
400
|
-
|
|
401
|
-
spans.append(span)
|
|
402
|
-
|
|
403
|
-
return spans
|
|
404
|
-
|
|
405
|
-
def _iso_to_nanos(self, iso_str: str | None) -> int:
|
|
406
|
-
"""Convert ISO timestamp to nanoseconds."""
|
|
407
|
-
if not iso_str:
|
|
408
|
-
return 0
|
|
409
|
-
|
|
410
|
-
try:
|
|
411
|
-
# Remove Z and parse
|
|
412
|
-
dt_str = iso_str.replace("Z", "+00:00")
|
|
413
|
-
dt = datetime.fromisoformat(dt_str)
|
|
414
|
-
# Convert to nanoseconds since epoch
|
|
415
|
-
return int(dt.timestamp() * 1_000_000_000)
|
|
416
|
-
except Exception:
|
|
417
|
-
return 0
|
|
418
|
-
|
|
419
|
-
def save_dashboard(
|
|
420
|
-
self, dashboard: dict[str, Any], output_path: Path
|
|
421
|
-
) -> None:
|
|
422
|
-
"""
|
|
423
|
-
Save dashboard data to JSON file.
|
|
424
|
-
|
|
425
|
-
Args:
|
|
426
|
-
dashboard: Dashboard data dictionary
|
|
427
|
-
output_path: Output file path
|
|
428
|
-
|
|
429
|
-
Raises:
|
|
430
|
-
ValueError: If dashboard or output_path is invalid
|
|
431
|
-
OSError: If file cannot be written
|
|
432
|
-
"""
|
|
433
|
-
if not dashboard:
|
|
434
|
-
raise ValueError("Dashboard data required")
|
|
435
|
-
|
|
436
|
-
if not output_path:
|
|
437
|
-
raise ValueError("Output path required")
|
|
438
|
-
|
|
439
|
-
try:
|
|
440
|
-
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
441
|
-
except OSError as e:
|
|
442
|
-
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
443
|
-
|
|
444
|
-
try:
|
|
445
|
-
output_path.write_text(
|
|
446
|
-
json.dumps(dashboard, indent=2, default=str), encoding="utf-8"
|
|
447
|
-
)
|
|
448
|
-
except OSError as e:
|
|
449
|
-
raise OSError(f"Cannot write dashboard file to {output_path}: {e}") from e
|
|
450
|
-
except Exception as e:
|
|
451
|
-
raise DashboardGenerationError(f"Failed to save dashboard: {e}") from e
|
|
1
|
+
"""
|
|
2
|
+
Observability Dashboard
|
|
3
|
+
|
|
4
|
+
Correlates metrics, traces, and logs for comprehensive workflow observability.
|
|
5
|
+
Supports OpenTelemetry export for integration with external tools.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from dataclasses import asdict
|
|
13
|
+
from datetime import datetime, UTC
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
from .event_log import WorkflowEventLog
|
|
18
|
+
from .execution_graph import ExecutionGraph, ExecutionGraphGenerator
|
|
19
|
+
from .execution_metrics import ExecutionMetricsCollector, ExecutionMetric
|
|
20
|
+
from .exceptions import (
|
|
21
|
+
DashboardGenerationError,
|
|
22
|
+
OpenTelemetryExportError,
|
|
23
|
+
)
|
|
24
|
+
from ..core.exceptions import WorkflowNotFoundError
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ObservabilityDashboard:
|
|
30
|
+
"""Observability dashboard that correlates metrics, traces, and logs."""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
project_root: Path | None = None,
|
|
35
|
+
event_log: WorkflowEventLog | None = None,
|
|
36
|
+
metrics_collector: ExecutionMetricsCollector | None = None,
|
|
37
|
+
):
|
|
38
|
+
"""
|
|
39
|
+
Initialize observability dashboard.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
project_root: Project root directory
|
|
43
|
+
event_log: Optional WorkflowEventLog instance
|
|
44
|
+
metrics_collector: Optional ExecutionMetricsCollector instance
|
|
45
|
+
"""
|
|
46
|
+
self.project_root = project_root or Path.cwd()
|
|
47
|
+
self.event_log = event_log
|
|
48
|
+
self.metrics_collector = metrics_collector
|
|
49
|
+
self.graph_generator = ExecutionGraphGenerator(event_log=event_log)
|
|
50
|
+
|
|
51
|
+
def generate_dashboard(
|
|
52
|
+
self, workflow_id: str | None = None
|
|
53
|
+
) -> dict[str, Any]:
|
|
54
|
+
"""
|
|
55
|
+
Generate comprehensive dashboard data.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
workflow_id: Optional workflow ID (if None, shows all workflows)
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Dashboard data dictionary
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
ValueError: If workflow_id format is invalid
|
|
65
|
+
DashboardGenerationError: If dashboard generation fails
|
|
66
|
+
"""
|
|
67
|
+
# Validate workflow_id format if provided
|
|
68
|
+
if workflow_id is not None:
|
|
69
|
+
if not isinstance(workflow_id, str) or not workflow_id.strip():
|
|
70
|
+
raise ValueError("workflow_id must be a non-empty string")
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
dashboard: dict[str, Any] = {
|
|
74
|
+
"generated_at": datetime.now(UTC).isoformat() + "Z",
|
|
75
|
+
"workflow_id": workflow_id,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if workflow_id:
|
|
79
|
+
# Single workflow dashboard
|
|
80
|
+
dashboard.update(self._generate_workflow_dashboard(workflow_id))
|
|
81
|
+
else:
|
|
82
|
+
# Multi-workflow overview
|
|
83
|
+
dashboard.update(self._generate_overview_dashboard())
|
|
84
|
+
|
|
85
|
+
return dashboard
|
|
86
|
+
except (ValueError, WorkflowNotFoundError):
|
|
87
|
+
# Re-raise validation errors
|
|
88
|
+
raise
|
|
89
|
+
except Exception as e:
|
|
90
|
+
raise DashboardGenerationError(f"Failed to generate dashboard: {e}") from e
|
|
91
|
+
|
|
92
|
+
def _generate_workflow_dashboard(self, workflow_id: str) -> dict[str, Any]:
|
|
93
|
+
"""
|
|
94
|
+
Generate dashboard for a single workflow with graceful degradation.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
workflow_id: Workflow ID
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Dashboard data dictionary with available data (partial if some sources unavailable)
|
|
101
|
+
"""
|
|
102
|
+
dashboard: dict[str, Any] = {}
|
|
103
|
+
|
|
104
|
+
# Get execution trace if available
|
|
105
|
+
trace = None
|
|
106
|
+
if self.event_log:
|
|
107
|
+
try:
|
|
108
|
+
trace = self.event_log.get_execution_trace(workflow_id)
|
|
109
|
+
dashboard["trace"] = trace
|
|
110
|
+
except (FileNotFoundError, KeyError) as e:
|
|
111
|
+
dashboard["trace_error"] = f"Trace not found: {e}"
|
|
112
|
+
logger.warning(f"Trace not found for workflow {workflow_id}: {e}")
|
|
113
|
+
except Exception as e:
|
|
114
|
+
dashboard["trace_error"] = f"Failed to load trace: {e}"
|
|
115
|
+
logger.warning(f"Failed to load trace for workflow {workflow_id}: {e}")
|
|
116
|
+
|
|
117
|
+
# Generate execution graph if trace available
|
|
118
|
+
if trace and self.graph_generator:
|
|
119
|
+
try:
|
|
120
|
+
graph = self.graph_generator.generate_graph(workflow_id)
|
|
121
|
+
dashboard["graph"] = {
|
|
122
|
+
"nodes": len(graph.nodes),
|
|
123
|
+
"edges": len(graph.edges),
|
|
124
|
+
"dot": graph.to_dot(),
|
|
125
|
+
"mermaid": graph.to_mermaid(),
|
|
126
|
+
}
|
|
127
|
+
except Exception as e:
|
|
128
|
+
dashboard["graph_error"] = str(e)
|
|
129
|
+
logger.warning(f"Failed to generate graph for workflow {workflow_id}: {e}")
|
|
130
|
+
|
|
131
|
+
# Get events if event_log available
|
|
132
|
+
if self.event_log:
|
|
133
|
+
try:
|
|
134
|
+
events = self.event_log.read_events(workflow_id)
|
|
135
|
+
dashboard["events"] = {
|
|
136
|
+
"total": len(events),
|
|
137
|
+
"by_type": self._count_events_by_type(events),
|
|
138
|
+
}
|
|
139
|
+
except Exception as e:
|
|
140
|
+
dashboard["events_error"] = str(e)
|
|
141
|
+
logger.warning(f"Failed to read events for workflow {workflow_id}: {e}")
|
|
142
|
+
|
|
143
|
+
# Get metrics if metrics_collector available
|
|
144
|
+
if self.metrics_collector:
|
|
145
|
+
try:
|
|
146
|
+
metrics = self.metrics_collector.get_metrics(
|
|
147
|
+
workflow_id=workflow_id, limit=1000
|
|
148
|
+
)
|
|
149
|
+
dashboard["metrics"] = self._aggregate_metrics(metrics)
|
|
150
|
+
except Exception as e:
|
|
151
|
+
dashboard["metrics_error"] = str(e)
|
|
152
|
+
logger.warning(f"Failed to get metrics for workflow {workflow_id}: {e}")
|
|
153
|
+
|
|
154
|
+
# Correlate data if both trace and metrics available
|
|
155
|
+
if trace and dashboard.get("metrics"):
|
|
156
|
+
try:
|
|
157
|
+
dashboard["correlation"] = self._correlate_data(
|
|
158
|
+
workflow_id, trace, dashboard["metrics"]
|
|
159
|
+
)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
dashboard["correlation_error"] = str(e)
|
|
162
|
+
logger.warning(f"Failed to correlate data for workflow {workflow_id}: {e}")
|
|
163
|
+
|
|
164
|
+
return dashboard
|
|
165
|
+
|
|
166
|
+
def _generate_overview_dashboard(self) -> dict[str, Any]:
|
|
167
|
+
"""Generate overview dashboard for all workflows."""
|
|
168
|
+
dashboard: dict[str, Any] = {
|
|
169
|
+
"workflows": [],
|
|
170
|
+
"summary": {},
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
# Find all workflow event files
|
|
174
|
+
if self.event_log:
|
|
175
|
+
events_dir = self.event_log.events_dir
|
|
176
|
+
if events_dir.exists():
|
|
177
|
+
event_files = list(events_dir.glob("*.events.jsonl"))
|
|
178
|
+
workflow_ids = [
|
|
179
|
+
f.stem.replace(".events", "") for f in event_files
|
|
180
|
+
]
|
|
181
|
+
|
|
182
|
+
for wf_id in workflow_ids:
|
|
183
|
+
try:
|
|
184
|
+
wf_data = self._generate_workflow_dashboard(wf_id)
|
|
185
|
+
wf_data["workflow_id"] = wf_id
|
|
186
|
+
dashboard["workflows"].append(wf_data)
|
|
187
|
+
except Exception as e:
|
|
188
|
+
dashboard["workflows"].append(
|
|
189
|
+
{"workflow_id": wf_id, "error": str(e)}
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Generate summary
|
|
193
|
+
dashboard["summary"] = self._generate_summary(
|
|
194
|
+
dashboard["workflows"]
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
return dashboard
|
|
198
|
+
|
|
199
|
+
def _count_events_by_type(self, events: list[Any]) -> dict[str, int]:
|
|
200
|
+
"""Count events by type."""
|
|
201
|
+
counts: dict[str, int] = {}
|
|
202
|
+
for event in events:
|
|
203
|
+
event_type = event.event_type if hasattr(event, "event_type") else str(event.get("event_type", "unknown"))
|
|
204
|
+
counts[event_type] = counts.get(event_type, 0) + 1
|
|
205
|
+
return counts
|
|
206
|
+
|
|
207
|
+
def _aggregate_metrics(
|
|
208
|
+
self, metrics: list[ExecutionMetric]
|
|
209
|
+
) -> dict[str, Any]:
|
|
210
|
+
"""Aggregate metrics data."""
|
|
211
|
+
if not metrics:
|
|
212
|
+
return {}
|
|
213
|
+
|
|
214
|
+
total_duration = sum(m.duration_ms for m in metrics if m.duration_ms)
|
|
215
|
+
avg_duration = total_duration / len(metrics) if metrics else 0
|
|
216
|
+
|
|
217
|
+
status_counts: dict[str, int] = {}
|
|
218
|
+
for metric in metrics:
|
|
219
|
+
status = metric.status or "unknown"
|
|
220
|
+
status_counts[status] = status_counts.get(status, 0) + 1
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
"total_executions": len(metrics),
|
|
224
|
+
"total_duration_ms": total_duration,
|
|
225
|
+
"avg_duration_ms": avg_duration,
|
|
226
|
+
"status_counts": status_counts,
|
|
227
|
+
"retry_count": sum(m.retry_count for m in metrics),
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
def _correlate_data(
|
|
231
|
+
self,
|
|
232
|
+
workflow_id: str,
|
|
233
|
+
trace: dict[str, Any] | None,
|
|
234
|
+
metrics: dict[str, Any] | None,
|
|
235
|
+
) -> dict[str, Any]:
|
|
236
|
+
"""Correlate trace and metrics data."""
|
|
237
|
+
correlation: dict[str, Any] = {}
|
|
238
|
+
|
|
239
|
+
if trace and metrics:
|
|
240
|
+
# Match steps with metrics
|
|
241
|
+
steps = trace.get("steps", [])
|
|
242
|
+
step_metrics: dict[str, list[dict[str, Any]]] = {}
|
|
243
|
+
|
|
244
|
+
if self.metrics_collector:
|
|
245
|
+
all_metrics = self.metrics_collector.get_metrics(
|
|
246
|
+
workflow_id=workflow_id, limit=1000
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
for step in steps:
|
|
250
|
+
step_id = step.get("step_id")
|
|
251
|
+
if step_id:
|
|
252
|
+
step_metrics[step_id] = [
|
|
253
|
+
asdict(m)
|
|
254
|
+
for m in all_metrics
|
|
255
|
+
if m.step_id == step_id
|
|
256
|
+
]
|
|
257
|
+
|
|
258
|
+
correlation["step_metrics"] = step_metrics
|
|
259
|
+
|
|
260
|
+
# Identify bottlenecks
|
|
261
|
+
if steps:
|
|
262
|
+
durations = [
|
|
263
|
+
s.get("duration_ms", 0) for s in steps if s.get("duration_ms")
|
|
264
|
+
]
|
|
265
|
+
if durations:
|
|
266
|
+
max_duration = max(durations)
|
|
267
|
+
bottleneck_step = next(
|
|
268
|
+
(
|
|
269
|
+
s
|
|
270
|
+
for s in steps
|
|
271
|
+
if s.get("duration_ms") == max_duration
|
|
272
|
+
),
|
|
273
|
+
None,
|
|
274
|
+
)
|
|
275
|
+
if bottleneck_step:
|
|
276
|
+
correlation["bottleneck"] = {
|
|
277
|
+
"step_id": bottleneck_step.get("step_id"),
|
|
278
|
+
"duration_ms": max_duration,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return correlation
|
|
282
|
+
|
|
283
|
+
def _generate_summary(self, workflows: list[dict[str, Any]]) -> dict[str, Any]:
|
|
284
|
+
"""Generate summary statistics."""
|
|
285
|
+
total_workflows = len(workflows)
|
|
286
|
+
completed = sum(
|
|
287
|
+
1
|
|
288
|
+
for wf in workflows
|
|
289
|
+
if wf.get("trace", {}).get("ended_at") is not None
|
|
290
|
+
)
|
|
291
|
+
failed = sum(
|
|
292
|
+
1
|
|
293
|
+
for wf in workflows
|
|
294
|
+
if any(
|
|
295
|
+
step.get("status") == "failed"
|
|
296
|
+
for step in wf.get("trace", {}).get("steps", [])
|
|
297
|
+
)
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
total_steps = sum(
|
|
301
|
+
len(wf.get("trace", {}).get("steps", [])) for wf in workflows
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
"total_workflows": total_workflows,
|
|
306
|
+
"completed": completed,
|
|
307
|
+
"failed": failed,
|
|
308
|
+
"in_progress": total_workflows - completed,
|
|
309
|
+
"total_steps": total_steps,
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
def export_otel_trace(self, workflow_id: str) -> dict[str, Any]:
|
|
313
|
+
"""
|
|
314
|
+
Export workflow trace to OpenTelemetry format.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
workflow_id: Workflow ID
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
OpenTelemetry trace dictionary
|
|
321
|
+
|
|
322
|
+
Raises:
|
|
323
|
+
ValueError: If workflow_id is invalid
|
|
324
|
+
OpenTelemetryExportError: If export fails
|
|
325
|
+
"""
|
|
326
|
+
# Validate inputs
|
|
327
|
+
if not workflow_id or not isinstance(workflow_id, str):
|
|
328
|
+
raise ValueError("workflow_id must be a non-empty string")
|
|
329
|
+
|
|
330
|
+
if not self.event_log:
|
|
331
|
+
raise ValueError("WorkflowEventLog required for OpenTelemetry export")
|
|
332
|
+
|
|
333
|
+
try:
|
|
334
|
+
trace = self.event_log.get_execution_trace(workflow_id)
|
|
335
|
+
except FileNotFoundError as e:
|
|
336
|
+
raise WorkflowNotFoundError(f"Workflow {workflow_id} not found") from e
|
|
337
|
+
except Exception as e:
|
|
338
|
+
raise OpenTelemetryExportError(f"Failed to load trace for workflow {workflow_id}: {e}") from e
|
|
339
|
+
|
|
340
|
+
if not trace or not isinstance(trace, dict):
|
|
341
|
+
raise OpenTelemetryExportError(f"Invalid trace structure for workflow {workflow_id}")
|
|
342
|
+
|
|
343
|
+
if not trace.get("steps"):
|
|
344
|
+
raise OpenTelemetryExportError(f"Workflow {workflow_id} has no steps to export")
|
|
345
|
+
|
|
346
|
+
# Convert to OpenTelemetry format
|
|
347
|
+
try:
|
|
348
|
+
otel_trace = {
|
|
349
|
+
"resourceSpans": [
|
|
350
|
+
{
|
|
351
|
+
"resource": {
|
|
352
|
+
"attributes": [
|
|
353
|
+
{"key": "service.name", "value": {"stringValue": "tapps-agents"}},
|
|
354
|
+
{"key": "workflow.id", "value": {"stringValue": workflow_id}},
|
|
355
|
+
]
|
|
356
|
+
},
|
|
357
|
+
"scopeSpans": [
|
|
358
|
+
{
|
|
359
|
+
"spans": self._convert_steps_to_spans(trace.get("steps", [])),
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
}
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return otel_trace
|
|
367
|
+
except Exception as e:
|
|
368
|
+
raise OpenTelemetryExportError(f"Failed to convert trace to OpenTelemetry format: {e}") from e
|
|
369
|
+
|
|
370
|
+
def _convert_steps_to_spans(self, steps: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
|
371
|
+
"""Convert workflow steps to OpenTelemetry spans."""
|
|
372
|
+
spans = []
|
|
373
|
+
|
|
374
|
+
for step in steps:
|
|
375
|
+
span = {
|
|
376
|
+
"traceId": step.get("step_id", ""),
|
|
377
|
+
"spanId": step.get("step_id", ""),
|
|
378
|
+
"name": f"{step.get('agent', 'unknown')}.{step.get('action', 'unknown')}",
|
|
379
|
+
"startTimeUnixNano": self._iso_to_nanos(step.get("started_at")),
|
|
380
|
+
"endTimeUnixNano": self._iso_to_nanos(step.get("ended_at")),
|
|
381
|
+
"attributes": [
|
|
382
|
+
{"key": "step.id", "value": {"stringValue": step.get("step_id", "")}},
|
|
383
|
+
{"key": "agent", "value": {"stringValue": step.get("agent", "")}},
|
|
384
|
+
{"key": "action", "value": {"stringValue": step.get("action", "")}},
|
|
385
|
+
{"key": "status", "value": {"stringValue": step.get("status", "")}},
|
|
386
|
+
],
|
|
387
|
+
"status": {
|
|
388
|
+
"code": 1 if step.get("status") == "failed" else 2,
|
|
389
|
+
},
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if step.get("duration_ms"):
|
|
393
|
+
span["attributes"].append({
|
|
394
|
+
"key": "duration.ms",
|
|
395
|
+
"value": {"doubleValue": step.get("duration_ms")},
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
if step.get("error"):
|
|
399
|
+
span["status"]["message"] = step.get("error")
|
|
400
|
+
|
|
401
|
+
spans.append(span)
|
|
402
|
+
|
|
403
|
+
return spans
|
|
404
|
+
|
|
405
|
+
def _iso_to_nanos(self, iso_str: str | None) -> int:
|
|
406
|
+
"""Convert ISO timestamp to nanoseconds."""
|
|
407
|
+
if not iso_str:
|
|
408
|
+
return 0
|
|
409
|
+
|
|
410
|
+
try:
|
|
411
|
+
# Remove Z and parse
|
|
412
|
+
dt_str = iso_str.replace("Z", "+00:00")
|
|
413
|
+
dt = datetime.fromisoformat(dt_str)
|
|
414
|
+
# Convert to nanoseconds since epoch
|
|
415
|
+
return int(dt.timestamp() * 1_000_000_000)
|
|
416
|
+
except Exception:
|
|
417
|
+
return 0
|
|
418
|
+
|
|
419
|
+
def save_dashboard(
|
|
420
|
+
self, dashboard: dict[str, Any], output_path: Path
|
|
421
|
+
) -> None:
|
|
422
|
+
"""
|
|
423
|
+
Save dashboard data to JSON file.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
dashboard: Dashboard data dictionary
|
|
427
|
+
output_path: Output file path
|
|
428
|
+
|
|
429
|
+
Raises:
|
|
430
|
+
ValueError: If dashboard or output_path is invalid
|
|
431
|
+
OSError: If file cannot be written
|
|
432
|
+
"""
|
|
433
|
+
if not dashboard:
|
|
434
|
+
raise ValueError("Dashboard data required")
|
|
435
|
+
|
|
436
|
+
if not output_path:
|
|
437
|
+
raise ValueError("Output path required")
|
|
438
|
+
|
|
439
|
+
try:
|
|
440
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
441
|
+
except OSError as e:
|
|
442
|
+
raise OSError(f"Cannot create directory for {output_path}: {e}") from e
|
|
443
|
+
|
|
444
|
+
try:
|
|
445
|
+
output_path.write_text(
|
|
446
|
+
json.dumps(dashboard, indent=2, default=str), encoding="utf-8"
|
|
447
|
+
)
|
|
448
|
+
except OSError as e:
|
|
449
|
+
raise OSError(f"Cannot write dashboard file to {output_path}: {e}") from e
|
|
450
|
+
except Exception as e:
|
|
451
|
+
raise DashboardGenerationError(f"Failed to save dashboard: {e}") from e
|