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,744 +1,744 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Expert Registry
|
|
3
|
-
|
|
4
|
-
Manages expert instances and provides consultation services with weighted decision-making.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
# @ai-prime-directive: This file implements the Expert Registry system for weighted expert consultation.
|
|
8
|
-
# The registry manages both built-in framework experts and project-defined industry experts, providing
|
|
9
|
-
# weighted decision aggregation and confidence calculation. This is a core component of the expert system design.
|
|
10
|
-
|
|
11
|
-
# @ai-constraints:
|
|
12
|
-
# - Must maintain separation between built-in experts (framework-controlled) and customer experts (project-defined)
|
|
13
|
-
# - Weight distribution must follow 51% primary authority model for technical domains
|
|
14
|
-
# - Confidence calculation must consider agreement level, expert weights, and domain expertise
|
|
15
|
-
# - Built-in experts have primary authority in TECHNICAL_DOMAINS (see BuiltinExpertRegistry)
|
|
16
|
-
# - Performance: Consultation should complete in <5s for typical queries
|
|
17
|
-
|
|
18
|
-
# @note[2025-01-15]: Expert system design per ADR-003.
|
|
19
|
-
# The registry implements weighted consultation with built-in and project-defined experts.
|
|
20
|
-
# See docs/architecture/decisions/ADR-003-expert-system-design.md
|
|
21
|
-
|
|
22
|
-
from __future__ import annotations
|
|
23
|
-
|
|
24
|
-
from dataclasses import dataclass
|
|
25
|
-
from pathlib import Path
|
|
26
|
-
from typing import Any
|
|
27
|
-
|
|
28
|
-
import yaml
|
|
29
|
-
|
|
30
|
-
from ..core.config import get_expert_config
|
|
31
|
-
from ..core.project_profile import ProjectProfile, load_project_profile
|
|
32
|
-
from .base_expert import BaseExpert
|
|
33
|
-
from .builtin_registry import BuiltinExpertRegistry
|
|
34
|
-
from .confidence_calculator import ConfidenceCalculator
|
|
35
|
-
from .confidence_metrics import get_tracker
|
|
36
|
-
from .domain_config import DomainConfig, DomainConfigParser
|
|
37
|
-
from .expert_config import load_expert_configs
|
|
38
|
-
from .weight_distributor import ExpertWeightMatrix
|
|
39
|
-
|
|
40
|
-
import logging
|
|
41
|
-
|
|
42
|
-
logger = logging.getLogger(__name__)
|
|
43
|
-
|
|
44
|
-
# Technical domains where built-in experts have primary authority
|
|
45
|
-
# These domains are framework-controlled and built-in experts should be prioritized
|
|
46
|
-
TECHNICAL_DOMAINS = BuiltinExpertRegistry.TECHNICAL_DOMAINS
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass
|
|
50
|
-
class ConsultationResult:
|
|
51
|
-
"""Result from consulting multiple experts."""
|
|
52
|
-
|
|
53
|
-
domain: str
|
|
54
|
-
query: str
|
|
55
|
-
responses: list[dict[str, Any]] # Individual expert responses
|
|
56
|
-
weighted_answer: str # Combined weighted answer
|
|
57
|
-
agreement_level: float # 0.0-1.0
|
|
58
|
-
confidence: float # Overall confidence
|
|
59
|
-
confidence_threshold: float # Agent-specific confidence threshold
|
|
60
|
-
primary_expert: str
|
|
61
|
-
all_experts_agreed: bool
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class ExpertRegistry:
|
|
65
|
-
"""
|
|
66
|
-
Registry for managing Industry Expert agents.
|
|
67
|
-
|
|
68
|
-
Provides:
|
|
69
|
-
- Expert instance management
|
|
70
|
-
- Weighted consultation services
|
|
71
|
-
- Decision aggregation
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
def __init__(
|
|
75
|
-
self,
|
|
76
|
-
domain_config: DomainConfig | None = None,
|
|
77
|
-
load_builtin: bool = True,
|
|
78
|
-
project_root: Path | None = None,
|
|
79
|
-
):
|
|
80
|
-
"""
|
|
81
|
-
Initialize expert registry.
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
domain_config: Optional domain configuration (can be loaded later)
|
|
85
|
-
load_builtin: Whether to auto-load built-in framework experts (default: True)
|
|
86
|
-
project_root: Optional project root for profile loading
|
|
87
|
-
"""
|
|
88
|
-
self.domain_config = domain_config
|
|
89
|
-
self.experts: dict[str, BaseExpert] = {}
|
|
90
|
-
self.builtin_experts: dict[str, BaseExpert] = {} # Built-in framework experts
|
|
91
|
-
self.customer_experts: dict[str, BaseExpert] = {} # Customer-configured experts
|
|
92
|
-
self.weight_matrix: ExpertWeightMatrix | None = (
|
|
93
|
-
domain_config.weight_matrix if domain_config else None
|
|
94
|
-
)
|
|
95
|
-
self.project_root = project_root or Path.cwd()
|
|
96
|
-
self._cached_profile: ProjectProfile | None = None
|
|
97
|
-
self._tech_stack_priorities: dict[str, float] | None = None
|
|
98
|
-
|
|
99
|
-
# Auto-load built-in experts if enabled
|
|
100
|
-
if load_builtin:
|
|
101
|
-
self._load_builtin_experts()
|
|
102
|
-
|
|
103
|
-
# Load tech stack priorities if available
|
|
104
|
-
self._load_tech_stack_priorities()
|
|
105
|
-
|
|
106
|
-
def _get_project_profile(self) -> ProjectProfile | None:
|
|
107
|
-
"""
|
|
108
|
-
Get project profile (cached).
|
|
109
|
-
|
|
110
|
-
Returns:
|
|
111
|
-
ProjectProfile if available, None otherwise
|
|
112
|
-
"""
|
|
113
|
-
if self._cached_profile is None:
|
|
114
|
-
self._cached_profile = load_project_profile(project_root=self.project_root)
|
|
115
|
-
return self._cached_profile
|
|
116
|
-
|
|
117
|
-
def _load_tech_stack_priorities(self) -> None:
|
|
118
|
-
"""
|
|
119
|
-
Load expert priorities from tech-stack.yaml config file.
|
|
120
|
-
|
|
121
|
-
Priorities are loaded from `.tapps-agents/tech-stack.yaml` if it exists.
|
|
122
|
-
Priorities from `expert_priorities` section are merged with `overrides` section
|
|
123
|
-
(overrides take precedence).
|
|
124
|
-
"""
|
|
125
|
-
tech_stack_config = self.project_root / ".tapps-agents" / "tech-stack.yaml"
|
|
126
|
-
if not tech_stack_config.exists():
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
try:
|
|
130
|
-
content = tech_stack_config.read_text(encoding="utf-8")
|
|
131
|
-
config = yaml.safe_load(content) or {}
|
|
132
|
-
|
|
133
|
-
# Get expert priorities (defaults)
|
|
134
|
-
expert_priorities = config.get("expert_priorities", {}).copy()
|
|
135
|
-
|
|
136
|
-
# Apply overrides (overrides take precedence)
|
|
137
|
-
overrides = config.get("overrides", {})
|
|
138
|
-
expert_priorities.update(overrides)
|
|
139
|
-
|
|
140
|
-
if expert_priorities:
|
|
141
|
-
self._tech_stack_priorities = expert_priorities
|
|
142
|
-
except Exception:
|
|
143
|
-
# Silently fail if config file can't be loaded
|
|
144
|
-
# Registry will work without priorities (backward compatible)
|
|
145
|
-
pass
|
|
146
|
-
|
|
147
|
-
@classmethod
|
|
148
|
-
def from_domains_file(cls, domains_file: Path) -> ExpertRegistry:
|
|
149
|
-
"""
|
|
150
|
-
Create registry from domains.md file.
|
|
151
|
-
|
|
152
|
-
Args:
|
|
153
|
-
domains_file: Path to domains.md
|
|
154
|
-
|
|
155
|
-
Returns:
|
|
156
|
-
ExpertRegistry instance
|
|
157
|
-
"""
|
|
158
|
-
domain_config = DomainConfigParser.parse(domains_file)
|
|
159
|
-
return cls(domain_config=domain_config)
|
|
160
|
-
|
|
161
|
-
@classmethod
|
|
162
|
-
def from_config_file(
|
|
163
|
-
cls, config_file: Path, domain_config: DomainConfig | None = None
|
|
164
|
-
) -> ExpertRegistry:
|
|
165
|
-
"""
|
|
166
|
-
Create registry from experts.yaml configuration file.
|
|
167
|
-
|
|
168
|
-
This is the preferred method for creating experts - define them
|
|
169
|
-
in YAML configuration rather than code classes.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
config_file: Path to experts.yaml file
|
|
173
|
-
domain_config: Optional domain configuration for weight matrix
|
|
174
|
-
|
|
175
|
-
Returns:
|
|
176
|
-
ExpertRegistry instance with experts loaded from config
|
|
177
|
-
|
|
178
|
-
Example:
|
|
179
|
-
```python
|
|
180
|
-
registry = ExpertRegistry.from_config_file(
|
|
181
|
-
Path(".tapps-agents/experts.yaml"),
|
|
182
|
-
domain_config=domain_config
|
|
183
|
-
)
|
|
184
|
-
```
|
|
185
|
-
"""
|
|
186
|
-
expert_configs = load_expert_configs(config_file)
|
|
187
|
-
registry = cls(domain_config=domain_config)
|
|
188
|
-
|
|
189
|
-
# Create and register experts from config
|
|
190
|
-
for expert_config in expert_configs:
|
|
191
|
-
expert = BaseExpert(
|
|
192
|
-
expert_id=expert_config.expert_id,
|
|
193
|
-
expert_name=expert_config.expert_name,
|
|
194
|
-
primary_domain=expert_config.primary_domain,
|
|
195
|
-
confidence_matrix=expert_config.confidence_matrix,
|
|
196
|
-
rag_enabled=expert_config.rag_enabled,
|
|
197
|
-
fine_tuned=expert_config.fine_tuned,
|
|
198
|
-
)
|
|
199
|
-
registry.register_expert(expert)
|
|
200
|
-
|
|
201
|
-
registry = cls(domain_config=domain_config, load_builtin=True)
|
|
202
|
-
|
|
203
|
-
# Create and register customer experts from config
|
|
204
|
-
for expert_config in expert_configs:
|
|
205
|
-
# Skip if this is a built-in expert (already loaded)
|
|
206
|
-
if BuiltinExpertRegistry.is_builtin_expert(expert_config.expert_id):
|
|
207
|
-
continue
|
|
208
|
-
|
|
209
|
-
expert = BaseExpert(
|
|
210
|
-
expert_id=expert_config.expert_id,
|
|
211
|
-
expert_name=expert_config.expert_name,
|
|
212
|
-
primary_domain=expert_config.primary_domain,
|
|
213
|
-
confidence_matrix=expert_config.confidence_matrix,
|
|
214
|
-
rag_enabled=expert_config.rag_enabled,
|
|
215
|
-
fine_tuned=expert_config.fine_tuned,
|
|
216
|
-
)
|
|
217
|
-
registry.register_expert(expert, is_builtin=False)
|
|
218
|
-
|
|
219
|
-
return registry
|
|
220
|
-
|
|
221
|
-
def _load_builtin_experts(self):
|
|
222
|
-
"""
|
|
223
|
-
Load all built-in framework experts automatically.
|
|
224
|
-
|
|
225
|
-
Built-in experts are immutable and provide technical domain knowledge.
|
|
226
|
-
They are loaded from the BuiltinExpertRegistry.
|
|
227
|
-
"""
|
|
228
|
-
builtin_configs = BuiltinExpertRegistry.get_builtin_experts()
|
|
229
|
-
builtin_knowledge_path = BuiltinExpertRegistry.get_builtin_knowledge_path()
|
|
230
|
-
|
|
231
|
-
for config in builtin_configs:
|
|
232
|
-
expert = BaseExpert(
|
|
233
|
-
expert_id=config.expert_id,
|
|
234
|
-
expert_name=config.expert_name,
|
|
235
|
-
primary_domain=config.primary_domain,
|
|
236
|
-
confidence_matrix=config.confidence_matrix,
|
|
237
|
-
rag_enabled=config.rag_enabled,
|
|
238
|
-
fine_tuned=config.fine_tuned,
|
|
239
|
-
)
|
|
240
|
-
# Mark as built-in for knowledge base path resolution
|
|
241
|
-
expert._is_builtin = True
|
|
242
|
-
expert._builtin_knowledge_path = builtin_knowledge_path
|
|
243
|
-
|
|
244
|
-
self.register_expert(expert, is_builtin=True)
|
|
245
|
-
|
|
246
|
-
def register_expert(self, expert: BaseExpert, is_builtin: bool = False) -> None:
|
|
247
|
-
"""
|
|
248
|
-
Register an expert agent.
|
|
249
|
-
|
|
250
|
-
Args:
|
|
251
|
-
expert: BaseExpert instance to register
|
|
252
|
-
is_builtin: Whether this is a built-in expert (default: False)
|
|
253
|
-
|
|
254
|
-
Raises:
|
|
255
|
-
ValueError: If expert not found in weight matrix (unless it's a built-in expert)
|
|
256
|
-
"""
|
|
257
|
-
# Built-in experts don't need to be in weight matrix
|
|
258
|
-
if (
|
|
259
|
-
self.weight_matrix
|
|
260
|
-
and expert.expert_id not in self.weight_matrix.experts
|
|
261
|
-
and not is_builtin
|
|
262
|
-
):
|
|
263
|
-
raise ValueError(
|
|
264
|
-
f"Expert '{expert.expert_id}' not found in weight matrix. "
|
|
265
|
-
f"Registered experts: {list(self.weight_matrix.experts)}"
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
# Update confidence matrix from weight matrix if available
|
|
269
|
-
if self.weight_matrix:
|
|
270
|
-
expert.confidence_matrix = self.weight_matrix.weights.get(
|
|
271
|
-
expert.expert_id, {}
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
# Register in appropriate dictionary
|
|
275
|
-
self.experts[expert.expert_id] = expert
|
|
276
|
-
if is_builtin:
|
|
277
|
-
self.builtin_experts[expert.expert_id] = expert
|
|
278
|
-
else:
|
|
279
|
-
self.customer_experts[expert.expert_id] = expert
|
|
280
|
-
|
|
281
|
-
def get_expert(self, expert_id: str) -> BaseExpert | None:
|
|
282
|
-
"""Get an expert by ID."""
|
|
283
|
-
return self.experts.get(expert_id)
|
|
284
|
-
|
|
285
|
-
def list_experts(self) -> list[str]:
|
|
286
|
-
"""List all registered expert IDs."""
|
|
287
|
-
return list(self.experts.keys())
|
|
288
|
-
|
|
289
|
-
async def consult(
|
|
290
|
-
self,
|
|
291
|
-
query: str,
|
|
292
|
-
domain: str,
|
|
293
|
-
include_all: bool = True,
|
|
294
|
-
prioritize_builtin: bool = False,
|
|
295
|
-
agent_id: str | None = None,
|
|
296
|
-
) -> ConsultationResult:
|
|
297
|
-
"""
|
|
298
|
-
Consult multiple experts on a domain question and aggregate weighted responses.
|
|
299
|
-
|
|
300
|
-
Args:
|
|
301
|
-
query: The question to ask
|
|
302
|
-
domain: Domain context
|
|
303
|
-
include_all: Whether to consult all experts or just primary
|
|
304
|
-
prioritize_builtin: If True, built-in experts get higher weight for technical domains.
|
|
305
|
-
If False (default), uses weight matrix configuration.
|
|
306
|
-
For technical domains, built-in experts should be prioritized.
|
|
307
|
-
For business domains, customer experts should be prioritized.
|
|
308
|
-
agent_id: Optional agent ID for agent-specific confidence threshold
|
|
309
|
-
|
|
310
|
-
Returns:
|
|
311
|
-
ConsultationResult with weighted answer and agreement metrics
|
|
312
|
-
"""
|
|
313
|
-
# Determine expert priority based on domain type
|
|
314
|
-
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
315
|
-
|
|
316
|
-
# Collect expert IDs to consult
|
|
317
|
-
expert_ids_to_consult = []
|
|
318
|
-
|
|
319
|
-
# If weight matrix is available and not prioritizing built-in explicitly, use it
|
|
320
|
-
if self.weight_matrix and not prioritize_builtin:
|
|
321
|
-
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
322
|
-
if primary_expert_id:
|
|
323
|
-
if include_all:
|
|
324
|
-
# Consult all experts in weight matrix
|
|
325
|
-
expert_ids_to_consult = list(self.weight_matrix.experts)
|
|
326
|
-
else:
|
|
327
|
-
# Only consult primary
|
|
328
|
-
expert_ids_to_consult = [primary_expert_id]
|
|
329
|
-
|
|
330
|
-
# If no experts from weight matrix, get experts for domain
|
|
331
|
-
if not expert_ids_to_consult:
|
|
332
|
-
if prioritize_builtin and is_technical_domain:
|
|
333
|
-
# Technical domain: built-in experts have authority
|
|
334
|
-
expert_ids_to_consult = self._get_experts_for_domain(
|
|
335
|
-
domain, prioritize_builtin=True
|
|
336
|
-
)
|
|
337
|
-
elif not is_technical_domain:
|
|
338
|
-
# Business domain: customer experts have authority
|
|
339
|
-
expert_ids_to_consult = self._get_experts_for_domain(
|
|
340
|
-
domain, prioritize_builtin=False
|
|
341
|
-
)
|
|
342
|
-
else:
|
|
343
|
-
# Technical domain without prioritize_builtin: use built-in experts
|
|
344
|
-
expert_ids_to_consult = self._get_experts_for_domain(
|
|
345
|
-
domain, prioritize_builtin=True
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
# If still no experts found, try fallback
|
|
349
|
-
if not expert_ids_to_consult:
|
|
350
|
-
# Fallback: get any available experts
|
|
351
|
-
if is_technical_domain:
|
|
352
|
-
expert_ids_to_consult = list(self.builtin_experts.keys())
|
|
353
|
-
else:
|
|
354
|
-
expert_ids_to_consult = list(self.customer_experts.keys()) + list(
|
|
355
|
-
self.builtin_experts.keys()
|
|
356
|
-
)
|
|
357
|
-
|
|
358
|
-
if not expert_ids_to_consult:
|
|
359
|
-
raise ValueError(f"No experts found for domain '{domain}'")
|
|
360
|
-
|
|
361
|
-
# Get project profile if available
|
|
362
|
-
project_profile = self._get_project_profile()
|
|
363
|
-
|
|
364
|
-
# Consult each expert
|
|
365
|
-
responses = []
|
|
366
|
-
for expert_id in expert_ids_to_consult:
|
|
367
|
-
expert = self.experts.get(expert_id)
|
|
368
|
-
if not expert:
|
|
369
|
-
continue # Skip if expert not registered
|
|
370
|
-
|
|
371
|
-
try:
|
|
372
|
-
# Pass project profile to expert consultation
|
|
373
|
-
response = await expert.run(
|
|
374
|
-
"consult",
|
|
375
|
-
query=query,
|
|
376
|
-
domain=domain,
|
|
377
|
-
project_profile=project_profile,
|
|
378
|
-
)
|
|
379
|
-
if "error" not in response:
|
|
380
|
-
confidence = response.get("confidence", 0.0)
|
|
381
|
-
responses.append(
|
|
382
|
-
{
|
|
383
|
-
"expert_id": expert_id,
|
|
384
|
-
"expert_name": expert.agent_name,
|
|
385
|
-
"answer": response.get("answer", ""),
|
|
386
|
-
"confidence": confidence,
|
|
387
|
-
"sources": response.get("sources", []),
|
|
388
|
-
}
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
# Track expert consultation for adaptive learning
|
|
392
|
-
try:
|
|
393
|
-
from ..experts.performance_tracker import ExpertPerformanceTracker
|
|
394
|
-
perf_tracker = ExpertPerformanceTracker(project_root=self.project_root)
|
|
395
|
-
perf_tracker.track_consultation(
|
|
396
|
-
expert_id=expert_id,
|
|
397
|
-
domain=domain,
|
|
398
|
-
confidence=confidence,
|
|
399
|
-
query=query,
|
|
400
|
-
)
|
|
401
|
-
except Exception as e:
|
|
402
|
-
# Don't fail consultation if tracking fails
|
|
403
|
-
logger.debug(f"Failed to track expert consultation: {e}")
|
|
404
|
-
except Exception as e:
|
|
405
|
-
# Log error but continue with other experts
|
|
406
|
-
responses.append({"expert_id": expert_id, "error": str(e)})
|
|
407
|
-
|
|
408
|
-
if not responses:
|
|
409
|
-
raise ValueError(f"No expert responses received for domain '{domain}'")
|
|
410
|
-
|
|
411
|
-
# Determine primary expert ID for aggregation
|
|
412
|
-
primary_expert_id = None
|
|
413
|
-
if self.weight_matrix:
|
|
414
|
-
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
415
|
-
|
|
416
|
-
# If no primary from weight matrix, use first expert or built-in expert for technical domains
|
|
417
|
-
if not primary_expert_id:
|
|
418
|
-
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
419
|
-
if is_technical_domain:
|
|
420
|
-
# For technical domains, prefer built-in expert
|
|
421
|
-
for expert_id in expert_ids_to_consult:
|
|
422
|
-
if expert_id in self.builtin_experts:
|
|
423
|
-
primary_expert_id = expert_id
|
|
424
|
-
break
|
|
425
|
-
|
|
426
|
-
# Fallback to first available expert
|
|
427
|
-
if not primary_expert_id and responses:
|
|
428
|
-
primary_expert_id = responses[0].get("expert_id")
|
|
429
|
-
|
|
430
|
-
# Ensure a stable non-None primary expert id for downstream logic and dataclass typing.
|
|
431
|
-
if not primary_expert_id:
|
|
432
|
-
primary_expert_id = "unknown"
|
|
433
|
-
|
|
434
|
-
# Aggregate weighted responses
|
|
435
|
-
weighted_answer = self._aggregate_responses(
|
|
436
|
-
responses, domain, primary_expert_id
|
|
437
|
-
)
|
|
438
|
-
|
|
439
|
-
# Calculate agreement level
|
|
440
|
-
agreement_level = self._calculate_agreement(
|
|
441
|
-
responses, domain, primary_expert_id
|
|
442
|
-
)
|
|
443
|
-
|
|
444
|
-
# Calculate confidence using improved algorithm
|
|
445
|
-
valid_responses = [r for r in responses if "error" not in r]
|
|
446
|
-
|
|
447
|
-
# Calculate RAG quality from sources
|
|
448
|
-
rag_quality = None
|
|
449
|
-
if valid_responses:
|
|
450
|
-
sources_count = sum(len(r.get("sources", [])) for r in valid_responses)
|
|
451
|
-
num_responses = len(valid_responses)
|
|
452
|
-
rag_quality = min(
|
|
453
|
-
1.0, sources_count / max(num_responses * 2, 1)
|
|
454
|
-
) # 2 sources per response = perfect
|
|
455
|
-
|
|
456
|
-
# Use improved confidence calculator
|
|
457
|
-
confidence, threshold = ConfidenceCalculator.calculate(
|
|
458
|
-
responses=valid_responses,
|
|
459
|
-
domain=domain,
|
|
460
|
-
agent_id=agent_id,
|
|
461
|
-
agreement_level=agreement_level,
|
|
462
|
-
rag_quality=rag_quality,
|
|
463
|
-
num_experts_consulted=len(expert_ids_to_consult),
|
|
464
|
-
project_profile=project_profile,
|
|
465
|
-
)
|
|
466
|
-
|
|
467
|
-
# Get expert config for thresholds
|
|
468
|
-
expert_config = get_expert_config()
|
|
469
|
-
all_agreed = agreement_level >= expert_config.high_agreement_threshold
|
|
470
|
-
|
|
471
|
-
# Track confidence metrics
|
|
472
|
-
if agent_id:
|
|
473
|
-
try:
|
|
474
|
-
tracker = get_tracker()
|
|
475
|
-
tracker.record(
|
|
476
|
-
agent_id=agent_id,
|
|
477
|
-
domain=domain,
|
|
478
|
-
confidence=confidence,
|
|
479
|
-
threshold=threshold,
|
|
480
|
-
agreement_level=agreement_level,
|
|
481
|
-
num_experts=len(expert_ids_to_consult),
|
|
482
|
-
primary_expert=primary_expert_id or "unknown",
|
|
483
|
-
query=query,
|
|
484
|
-
)
|
|
485
|
-
except Exception as e:
|
|
486
|
-
# Silently fail if tracking fails (non-critical)
|
|
487
|
-
# Log at debug level if logging is available
|
|
488
|
-
import logging
|
|
489
|
-
|
|
490
|
-
logger = logging.getLogger(__name__)
|
|
491
|
-
logger.debug(f"Failed to track confidence metrics: {e}")
|
|
492
|
-
|
|
493
|
-
return ConsultationResult(
|
|
494
|
-
domain=domain,
|
|
495
|
-
query=query,
|
|
496
|
-
responses=responses,
|
|
497
|
-
weighted_answer=weighted_answer,
|
|
498
|
-
agreement_level=agreement_level,
|
|
499
|
-
confidence=confidence,
|
|
500
|
-
confidence_threshold=threshold,
|
|
501
|
-
primary_expert=primary_expert_id,
|
|
502
|
-
all_experts_agreed=all_agreed,
|
|
503
|
-
)
|
|
504
|
-
|
|
505
|
-
def _aggregate_responses(
|
|
506
|
-
self,
|
|
507
|
-
responses: list[dict[str, Any]],
|
|
508
|
-
domain: str,
|
|
509
|
-
primary_expert_id: str | None = None,
|
|
510
|
-
) -> str:
|
|
511
|
-
"""
|
|
512
|
-
Aggregate expert responses using weighted decision-making.
|
|
513
|
-
|
|
514
|
-
Primary expert (51%) has primary influence; others augment.
|
|
515
|
-
"""
|
|
516
|
-
if not primary_expert_id:
|
|
517
|
-
# Fallback: use first available response
|
|
518
|
-
primary = next(
|
|
519
|
-
(r for r in responses if r.get("expert_id") and "error" not in r), None
|
|
520
|
-
)
|
|
521
|
-
return primary.get("answer", "") if primary else ""
|
|
522
|
-
|
|
523
|
-
# Try to get primary expert from weight matrix if not provided
|
|
524
|
-
if self.weight_matrix and not primary_expert_id:
|
|
525
|
-
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
526
|
-
|
|
527
|
-
# Find primary expert response
|
|
528
|
-
primary_response = next(
|
|
529
|
-
(
|
|
530
|
-
r
|
|
531
|
-
for r in responses
|
|
532
|
-
if r.get("expert_id") == primary_expert_id and "error" not in r
|
|
533
|
-
),
|
|
534
|
-
None,
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
if not primary_response:
|
|
538
|
-
# Fallback to first available response
|
|
539
|
-
primary_response = next((r for r in responses if "error" not in r), None)
|
|
540
|
-
if not primary_response:
|
|
541
|
-
return "No expert responses available."
|
|
542
|
-
return primary_response.get("answer", "")
|
|
543
|
-
|
|
544
|
-
# Start with primary expert answer (51% weight)
|
|
545
|
-
primary_answer = primary_response.get("answer", "")
|
|
546
|
-
aggregated_parts = [
|
|
547
|
-
f"[Primary - {primary_response.get('expert_name', 'Expert')}] {primary_answer}"
|
|
548
|
-
]
|
|
549
|
-
|
|
550
|
-
# Add influences from other experts
|
|
551
|
-
other_responses = [
|
|
552
|
-
r
|
|
553
|
-
for r in responses
|
|
554
|
-
if r.get("expert_id") != primary_expert_id and "error" not in r
|
|
555
|
-
]
|
|
556
|
-
|
|
557
|
-
if other_responses:
|
|
558
|
-
influences = []
|
|
559
|
-
for response in other_responses:
|
|
560
|
-
expert_id = response.get("expert_id", "")
|
|
561
|
-
# Get weight from weight matrix if available, otherwise use default
|
|
562
|
-
if self.weight_matrix:
|
|
563
|
-
weight = self.weight_matrix.get_expert_weight(expert_id, domain)
|
|
564
|
-
else:
|
|
565
|
-
# Default weight for non-primary experts (from config)
|
|
566
|
-
expert_config = get_expert_config()
|
|
567
|
-
weight = expert_config.supporting_expert_weight
|
|
568
|
-
answer = response.get("answer", "")
|
|
569
|
-
expert_name = response.get("expert_name", expert_id)
|
|
570
|
-
|
|
571
|
-
influences.append(
|
|
572
|
-
f"[Influence ({weight:.1%}) - {expert_name}] {answer}"
|
|
573
|
-
)
|
|
574
|
-
|
|
575
|
-
if influences:
|
|
576
|
-
aggregated_parts.append("\n\nAdditional Expert Input:")
|
|
577
|
-
aggregated_parts.extend(influences)
|
|
578
|
-
|
|
579
|
-
return "\n".join(aggregated_parts)
|
|
580
|
-
|
|
581
|
-
def _calculate_agreement(
|
|
582
|
-
self, responses: list[dict[str, Any]], domain: str, primary_expert_id: str
|
|
583
|
-
) -> float:
|
|
584
|
-
"""
|
|
585
|
-
Calculate agreement level between experts.
|
|
586
|
-
|
|
587
|
-
Agreement Level = Sum of weights for experts who agree with Primary
|
|
588
|
-
|
|
589
|
-
Returns:
|
|
590
|
-
Agreement level (0.0-1.0)
|
|
591
|
-
"""
|
|
592
|
-
if not self.weight_matrix:
|
|
593
|
-
return 1.0 # Assume agreement if no matrix
|
|
594
|
-
|
|
595
|
-
primary_response = next(
|
|
596
|
-
(
|
|
597
|
-
r
|
|
598
|
-
for r in responses
|
|
599
|
-
if r.get("expert_id") == primary_expert_id and "error" not in r
|
|
600
|
-
),
|
|
601
|
-
None,
|
|
602
|
-
)
|
|
603
|
-
|
|
604
|
-
if not primary_response:
|
|
605
|
-
return 0.51 # Minimum (primary alone)
|
|
606
|
-
|
|
607
|
-
primary_answer = primary_response.get("answer", "")
|
|
608
|
-
|
|
609
|
-
# For now, simple check: count experts with similar answers
|
|
610
|
-
# In a real implementation, this would use semantic similarity
|
|
611
|
-
agreement_weight = 0.51 # Primary always agrees with itself
|
|
612
|
-
|
|
613
|
-
for response in responses:
|
|
614
|
-
expert_id = response.get("expert_id", "")
|
|
615
|
-
if expert_id == primary_expert_id or "error" in response:
|
|
616
|
-
continue
|
|
617
|
-
|
|
618
|
-
# Simple similarity check (in practice, use semantic similarity)
|
|
619
|
-
answer = response.get("answer", "")
|
|
620
|
-
if answer and primary_answer:
|
|
621
|
-
# Very basic: if answers share significant content, consider agreeing
|
|
622
|
-
# This is a placeholder - real implementation would use embeddings
|
|
623
|
-
similarity = self._simple_similarity(primary_answer, answer)
|
|
624
|
-
expert_config = get_expert_config()
|
|
625
|
-
if similarity > expert_config.similarity_threshold:
|
|
626
|
-
weight = self.weight_matrix.get_expert_weight(expert_id, domain)
|
|
627
|
-
agreement_weight += weight
|
|
628
|
-
|
|
629
|
-
return min(agreement_weight, 1.0)
|
|
630
|
-
|
|
631
|
-
def _simple_similarity(self, text1: str, text2: str) -> float:
|
|
632
|
-
"""
|
|
633
|
-
Simple text similarity metric (placeholder).
|
|
634
|
-
|
|
635
|
-
In production, use proper semantic similarity (embeddings, cosine similarity).
|
|
636
|
-
"""
|
|
637
|
-
words1 = set(text1.lower().split())
|
|
638
|
-
words2 = set(text2.lower().split())
|
|
639
|
-
|
|
640
|
-
if not words1 or not words2:
|
|
641
|
-
return 0.0
|
|
642
|
-
|
|
643
|
-
intersection = words1.intersection(words2)
|
|
644
|
-
union = words1.union(words2)
|
|
645
|
-
|
|
646
|
-
return len(intersection) / len(union) if union else 0.0
|
|
647
|
-
|
|
648
|
-
def _get_experts_for_domain(
|
|
649
|
-
self, domain: str, prioritize_builtin: bool = False
|
|
650
|
-
) -> list[str]:
|
|
651
|
-
"""
|
|
652
|
-
Get expert IDs for a domain, prioritizing built-in or customer experts.
|
|
653
|
-
|
|
654
|
-
Args:
|
|
655
|
-
domain: Domain name
|
|
656
|
-
prioritize_builtin: If True, prioritize built-in experts for technical domains.
|
|
657
|
-
If False, prioritize customer experts for business domains.
|
|
658
|
-
|
|
659
|
-
Returns:
|
|
660
|
-
List of expert IDs to consult, ordered by priority
|
|
661
|
-
"""
|
|
662
|
-
expert_ids = []
|
|
663
|
-
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
664
|
-
|
|
665
|
-
# Find experts that match the domain
|
|
666
|
-
builtin_matches = []
|
|
667
|
-
customer_matches = []
|
|
668
|
-
|
|
669
|
-
for expert_id, expert in self.builtin_experts.items():
|
|
670
|
-
if expert.primary_domain == domain:
|
|
671
|
-
builtin_matches.append(expert_id)
|
|
672
|
-
|
|
673
|
-
for expert_id, expert in self.customer_experts.items():
|
|
674
|
-
if expert.primary_domain == domain:
|
|
675
|
-
customer_matches.append(expert_id)
|
|
676
|
-
|
|
677
|
-
# Determine priority order
|
|
678
|
-
if is_technical_domain and prioritize_builtin:
|
|
679
|
-
# Technical domain: built-in experts first
|
|
680
|
-
expert_ids.extend(builtin_matches)
|
|
681
|
-
expert_ids.extend(customer_matches)
|
|
682
|
-
elif not is_technical_domain and not prioritize_builtin:
|
|
683
|
-
# Business domain: customer experts first
|
|
684
|
-
expert_ids.extend(customer_matches)
|
|
685
|
-
expert_ids.extend(builtin_matches)
|
|
686
|
-
else:
|
|
687
|
-
# Default: built-in first for technical, customer first for business
|
|
688
|
-
if is_technical_domain:
|
|
689
|
-
expert_ids.extend(builtin_matches)
|
|
690
|
-
expert_ids.extend(customer_matches)
|
|
691
|
-
else:
|
|
692
|
-
expert_ids.extend(customer_matches)
|
|
693
|
-
expert_ids.extend(builtin_matches)
|
|
694
|
-
|
|
695
|
-
# If no domain matches, try to find experts with related domains
|
|
696
|
-
if not expert_ids:
|
|
697
|
-
# Fallback: get any expert that might be relevant
|
|
698
|
-
if is_technical_domain:
|
|
699
|
-
expert_ids.extend(list(self.builtin_experts.keys()))
|
|
700
|
-
else:
|
|
701
|
-
expert_ids.extend(list(self.customer_experts.keys()))
|
|
702
|
-
expert_ids.extend(list(self.builtin_experts.keys()))
|
|
703
|
-
|
|
704
|
-
# Apply tech stack priorities if available
|
|
705
|
-
if self._tech_stack_priorities and expert_ids:
|
|
706
|
-
expert_ids = self._apply_priorities(expert_ids)
|
|
707
|
-
|
|
708
|
-
return expert_ids
|
|
709
|
-
|
|
710
|
-
def _apply_priorities(self, expert_ids: list[str]) -> list[str]:
|
|
711
|
-
"""
|
|
712
|
-
Apply tech stack priorities to expert ID list.
|
|
713
|
-
|
|
714
|
-
Experts are sorted by priority (higher first), with experts not in
|
|
715
|
-
priority mapping appearing at the end.
|
|
716
|
-
|
|
717
|
-
Args:
|
|
718
|
-
expert_ids: List of expert IDs to prioritize
|
|
719
|
-
|
|
720
|
-
Returns:
|
|
721
|
-
List of expert IDs sorted by priority (higher first)
|
|
722
|
-
"""
|
|
723
|
-
if not self._tech_stack_priorities:
|
|
724
|
-
return expert_ids
|
|
725
|
-
|
|
726
|
-
# Separate experts into prioritized and unprioritized
|
|
727
|
-
prioritized: list[tuple[str, float]] = []
|
|
728
|
-
unprioritized: list[str] = []
|
|
729
|
-
|
|
730
|
-
for expert_id in expert_ids:
|
|
731
|
-
priority = self._tech_stack_priorities.get(expert_id)
|
|
732
|
-
if priority is not None:
|
|
733
|
-
prioritized.append((expert_id, priority))
|
|
734
|
-
else:
|
|
735
|
-
unprioritized.append(expert_id)
|
|
736
|
-
|
|
737
|
-
# Sort prioritized experts by priority (higher first)
|
|
738
|
-
prioritized.sort(key=lambda x: x[1], reverse=True)
|
|
739
|
-
|
|
740
|
-
# Combine: prioritized experts first (sorted), then unprioritized
|
|
741
|
-
result = [expert_id for expert_id, _ in prioritized]
|
|
742
|
-
result.extend(unprioritized)
|
|
743
|
-
|
|
744
|
-
return result
|
|
1
|
+
"""
|
|
2
|
+
Expert Registry
|
|
3
|
+
|
|
4
|
+
Manages expert instances and provides consultation services with weighted decision-making.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# @ai-prime-directive: This file implements the Expert Registry system for weighted expert consultation.
|
|
8
|
+
# The registry manages both built-in framework experts and project-defined industry experts, providing
|
|
9
|
+
# weighted decision aggregation and confidence calculation. This is a core component of the expert system design.
|
|
10
|
+
|
|
11
|
+
# @ai-constraints:
|
|
12
|
+
# - Must maintain separation between built-in experts (framework-controlled) and customer experts (project-defined)
|
|
13
|
+
# - Weight distribution must follow 51% primary authority model for technical domains
|
|
14
|
+
# - Confidence calculation must consider agreement level, expert weights, and domain expertise
|
|
15
|
+
# - Built-in experts have primary authority in TECHNICAL_DOMAINS (see BuiltinExpertRegistry)
|
|
16
|
+
# - Performance: Consultation should complete in <5s for typical queries
|
|
17
|
+
|
|
18
|
+
# @note[2025-01-15]: Expert system design per ADR-003.
|
|
19
|
+
# The registry implements weighted consultation with built-in and project-defined experts.
|
|
20
|
+
# See docs/architecture/decisions/ADR-003-expert-system-design.md
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from dataclasses import dataclass
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any
|
|
27
|
+
|
|
28
|
+
import yaml
|
|
29
|
+
|
|
30
|
+
from ..core.config import get_expert_config
|
|
31
|
+
from ..core.project_profile import ProjectProfile, load_project_profile
|
|
32
|
+
from .base_expert import BaseExpert
|
|
33
|
+
from .builtin_registry import BuiltinExpertRegistry
|
|
34
|
+
from .confidence_calculator import ConfidenceCalculator
|
|
35
|
+
from .confidence_metrics import get_tracker
|
|
36
|
+
from .domain_config import DomainConfig, DomainConfigParser
|
|
37
|
+
from .expert_config import load_expert_configs
|
|
38
|
+
from .weight_distributor import ExpertWeightMatrix
|
|
39
|
+
|
|
40
|
+
import logging
|
|
41
|
+
|
|
42
|
+
logger = logging.getLogger(__name__)
|
|
43
|
+
|
|
44
|
+
# Technical domains where built-in experts have primary authority
|
|
45
|
+
# These domains are framework-controlled and built-in experts should be prioritized
|
|
46
|
+
TECHNICAL_DOMAINS = BuiltinExpertRegistry.TECHNICAL_DOMAINS
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class ConsultationResult:
|
|
51
|
+
"""Result from consulting multiple experts."""
|
|
52
|
+
|
|
53
|
+
domain: str
|
|
54
|
+
query: str
|
|
55
|
+
responses: list[dict[str, Any]] # Individual expert responses
|
|
56
|
+
weighted_answer: str # Combined weighted answer
|
|
57
|
+
agreement_level: float # 0.0-1.0
|
|
58
|
+
confidence: float # Overall confidence
|
|
59
|
+
confidence_threshold: float # Agent-specific confidence threshold
|
|
60
|
+
primary_expert: str
|
|
61
|
+
all_experts_agreed: bool
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ExpertRegistry:
|
|
65
|
+
"""
|
|
66
|
+
Registry for managing Industry Expert agents.
|
|
67
|
+
|
|
68
|
+
Provides:
|
|
69
|
+
- Expert instance management
|
|
70
|
+
- Weighted consultation services
|
|
71
|
+
- Decision aggregation
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
domain_config: DomainConfig | None = None,
|
|
77
|
+
load_builtin: bool = True,
|
|
78
|
+
project_root: Path | None = None,
|
|
79
|
+
):
|
|
80
|
+
"""
|
|
81
|
+
Initialize expert registry.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
domain_config: Optional domain configuration (can be loaded later)
|
|
85
|
+
load_builtin: Whether to auto-load built-in framework experts (default: True)
|
|
86
|
+
project_root: Optional project root for profile loading
|
|
87
|
+
"""
|
|
88
|
+
self.domain_config = domain_config
|
|
89
|
+
self.experts: dict[str, BaseExpert] = {}
|
|
90
|
+
self.builtin_experts: dict[str, BaseExpert] = {} # Built-in framework experts
|
|
91
|
+
self.customer_experts: dict[str, BaseExpert] = {} # Customer-configured experts
|
|
92
|
+
self.weight_matrix: ExpertWeightMatrix | None = (
|
|
93
|
+
domain_config.weight_matrix if domain_config else None
|
|
94
|
+
)
|
|
95
|
+
self.project_root = project_root or Path.cwd()
|
|
96
|
+
self._cached_profile: ProjectProfile | None = None
|
|
97
|
+
self._tech_stack_priorities: dict[str, float] | None = None
|
|
98
|
+
|
|
99
|
+
# Auto-load built-in experts if enabled
|
|
100
|
+
if load_builtin:
|
|
101
|
+
self._load_builtin_experts()
|
|
102
|
+
|
|
103
|
+
# Load tech stack priorities if available
|
|
104
|
+
self._load_tech_stack_priorities()
|
|
105
|
+
|
|
106
|
+
def _get_project_profile(self) -> ProjectProfile | None:
|
|
107
|
+
"""
|
|
108
|
+
Get project profile (cached).
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
ProjectProfile if available, None otherwise
|
|
112
|
+
"""
|
|
113
|
+
if self._cached_profile is None:
|
|
114
|
+
self._cached_profile = load_project_profile(project_root=self.project_root)
|
|
115
|
+
return self._cached_profile
|
|
116
|
+
|
|
117
|
+
def _load_tech_stack_priorities(self) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Load expert priorities from tech-stack.yaml config file.
|
|
120
|
+
|
|
121
|
+
Priorities are loaded from `.tapps-agents/tech-stack.yaml` if it exists.
|
|
122
|
+
Priorities from `expert_priorities` section are merged with `overrides` section
|
|
123
|
+
(overrides take precedence).
|
|
124
|
+
"""
|
|
125
|
+
tech_stack_config = self.project_root / ".tapps-agents" / "tech-stack.yaml"
|
|
126
|
+
if not tech_stack_config.exists():
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
content = tech_stack_config.read_text(encoding="utf-8")
|
|
131
|
+
config = yaml.safe_load(content) or {}
|
|
132
|
+
|
|
133
|
+
# Get expert priorities (defaults)
|
|
134
|
+
expert_priorities = config.get("expert_priorities", {}).copy()
|
|
135
|
+
|
|
136
|
+
# Apply overrides (overrides take precedence)
|
|
137
|
+
overrides = config.get("overrides", {})
|
|
138
|
+
expert_priorities.update(overrides)
|
|
139
|
+
|
|
140
|
+
if expert_priorities:
|
|
141
|
+
self._tech_stack_priorities = expert_priorities
|
|
142
|
+
except Exception:
|
|
143
|
+
# Silently fail if config file can't be loaded
|
|
144
|
+
# Registry will work without priorities (backward compatible)
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
@classmethod
|
|
148
|
+
def from_domains_file(cls, domains_file: Path) -> ExpertRegistry:
|
|
149
|
+
"""
|
|
150
|
+
Create registry from domains.md file.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
domains_file: Path to domains.md
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
ExpertRegistry instance
|
|
157
|
+
"""
|
|
158
|
+
domain_config = DomainConfigParser.parse(domains_file)
|
|
159
|
+
return cls(domain_config=domain_config)
|
|
160
|
+
|
|
161
|
+
@classmethod
|
|
162
|
+
def from_config_file(
|
|
163
|
+
cls, config_file: Path, domain_config: DomainConfig | None = None
|
|
164
|
+
) -> ExpertRegistry:
|
|
165
|
+
"""
|
|
166
|
+
Create registry from experts.yaml configuration file.
|
|
167
|
+
|
|
168
|
+
This is the preferred method for creating experts - define them
|
|
169
|
+
in YAML configuration rather than code classes.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
config_file: Path to experts.yaml file
|
|
173
|
+
domain_config: Optional domain configuration for weight matrix
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
ExpertRegistry instance with experts loaded from config
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
```python
|
|
180
|
+
registry = ExpertRegistry.from_config_file(
|
|
181
|
+
Path(".tapps-agents/experts.yaml"),
|
|
182
|
+
domain_config=domain_config
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
"""
|
|
186
|
+
expert_configs = load_expert_configs(config_file)
|
|
187
|
+
registry = cls(domain_config=domain_config)
|
|
188
|
+
|
|
189
|
+
# Create and register experts from config
|
|
190
|
+
for expert_config in expert_configs:
|
|
191
|
+
expert = BaseExpert(
|
|
192
|
+
expert_id=expert_config.expert_id,
|
|
193
|
+
expert_name=expert_config.expert_name,
|
|
194
|
+
primary_domain=expert_config.primary_domain,
|
|
195
|
+
confidence_matrix=expert_config.confidence_matrix,
|
|
196
|
+
rag_enabled=expert_config.rag_enabled,
|
|
197
|
+
fine_tuned=expert_config.fine_tuned,
|
|
198
|
+
)
|
|
199
|
+
registry.register_expert(expert)
|
|
200
|
+
|
|
201
|
+
registry = cls(domain_config=domain_config, load_builtin=True)
|
|
202
|
+
|
|
203
|
+
# Create and register customer experts from config
|
|
204
|
+
for expert_config in expert_configs:
|
|
205
|
+
# Skip if this is a built-in expert (already loaded)
|
|
206
|
+
if BuiltinExpertRegistry.is_builtin_expert(expert_config.expert_id):
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
expert = BaseExpert(
|
|
210
|
+
expert_id=expert_config.expert_id,
|
|
211
|
+
expert_name=expert_config.expert_name,
|
|
212
|
+
primary_domain=expert_config.primary_domain,
|
|
213
|
+
confidence_matrix=expert_config.confidence_matrix,
|
|
214
|
+
rag_enabled=expert_config.rag_enabled,
|
|
215
|
+
fine_tuned=expert_config.fine_tuned,
|
|
216
|
+
)
|
|
217
|
+
registry.register_expert(expert, is_builtin=False)
|
|
218
|
+
|
|
219
|
+
return registry
|
|
220
|
+
|
|
221
|
+
def _load_builtin_experts(self):
|
|
222
|
+
"""
|
|
223
|
+
Load all built-in framework experts automatically.
|
|
224
|
+
|
|
225
|
+
Built-in experts are immutable and provide technical domain knowledge.
|
|
226
|
+
They are loaded from the BuiltinExpertRegistry.
|
|
227
|
+
"""
|
|
228
|
+
builtin_configs = BuiltinExpertRegistry.get_builtin_experts()
|
|
229
|
+
builtin_knowledge_path = BuiltinExpertRegistry.get_builtin_knowledge_path()
|
|
230
|
+
|
|
231
|
+
for config in builtin_configs:
|
|
232
|
+
expert = BaseExpert(
|
|
233
|
+
expert_id=config.expert_id,
|
|
234
|
+
expert_name=config.expert_name,
|
|
235
|
+
primary_domain=config.primary_domain,
|
|
236
|
+
confidence_matrix=config.confidence_matrix,
|
|
237
|
+
rag_enabled=config.rag_enabled,
|
|
238
|
+
fine_tuned=config.fine_tuned,
|
|
239
|
+
)
|
|
240
|
+
# Mark as built-in for knowledge base path resolution
|
|
241
|
+
expert._is_builtin = True
|
|
242
|
+
expert._builtin_knowledge_path = builtin_knowledge_path
|
|
243
|
+
|
|
244
|
+
self.register_expert(expert, is_builtin=True)
|
|
245
|
+
|
|
246
|
+
def register_expert(self, expert: BaseExpert, is_builtin: bool = False) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Register an expert agent.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
expert: BaseExpert instance to register
|
|
252
|
+
is_builtin: Whether this is a built-in expert (default: False)
|
|
253
|
+
|
|
254
|
+
Raises:
|
|
255
|
+
ValueError: If expert not found in weight matrix (unless it's a built-in expert)
|
|
256
|
+
"""
|
|
257
|
+
# Built-in experts don't need to be in weight matrix
|
|
258
|
+
if (
|
|
259
|
+
self.weight_matrix
|
|
260
|
+
and expert.expert_id not in self.weight_matrix.experts
|
|
261
|
+
and not is_builtin
|
|
262
|
+
):
|
|
263
|
+
raise ValueError(
|
|
264
|
+
f"Expert '{expert.expert_id}' not found in weight matrix. "
|
|
265
|
+
f"Registered experts: {list(self.weight_matrix.experts)}"
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Update confidence matrix from weight matrix if available
|
|
269
|
+
if self.weight_matrix:
|
|
270
|
+
expert.confidence_matrix = self.weight_matrix.weights.get(
|
|
271
|
+
expert.expert_id, {}
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Register in appropriate dictionary
|
|
275
|
+
self.experts[expert.expert_id] = expert
|
|
276
|
+
if is_builtin:
|
|
277
|
+
self.builtin_experts[expert.expert_id] = expert
|
|
278
|
+
else:
|
|
279
|
+
self.customer_experts[expert.expert_id] = expert
|
|
280
|
+
|
|
281
|
+
def get_expert(self, expert_id: str) -> BaseExpert | None:
|
|
282
|
+
"""Get an expert by ID."""
|
|
283
|
+
return self.experts.get(expert_id)
|
|
284
|
+
|
|
285
|
+
def list_experts(self) -> list[str]:
|
|
286
|
+
"""List all registered expert IDs."""
|
|
287
|
+
return list(self.experts.keys())
|
|
288
|
+
|
|
289
|
+
async def consult(
|
|
290
|
+
self,
|
|
291
|
+
query: str,
|
|
292
|
+
domain: str,
|
|
293
|
+
include_all: bool = True,
|
|
294
|
+
prioritize_builtin: bool = False,
|
|
295
|
+
agent_id: str | None = None,
|
|
296
|
+
) -> ConsultationResult:
|
|
297
|
+
"""
|
|
298
|
+
Consult multiple experts on a domain question and aggregate weighted responses.
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
query: The question to ask
|
|
302
|
+
domain: Domain context
|
|
303
|
+
include_all: Whether to consult all experts or just primary
|
|
304
|
+
prioritize_builtin: If True, built-in experts get higher weight for technical domains.
|
|
305
|
+
If False (default), uses weight matrix configuration.
|
|
306
|
+
For technical domains, built-in experts should be prioritized.
|
|
307
|
+
For business domains, customer experts should be prioritized.
|
|
308
|
+
agent_id: Optional agent ID for agent-specific confidence threshold
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
ConsultationResult with weighted answer and agreement metrics
|
|
312
|
+
"""
|
|
313
|
+
# Determine expert priority based on domain type
|
|
314
|
+
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
315
|
+
|
|
316
|
+
# Collect expert IDs to consult
|
|
317
|
+
expert_ids_to_consult = []
|
|
318
|
+
|
|
319
|
+
# If weight matrix is available and not prioritizing built-in explicitly, use it
|
|
320
|
+
if self.weight_matrix and not prioritize_builtin:
|
|
321
|
+
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
322
|
+
if primary_expert_id:
|
|
323
|
+
if include_all:
|
|
324
|
+
# Consult all experts in weight matrix
|
|
325
|
+
expert_ids_to_consult = list(self.weight_matrix.experts)
|
|
326
|
+
else:
|
|
327
|
+
# Only consult primary
|
|
328
|
+
expert_ids_to_consult = [primary_expert_id]
|
|
329
|
+
|
|
330
|
+
# If no experts from weight matrix, get experts for domain
|
|
331
|
+
if not expert_ids_to_consult:
|
|
332
|
+
if prioritize_builtin and is_technical_domain:
|
|
333
|
+
# Technical domain: built-in experts have authority
|
|
334
|
+
expert_ids_to_consult = self._get_experts_for_domain(
|
|
335
|
+
domain, prioritize_builtin=True
|
|
336
|
+
)
|
|
337
|
+
elif not is_technical_domain:
|
|
338
|
+
# Business domain: customer experts have authority
|
|
339
|
+
expert_ids_to_consult = self._get_experts_for_domain(
|
|
340
|
+
domain, prioritize_builtin=False
|
|
341
|
+
)
|
|
342
|
+
else:
|
|
343
|
+
# Technical domain without prioritize_builtin: use built-in experts
|
|
344
|
+
expert_ids_to_consult = self._get_experts_for_domain(
|
|
345
|
+
domain, prioritize_builtin=True
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
# If still no experts found, try fallback
|
|
349
|
+
if not expert_ids_to_consult:
|
|
350
|
+
# Fallback: get any available experts
|
|
351
|
+
if is_technical_domain:
|
|
352
|
+
expert_ids_to_consult = list(self.builtin_experts.keys())
|
|
353
|
+
else:
|
|
354
|
+
expert_ids_to_consult = list(self.customer_experts.keys()) + list(
|
|
355
|
+
self.builtin_experts.keys()
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
if not expert_ids_to_consult:
|
|
359
|
+
raise ValueError(f"No experts found for domain '{domain}'")
|
|
360
|
+
|
|
361
|
+
# Get project profile if available
|
|
362
|
+
project_profile = self._get_project_profile()
|
|
363
|
+
|
|
364
|
+
# Consult each expert
|
|
365
|
+
responses = []
|
|
366
|
+
for expert_id in expert_ids_to_consult:
|
|
367
|
+
expert = self.experts.get(expert_id)
|
|
368
|
+
if not expert:
|
|
369
|
+
continue # Skip if expert not registered
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
# Pass project profile to expert consultation
|
|
373
|
+
response = await expert.run(
|
|
374
|
+
"consult",
|
|
375
|
+
query=query,
|
|
376
|
+
domain=domain,
|
|
377
|
+
project_profile=project_profile,
|
|
378
|
+
)
|
|
379
|
+
if "error" not in response:
|
|
380
|
+
confidence = response.get("confidence", 0.0)
|
|
381
|
+
responses.append(
|
|
382
|
+
{
|
|
383
|
+
"expert_id": expert_id,
|
|
384
|
+
"expert_name": expert.agent_name,
|
|
385
|
+
"answer": response.get("answer", ""),
|
|
386
|
+
"confidence": confidence,
|
|
387
|
+
"sources": response.get("sources", []),
|
|
388
|
+
}
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
# Track expert consultation for adaptive learning
|
|
392
|
+
try:
|
|
393
|
+
from ..experts.performance_tracker import ExpertPerformanceTracker
|
|
394
|
+
perf_tracker = ExpertPerformanceTracker(project_root=self.project_root)
|
|
395
|
+
perf_tracker.track_consultation(
|
|
396
|
+
expert_id=expert_id,
|
|
397
|
+
domain=domain,
|
|
398
|
+
confidence=confidence,
|
|
399
|
+
query=query,
|
|
400
|
+
)
|
|
401
|
+
except Exception as e:
|
|
402
|
+
# Don't fail consultation if tracking fails
|
|
403
|
+
logger.debug(f"Failed to track expert consultation: {e}")
|
|
404
|
+
except Exception as e:
|
|
405
|
+
# Log error but continue with other experts
|
|
406
|
+
responses.append({"expert_id": expert_id, "error": str(e)})
|
|
407
|
+
|
|
408
|
+
if not responses:
|
|
409
|
+
raise ValueError(f"No expert responses received for domain '{domain}'")
|
|
410
|
+
|
|
411
|
+
# Determine primary expert ID for aggregation
|
|
412
|
+
primary_expert_id = None
|
|
413
|
+
if self.weight_matrix:
|
|
414
|
+
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
415
|
+
|
|
416
|
+
# If no primary from weight matrix, use first expert or built-in expert for technical domains
|
|
417
|
+
if not primary_expert_id:
|
|
418
|
+
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
419
|
+
if is_technical_domain:
|
|
420
|
+
# For technical domains, prefer built-in expert
|
|
421
|
+
for expert_id in expert_ids_to_consult:
|
|
422
|
+
if expert_id in self.builtin_experts:
|
|
423
|
+
primary_expert_id = expert_id
|
|
424
|
+
break
|
|
425
|
+
|
|
426
|
+
# Fallback to first available expert
|
|
427
|
+
if not primary_expert_id and responses:
|
|
428
|
+
primary_expert_id = responses[0].get("expert_id")
|
|
429
|
+
|
|
430
|
+
# Ensure a stable non-None primary expert id for downstream logic and dataclass typing.
|
|
431
|
+
if not primary_expert_id:
|
|
432
|
+
primary_expert_id = "unknown"
|
|
433
|
+
|
|
434
|
+
# Aggregate weighted responses
|
|
435
|
+
weighted_answer = self._aggregate_responses(
|
|
436
|
+
responses, domain, primary_expert_id
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
# Calculate agreement level
|
|
440
|
+
agreement_level = self._calculate_agreement(
|
|
441
|
+
responses, domain, primary_expert_id
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
# Calculate confidence using improved algorithm
|
|
445
|
+
valid_responses = [r for r in responses if "error" not in r]
|
|
446
|
+
|
|
447
|
+
# Calculate RAG quality from sources
|
|
448
|
+
rag_quality = None
|
|
449
|
+
if valid_responses:
|
|
450
|
+
sources_count = sum(len(r.get("sources", [])) for r in valid_responses)
|
|
451
|
+
num_responses = len(valid_responses)
|
|
452
|
+
rag_quality = min(
|
|
453
|
+
1.0, sources_count / max(num_responses * 2, 1)
|
|
454
|
+
) # 2 sources per response = perfect
|
|
455
|
+
|
|
456
|
+
# Use improved confidence calculator
|
|
457
|
+
confidence, threshold = ConfidenceCalculator.calculate(
|
|
458
|
+
responses=valid_responses,
|
|
459
|
+
domain=domain,
|
|
460
|
+
agent_id=agent_id,
|
|
461
|
+
agreement_level=agreement_level,
|
|
462
|
+
rag_quality=rag_quality,
|
|
463
|
+
num_experts_consulted=len(expert_ids_to_consult),
|
|
464
|
+
project_profile=project_profile,
|
|
465
|
+
)
|
|
466
|
+
|
|
467
|
+
# Get expert config for thresholds
|
|
468
|
+
expert_config = get_expert_config()
|
|
469
|
+
all_agreed = agreement_level >= expert_config.high_agreement_threshold
|
|
470
|
+
|
|
471
|
+
# Track confidence metrics
|
|
472
|
+
if agent_id:
|
|
473
|
+
try:
|
|
474
|
+
tracker = get_tracker()
|
|
475
|
+
tracker.record(
|
|
476
|
+
agent_id=agent_id,
|
|
477
|
+
domain=domain,
|
|
478
|
+
confidence=confidence,
|
|
479
|
+
threshold=threshold,
|
|
480
|
+
agreement_level=agreement_level,
|
|
481
|
+
num_experts=len(expert_ids_to_consult),
|
|
482
|
+
primary_expert=primary_expert_id or "unknown",
|
|
483
|
+
query=query,
|
|
484
|
+
)
|
|
485
|
+
except Exception as e:
|
|
486
|
+
# Silently fail if tracking fails (non-critical)
|
|
487
|
+
# Log at debug level if logging is available
|
|
488
|
+
import logging
|
|
489
|
+
|
|
490
|
+
logger = logging.getLogger(__name__)
|
|
491
|
+
logger.debug(f"Failed to track confidence metrics: {e}")
|
|
492
|
+
|
|
493
|
+
return ConsultationResult(
|
|
494
|
+
domain=domain,
|
|
495
|
+
query=query,
|
|
496
|
+
responses=responses,
|
|
497
|
+
weighted_answer=weighted_answer,
|
|
498
|
+
agreement_level=agreement_level,
|
|
499
|
+
confidence=confidence,
|
|
500
|
+
confidence_threshold=threshold,
|
|
501
|
+
primary_expert=primary_expert_id,
|
|
502
|
+
all_experts_agreed=all_agreed,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
def _aggregate_responses(
|
|
506
|
+
self,
|
|
507
|
+
responses: list[dict[str, Any]],
|
|
508
|
+
domain: str,
|
|
509
|
+
primary_expert_id: str | None = None,
|
|
510
|
+
) -> str:
|
|
511
|
+
"""
|
|
512
|
+
Aggregate expert responses using weighted decision-making.
|
|
513
|
+
|
|
514
|
+
Primary expert (51%) has primary influence; others augment.
|
|
515
|
+
"""
|
|
516
|
+
if not primary_expert_id:
|
|
517
|
+
# Fallback: use first available response
|
|
518
|
+
primary = next(
|
|
519
|
+
(r for r in responses if r.get("expert_id") and "error" not in r), None
|
|
520
|
+
)
|
|
521
|
+
return primary.get("answer", "") if primary else ""
|
|
522
|
+
|
|
523
|
+
# Try to get primary expert from weight matrix if not provided
|
|
524
|
+
if self.weight_matrix and not primary_expert_id:
|
|
525
|
+
primary_expert_id = self.weight_matrix.get_primary_expert(domain)
|
|
526
|
+
|
|
527
|
+
# Find primary expert response
|
|
528
|
+
primary_response = next(
|
|
529
|
+
(
|
|
530
|
+
r
|
|
531
|
+
for r in responses
|
|
532
|
+
if r.get("expert_id") == primary_expert_id and "error" not in r
|
|
533
|
+
),
|
|
534
|
+
None,
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
if not primary_response:
|
|
538
|
+
# Fallback to first available response
|
|
539
|
+
primary_response = next((r for r in responses if "error" not in r), None)
|
|
540
|
+
if not primary_response:
|
|
541
|
+
return "No expert responses available."
|
|
542
|
+
return primary_response.get("answer", "")
|
|
543
|
+
|
|
544
|
+
# Start with primary expert answer (51% weight)
|
|
545
|
+
primary_answer = primary_response.get("answer", "")
|
|
546
|
+
aggregated_parts = [
|
|
547
|
+
f"[Primary - {primary_response.get('expert_name', 'Expert')}] {primary_answer}"
|
|
548
|
+
]
|
|
549
|
+
|
|
550
|
+
# Add influences from other experts
|
|
551
|
+
other_responses = [
|
|
552
|
+
r
|
|
553
|
+
for r in responses
|
|
554
|
+
if r.get("expert_id") != primary_expert_id and "error" not in r
|
|
555
|
+
]
|
|
556
|
+
|
|
557
|
+
if other_responses:
|
|
558
|
+
influences = []
|
|
559
|
+
for response in other_responses:
|
|
560
|
+
expert_id = response.get("expert_id", "")
|
|
561
|
+
# Get weight from weight matrix if available, otherwise use default
|
|
562
|
+
if self.weight_matrix:
|
|
563
|
+
weight = self.weight_matrix.get_expert_weight(expert_id, domain)
|
|
564
|
+
else:
|
|
565
|
+
# Default weight for non-primary experts (from config)
|
|
566
|
+
expert_config = get_expert_config()
|
|
567
|
+
weight = expert_config.supporting_expert_weight
|
|
568
|
+
answer = response.get("answer", "")
|
|
569
|
+
expert_name = response.get("expert_name", expert_id)
|
|
570
|
+
|
|
571
|
+
influences.append(
|
|
572
|
+
f"[Influence ({weight:.1%}) - {expert_name}] {answer}"
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
if influences:
|
|
576
|
+
aggregated_parts.append("\n\nAdditional Expert Input:")
|
|
577
|
+
aggregated_parts.extend(influences)
|
|
578
|
+
|
|
579
|
+
return "\n".join(aggregated_parts)
|
|
580
|
+
|
|
581
|
+
def _calculate_agreement(
|
|
582
|
+
self, responses: list[dict[str, Any]], domain: str, primary_expert_id: str
|
|
583
|
+
) -> float:
|
|
584
|
+
"""
|
|
585
|
+
Calculate agreement level between experts.
|
|
586
|
+
|
|
587
|
+
Agreement Level = Sum of weights for experts who agree with Primary
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
Agreement level (0.0-1.0)
|
|
591
|
+
"""
|
|
592
|
+
if not self.weight_matrix:
|
|
593
|
+
return 1.0 # Assume agreement if no matrix
|
|
594
|
+
|
|
595
|
+
primary_response = next(
|
|
596
|
+
(
|
|
597
|
+
r
|
|
598
|
+
for r in responses
|
|
599
|
+
if r.get("expert_id") == primary_expert_id and "error" not in r
|
|
600
|
+
),
|
|
601
|
+
None,
|
|
602
|
+
)
|
|
603
|
+
|
|
604
|
+
if not primary_response:
|
|
605
|
+
return 0.51 # Minimum (primary alone)
|
|
606
|
+
|
|
607
|
+
primary_answer = primary_response.get("answer", "")
|
|
608
|
+
|
|
609
|
+
# For now, simple check: count experts with similar answers
|
|
610
|
+
# In a real implementation, this would use semantic similarity
|
|
611
|
+
agreement_weight = 0.51 # Primary always agrees with itself
|
|
612
|
+
|
|
613
|
+
for response in responses:
|
|
614
|
+
expert_id = response.get("expert_id", "")
|
|
615
|
+
if expert_id == primary_expert_id or "error" in response:
|
|
616
|
+
continue
|
|
617
|
+
|
|
618
|
+
# Simple similarity check (in practice, use semantic similarity)
|
|
619
|
+
answer = response.get("answer", "")
|
|
620
|
+
if answer and primary_answer:
|
|
621
|
+
# Very basic: if answers share significant content, consider agreeing
|
|
622
|
+
# This is a placeholder - real implementation would use embeddings
|
|
623
|
+
similarity = self._simple_similarity(primary_answer, answer)
|
|
624
|
+
expert_config = get_expert_config()
|
|
625
|
+
if similarity > expert_config.similarity_threshold:
|
|
626
|
+
weight = self.weight_matrix.get_expert_weight(expert_id, domain)
|
|
627
|
+
agreement_weight += weight
|
|
628
|
+
|
|
629
|
+
return min(agreement_weight, 1.0)
|
|
630
|
+
|
|
631
|
+
def _simple_similarity(self, text1: str, text2: str) -> float:
|
|
632
|
+
"""
|
|
633
|
+
Simple text similarity metric (placeholder).
|
|
634
|
+
|
|
635
|
+
In production, use proper semantic similarity (embeddings, cosine similarity).
|
|
636
|
+
"""
|
|
637
|
+
words1 = set(text1.lower().split())
|
|
638
|
+
words2 = set(text2.lower().split())
|
|
639
|
+
|
|
640
|
+
if not words1 or not words2:
|
|
641
|
+
return 0.0
|
|
642
|
+
|
|
643
|
+
intersection = words1.intersection(words2)
|
|
644
|
+
union = words1.union(words2)
|
|
645
|
+
|
|
646
|
+
return len(intersection) / len(union) if union else 0.0
|
|
647
|
+
|
|
648
|
+
def _get_experts_for_domain(
|
|
649
|
+
self, domain: str, prioritize_builtin: bool = False
|
|
650
|
+
) -> list[str]:
|
|
651
|
+
"""
|
|
652
|
+
Get expert IDs for a domain, prioritizing built-in or customer experts.
|
|
653
|
+
|
|
654
|
+
Args:
|
|
655
|
+
domain: Domain name
|
|
656
|
+
prioritize_builtin: If True, prioritize built-in experts for technical domains.
|
|
657
|
+
If False, prioritize customer experts for business domains.
|
|
658
|
+
|
|
659
|
+
Returns:
|
|
660
|
+
List of expert IDs to consult, ordered by priority
|
|
661
|
+
"""
|
|
662
|
+
expert_ids = []
|
|
663
|
+
is_technical_domain = domain in TECHNICAL_DOMAINS
|
|
664
|
+
|
|
665
|
+
# Find experts that match the domain
|
|
666
|
+
builtin_matches = []
|
|
667
|
+
customer_matches = []
|
|
668
|
+
|
|
669
|
+
for expert_id, expert in self.builtin_experts.items():
|
|
670
|
+
if expert.primary_domain == domain:
|
|
671
|
+
builtin_matches.append(expert_id)
|
|
672
|
+
|
|
673
|
+
for expert_id, expert in self.customer_experts.items():
|
|
674
|
+
if expert.primary_domain == domain:
|
|
675
|
+
customer_matches.append(expert_id)
|
|
676
|
+
|
|
677
|
+
# Determine priority order
|
|
678
|
+
if is_technical_domain and prioritize_builtin:
|
|
679
|
+
# Technical domain: built-in experts first
|
|
680
|
+
expert_ids.extend(builtin_matches)
|
|
681
|
+
expert_ids.extend(customer_matches)
|
|
682
|
+
elif not is_technical_domain and not prioritize_builtin:
|
|
683
|
+
# Business domain: customer experts first
|
|
684
|
+
expert_ids.extend(customer_matches)
|
|
685
|
+
expert_ids.extend(builtin_matches)
|
|
686
|
+
else:
|
|
687
|
+
# Default: built-in first for technical, customer first for business
|
|
688
|
+
if is_technical_domain:
|
|
689
|
+
expert_ids.extend(builtin_matches)
|
|
690
|
+
expert_ids.extend(customer_matches)
|
|
691
|
+
else:
|
|
692
|
+
expert_ids.extend(customer_matches)
|
|
693
|
+
expert_ids.extend(builtin_matches)
|
|
694
|
+
|
|
695
|
+
# If no domain matches, try to find experts with related domains
|
|
696
|
+
if not expert_ids:
|
|
697
|
+
# Fallback: get any expert that might be relevant
|
|
698
|
+
if is_technical_domain:
|
|
699
|
+
expert_ids.extend(list(self.builtin_experts.keys()))
|
|
700
|
+
else:
|
|
701
|
+
expert_ids.extend(list(self.customer_experts.keys()))
|
|
702
|
+
expert_ids.extend(list(self.builtin_experts.keys()))
|
|
703
|
+
|
|
704
|
+
# Apply tech stack priorities if available
|
|
705
|
+
if self._tech_stack_priorities and expert_ids:
|
|
706
|
+
expert_ids = self._apply_priorities(expert_ids)
|
|
707
|
+
|
|
708
|
+
return expert_ids
|
|
709
|
+
|
|
710
|
+
def _apply_priorities(self, expert_ids: list[str]) -> list[str]:
|
|
711
|
+
"""
|
|
712
|
+
Apply tech stack priorities to expert ID list.
|
|
713
|
+
|
|
714
|
+
Experts are sorted by priority (higher first), with experts not in
|
|
715
|
+
priority mapping appearing at the end.
|
|
716
|
+
|
|
717
|
+
Args:
|
|
718
|
+
expert_ids: List of expert IDs to prioritize
|
|
719
|
+
|
|
720
|
+
Returns:
|
|
721
|
+
List of expert IDs sorted by priority (higher first)
|
|
722
|
+
"""
|
|
723
|
+
if not self._tech_stack_priorities:
|
|
724
|
+
return expert_ids
|
|
725
|
+
|
|
726
|
+
# Separate experts into prioritized and unprioritized
|
|
727
|
+
prioritized: list[tuple[str, float]] = []
|
|
728
|
+
unprioritized: list[str] = []
|
|
729
|
+
|
|
730
|
+
for expert_id in expert_ids:
|
|
731
|
+
priority = self._tech_stack_priorities.get(expert_id)
|
|
732
|
+
if priority is not None:
|
|
733
|
+
prioritized.append((expert_id, priority))
|
|
734
|
+
else:
|
|
735
|
+
unprioritized.append(expert_id)
|
|
736
|
+
|
|
737
|
+
# Sort prioritized experts by priority (higher first)
|
|
738
|
+
prioritized.sort(key=lambda x: x[1], reverse=True)
|
|
739
|
+
|
|
740
|
+
# Combine: prioritized experts first (sorted), then unprioritized
|
|
741
|
+
result = [expert_id for expert_id, _ in prioritized]
|
|
742
|
+
result.extend(unprioritized)
|
|
743
|
+
|
|
744
|
+
return result
|