@ngocsangairvds/vsaf 3.2.13 → 3.2.15
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.
- package/bin/vsaf.js +13 -0
- package/package.json +1 -1
- package/src/config.js +167 -0
- package/src/global.js +34 -51
- package/src/utils.js +44 -1
- package/tools/vds-scripts/Makefile +9 -31
- package/tools/vds-scripts/docker/docker-compose.cli.yml +1 -117
- package/tools/vds-scripts/docker/docker-compose.services.yml +1 -40
- package/tools/vds-scripts/docker/infrastructure/init-schemas.sql +0 -34
- package/tools/vds-scripts/docker/infrastructure/pgbouncer/pgbouncer.ini +2 -6
- package/tools/vds-scripts/pyproject.toml +1 -33
- package/tools/vds-scripts/uv.lock +80 -1651
- package/tools/vds-scripts/vds_cli/pyproject.toml +3 -0
- package/tools/vds-scripts/vds_cli/src/vds_cli/cli.py +1 -127
- package/tools/vds-scripts/vds_cli/src/vds_cli/commands/lint_cli.py +1 -20
- package/tools/vds-scripts/vds_cli/src/vds_cli/router.py +0 -100
- package/tools/vds-scripts/vds_cli/tests/conftest.py +0 -2
- package/tools/vds-scripts/vds_cli/tests/unit/test_cli.py +0 -25
- package/tools/vds-scripts/vds_cli/tests/unit/test_lint_cli.py +2 -2
- package/tools/vds-scripts/vds_cli/tests/unit/test_router.py +0 -2
- package/tools/vds-scripts/CLOSURE.md +0 -340
- package/tools/vds-scripts/ECOSYSTEM-CHANGELOG.md +0 -52
- package/tools/vds-scripts/ECOSYSTEM-DOCS.md +0 -602
- package/tools/vds-scripts/ECOSYSTEM_ALIGNMENT.md +0 -133
- package/tools/vds-scripts/ENV-HYGIENE-OPS-NOTE.md +0 -65
- package/tools/vds-scripts/INVESTIGATION-cloud-401.md +0 -103
- package/tools/vds-scripts/MEM0_2.0_API_REFERENCE.md +0 -238
- package/tools/vds-scripts/PACKAGE_P125B_IMPLEMENTATION_SUMMARY.md +0 -131
- package/tools/vds-scripts/PHASE-MERGE-SUMMARY.md +0 -121
- package/tools/vds-scripts/PHASES-3-ARCHIVE.md +0 -59
- package/tools/vds-scripts/PROJECT_COMPLETION_SUMMARY.md +0 -45
- package/tools/vds-scripts/SEARCH-CRASH-REPRO.md +0 -51
- package/tools/vds-scripts/analyze_hexagonal.py +0 -217
- package/tools/vds-scripts/analyze_profiles.py +0 -60
- package/tools/vds-scripts/audit-checklist.xlsx +0 -0
- package/tools/vds-scripts/audit_orchestrator/.audit_approvals/approvals_index.json +0 -1
- package/tools/vds-scripts/audit_orchestrator/.env.example +0 -85
- package/tools/vds-scripts/audit_orchestrator/.github/workflows/audit.yml +0 -47
- package/tools/vds-scripts/audit_orchestrator/Dockerfile +0 -92
- package/tools/vds-scripts/audit_orchestrator/GOOGLE_SHEETS_IMPLEMENTATION_SUMMARY.md +0 -218
- package/tools/vds-scripts/audit_orchestrator/PHASE3_INTEGRATION_SUMMARY.md +0 -268
- package/tools/vds-scripts/audit_orchestrator/PHASE7-MERGE-SUMMARY.md +0 -174
- package/tools/vds-scripts/audit_orchestrator/README.md +0 -1573
- package/tools/vds-scripts/audit_orchestrator/TSK-168-IMPLEMENTATION-SUMMARY.md +0 -191
- package/tools/vds-scripts/audit_orchestrator/TSK-196-IMPLEMENTATION-SUMMARY.md +0 -201
- package/tools/vds-scripts/audit_orchestrator/alembic/env.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/alembic/script.py.mako +0 -28
- package/tools/vds-scripts/audit_orchestrator/alembic/versions/0001_initial_audit_state_schema.py +0 -1260
- package/tools/vds-scripts/audit_orchestrator/alembic.ini +0 -68
- package/tools/vds-scripts/audit_orchestrator/config/category-mapping.json +0 -81
- package/tools/vds-scripts/audit_orchestrator/config/profile-timeouts.yaml +0 -17
- package/tools/vds-scripts/audit_orchestrator/create_sample.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/data/corpus_accuracy_report.json +0 -17
- package/tools/vds-scripts/audit_orchestrator/data/exemplar_quality_report.json +0 -1606
- package/tools/vds-scripts/audit_orchestrator/data/instruction_plan_fixtures.json +0 -163
- package/tools/vds-scripts/audit_orchestrator/data/requirement_exemplars.json +0 -3443
- package/tools/vds-scripts/audit_orchestrator/data/requirement_scope_fixtures.json +0 -172
- package/tools/vds-scripts/audit_orchestrator/debug_rg.py +0 -46
- package/tools/vds-scripts/audit_orchestrator/demo_code_pack.py +0 -127
- package/tools/vds-scripts/audit_orchestrator/docs/AGENT_SDK_SELECTION_SPEC.md +0 -720
- package/tools/vds-scripts/audit_orchestrator/docs/API.md +0 -804
- package/tools/vds-scripts/audit_orchestrator/docs/CONTENT_ANALYSIS_APPROACH.md +0 -1041
- package/tools/vds-scripts/audit_orchestrator/docs/CONTENT_SCORING_EVOLUTION_SPEC.md +0 -868
- package/tools/vds-scripts/audit_orchestrator/docs/DEPLOYMENT.md +0 -778
- package/tools/vds-scripts/audit_orchestrator/docs/LLM_AGENT_AUDIT_SPEC.md +0 -721
- package/tools/vds-scripts/audit_orchestrator/docs/LLM_CONTENT_ANALYSIS_SPEC.md +0 -1143
- package/tools/vds-scripts/audit_orchestrator/docs/LSP_SETUP_GUIDE.md +0 -221
- package/tools/vds-scripts/audit_orchestrator/docs/MULTI_REPO_AUDIT_SPEC.md +0 -951
- package/tools/vds-scripts/audit_orchestrator/docs/OLLAMA_EMBEDDINGS_SETUP.md +0 -119
- package/tools/vds-scripts/audit_orchestrator/docs/PHASE32_REAL_BENCHMARK_2026-02-08.md +0 -66
- package/tools/vds-scripts/audit_orchestrator/docs/PHASE_64_TO_92_HISTORICAL_SPEC.md +0 -1772
- package/tools/vds-scripts/audit_orchestrator/docs/TSK-193-flow-trace.md +0 -201
- package/tools/vds-scripts/audit_orchestrator/docs/TSK-193-verification.md +0 -124
- package/tools/vds-scripts/audit_orchestrator/docs/phase152-hierarchical-query-surface.md +0 -46
- package/tools/vds-scripts/audit_orchestrator/examples/bitbucket_metadata_example.json +0 -50
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/README.md +0 -68
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase117_phase118_shared_state.sql +0 -64
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase154_published_pages.sql +0 -28
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_dispatch_tables.sql +0 -94
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_events.sql +0 -91
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_scope_snapshots.sql +0 -24
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase157_status_view.sql +0 -22
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/phase169_dispatch_observability.sql +0 -55
- package/tools/vds-scripts/audit_orchestrator/legacy/migrations/state_repair_hardening.sql +0 -24
- package/tools/vds-scripts/audit_orchestrator/pyproject.toml +0 -211
- package/tools/vds-scripts/audit_orchestrator/pyrightconfig.json +0 -51
- package/tools/vds-scripts/audit_orchestrator/pytest.ini +0 -37
- package/tools/vds-scripts/audit_orchestrator/reproduce_scanner.py +0 -40
- package/tools/vds-scripts/audit_orchestrator/scripts/README.md +0 -116
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_crawl_modes.py +0 -455
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_dspy.py +0 -513
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_nlp_accuracy.py +0 -138
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_retrieval_modes.py +0 -176
- package/tools/vds-scripts/audit_orchestrator/scripts/benchmark_upload_update_mode.py +0 -167
- package/tools/vds-scripts/audit_orchestrator/scripts/build_check.py +0 -76
- package/tools/vds-scripts/audit_orchestrator/scripts/check_live_progress.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/scripts/cli_integration_test.py +0 -400
- package/tools/vds-scripts/audit_orchestrator/scripts/index_workspace.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/scripts/inspect_route_conformance.py +0 -196
- package/tools/vds-scripts/audit_orchestrator/scripts/monitor_postgres.py +0 -145
- package/tools/vds-scripts/audit_orchestrator/scripts/optimize_audit.py +0 -462
- package/tools/vds-scripts/audit_orchestrator/scripts/verify.py +0 -673
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase111_requirement_analysis.py +0 -375
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase117_cross_repo_evidence.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase121_short_circuit.py +0 -680
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase122_instruction_handling.py +0 -478
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase125_skill_integration.py +0 -832
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase_36.py +0 -394
- package/tools/vds-scripts/audit_orchestrator/scripts/verify_phase_37.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/_langchain_warnings.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/agentic_investigator.py +0 -4130
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/approval.py +0 -490
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/audit_loop_hooks.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/audit_state.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/base.py +0 -4035
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_agent.py +0 -667
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_analysis_helpers.py +0 -236
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/code_analysis_prompts.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/docs_agent.py +0 -1234
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/langgraph_workflow.py +0 -2002
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/pydantic_base.py +0 -1227
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/requirement_analysis_agent.py +0 -593
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/security_agent.py +0 -1829
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/security_scanner.py +0 -686
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/skill_tools.py +0 -204
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/synthesis_agent.py +0 -1463
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/tool_efficiency_guard.py +0 -609
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/tool_registry.py +0 -3822
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/__init__.py +0 -52
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/evidence_corpus.py +0 -385
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/filesystem.py +0 -1134
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/lsp.py +0 -458
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/mcp_toolset.py +0 -491
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/skills_toolset.py +0 -997
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/toolsets/vector_evidence.py +0 -842
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/usage_tracker.py +0 -682
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/agents/visualization.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/analyze_cmds.py +0 -892
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checklist_query/__init__.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checklist_query/service.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/__init__.py +0 -20
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/base.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/bitbucket/__init__.py +0 -6
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/bitbucket/checks.py +0 -257
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/confluence/__init__.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/confluence/checks.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/git/__init__.py +0 -6
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/git/file_checks.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/__init__.py +0 -17
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/api_docs_check.py +0 -80
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/readme_check.py +0 -76
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/llm_checks/security_docs_check.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/registry.py +0 -402
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/sonarqube/__init__.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/checks/sonarqube/checks.py +0 -276
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli.py +0 -12
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli_common.py +0 -128
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/cli_impl.py +0 -9826
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/bitbucket_cli_client.py +0 -187
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/confluence_cli_client.py +0 -977
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/clients/sonarqube_cli_client.py +0 -28
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/__init__.py +0 -21
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/base.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/bitbucket_downloader.py +0 -644
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/bitbucket_metadata.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/checklist_parser.py +0 -180
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/__init__.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/bitbucket_probe.py +0 -443
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/confluence_probe.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/freshness_evaluator.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/completeness/material_completeness_service.py +0 -1079
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/confluence_collector.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/diagram_extractor.py +0 -280
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/enrichment_extractor.py +0 -200
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/evidence_cache.py +0 -35
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/git_collector.py +0 -148
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/graphify_collector.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/image_extractor.py +0 -359
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/linked_page_tracker.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/markdown_converter.py +0 -344
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/material_cache.py +0 -1252
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/material_downloader.py +0 -1165
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/orchestrator.py +0 -168
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/registry_parser.py +0 -3063
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/requirements.py +0 -70
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/runner.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/collectors/sonarqube_collector.py +0 -113
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config.py +0 -1943
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/__init__.py +0 -23
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/discovery.py +0 -90
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/environment_resolver.py +0 -56
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/evidence.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/models.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/precedence.py +0 -10
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/config_resolution/redaction.py +0 -20
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/confluence_connectivity.py +0 -140
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/corpus_cmds.py +0 -278
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/db/__init__.py +0 -7
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/db/alembic_filters.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/docs/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/docs/diataxis_validator.py +0 -687
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/doctor_cmds.py +0 -3295
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/__init__.py +0 -5
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/evaluation.py +0 -301
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/modules.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/runtime.py +0 -836
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/dspy_modules/signatures.py +0 -406
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/__init__.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/ad_hoc_analyzer.py +0 -399
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/aggregator.py +0 -220
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/auditor.py +0 -504
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/batch_evidence_cache.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/batch_processor.py +0 -4776
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/calibration.py +0 -217
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_generator.py +0 -1201
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_projection.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checklist_scoping.py +0 -221
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/checkpoint.py +0 -159
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/cl003_shared_lib_guard.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/companion_context_service.py +0 -445
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/confluence_checklist_contract.py +0 -7425
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/cross_check_rules.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/deterministic_evaluator.py +0 -237
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/drift_detector.py +0 -157
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/dspy_requirement_classifier.py +0 -640
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_assembler.py +0 -407
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_collector.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/evidence_diversity.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/gap_analyzer.py +0 -549
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/graduated.py +0 -185
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/grounding_validator.py +0 -287
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/instruction_analyzer.py +0 -882
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/instruction_compliance.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/llm_row_evaluator.py +0 -9270
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/loader.py +0 -1070
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/manual_check_config.py +0 -136
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/mapping.py +0 -269
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/multi_judge.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/phase120_checklist_update.py +0 -416
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/profile_scorer.py +0 -427
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_evidence_context.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_knowledge_query_service.py +0 -155
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_knowledge_store.py +0 -383
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/project_topology.py +0 -1920
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/provider_failure_classifier.py +0 -778
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_cli_helpers.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_extractor.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/readiness_synthesizer.py +0 -730
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/regression_guard.py +0 -138
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/repo_type_classifier.py +0 -297
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/requirement_analysis.py +0 -1433
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/requirement_classification.py +0 -1725
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/result_merger.py +0 -814
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/route_matrix.py +0 -267
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator.py +0 -9437
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator_runtime.py +0 -1270
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/row_evaluator_types.py +0 -2102
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/rubric.py +0 -592
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/scorer.py +0 -1239
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/section_packs.py +0 -645
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/skill_recommendation.py +0 -1183
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/stability_harness.py +0 -207
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/target_selector.py +0 -841
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/telemetry.py +0 -347
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/template_analyzer.py +0 -469
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/token_tracker.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/tool_first_planner.py +0 -7905
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/topology_query_service.py +0 -80
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/validator.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/engine/weight_policy.py +0 -464
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/errors.py +0 -430
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/extract_cmds.py +0 -4887
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/identity.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/__init__.py +0 -52
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/baseline.py +0 -378
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/change_analyzer.py +0 -407
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/delta_report.py +0 -189
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/incremental/diff_detector.py +0 -301
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/integrations/__init__.py +0 -3
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/__init__.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/audit_schemas.py +0 -459
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/codex_oauth.py +0 -340
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/cost_tracker.py +0 -288
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/engine.py +0 -751
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/evaluator.py +0 -245
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/__init__.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/api_docs_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/gap_analysis.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/instruction_templates.py +0 -634
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/readme_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/row_evaluation.py +0 -247
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/security_docs_evaluation.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts/template_analysis.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/prompts.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/llm/provider.py +0 -626
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/logging_config.py +0 -577
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/__init__.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/default_checklist_mapping.json +0 -18
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/mappings/vietnamese_checklist_mapping.json +0 -38
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/misc_cmds.py +0 -4689
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/__init__.py +0 -153
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/calibration.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/checklist.py +0 -921
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/completeness.py +0 -309
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/enrichment.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/enums.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/evidence.py +0 -351
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/findings.py +0 -381
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/gaps.py +0 -299
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/graph.py +0 -42
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/multi_judge.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/readiness.py +0 -309
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/registry.py +0 -386
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/reporting.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/task.py +0 -549
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/models/template.py +0 -477
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/observability/__init__.py +0 -31
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/observability/metrics.py +0 -404
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/parse_cmds.py +0 -608
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/pdf_cmds.py +0 -208
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/performance_gates.py +0 -224
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/phase151_projection.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/__init__.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/detection.py +0 -842
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/profiles/models.py +0 -474
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/__init__.py +0 -1
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_confluence_macros.py +0 -145
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_field_sanitizer.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_table_builder.py +0 -63
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/_vietnamese_templates.py +0 -103
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/bitbucket_link_resolver.py +0 -34
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/checklist_renderer.py +0 -483
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/confluence_publisher.py +0 -3048
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/hierarchy_publisher.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/live_data_injector.py +0 -152
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/macro_builder.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/markdown_converter.py +0 -154
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/priority_renderer.py +0 -133
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/project_aggregate_renderer.py +0 -423
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/readiness_renderer.py +0 -186
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/system_doc_hierarchy_renderer.py +0 -382
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/publishers/system_doc_renderer.py +0 -683
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/report_cmds.py +0 -788
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/__init__.py +0 -13
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/aggregation_report.py +0 -86
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/checklist_generator.py +0 -425
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/excel_generator.py +0 -599
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/gap_report.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/json_generator.py +0 -188
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/markdown_generator.py +0 -595
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/__init__.py +0 -154
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/collector.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/department_builder.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/errors.py +0 -9
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/md_renderer.py +0 -386
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/pdf_models.py +0 -95
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/pdf_writer.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/pdf/repo_project_builders.py +0 -274
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/readiness_report.py +0 -447
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/reporting.py +0 -94
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/reports/sarif_generator.py +0 -519
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/runtime_profiles.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/seed/__init__.py +0 -29
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/seed/seed_loader.py +0 -561
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/skills/__init__.py +0 -5
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/skills/skill_routing.py +0 -312
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/base.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/bitbucket.py +0 -129
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/git_url.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/github.py +0 -75
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sources/local.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/spec_sync_validator.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/__init__.py +0 -6285
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/readiness_helpers.py +0 -74
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/skill_readiness.py +0 -487
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state/store.py +0 -12927
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/state_cmds.py +0 -1868
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync/repo_sync.py +0 -409
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/sync_cmds.py +0 -1247
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/utils/__init__.py +0 -3
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/utils/debug_bundle.py +0 -214
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/validators/checklist_validator.py +0 -342
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflow_cmds.py +0 -19147
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/__init__.py +0 -9
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/_test_audit_daily_batch.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_daily_batch.py +0 -308
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_deep_monthly.py +0 -193
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_drift_scan.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/src/vds_audit_orchestrator/workflows/audit_security_daily.py +0 -183
- package/tools/vds-scripts/audit_orchestrator/templates/sample_audit_template.xlsx +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/_helpers.py +0 -32
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/test_bitbucket_probe.py +0 -403
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/completeness/test_confluence_probe.py +0 -423
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_bitbucket_downloader.py +0 -289
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_image_extractor.py +0 -260
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_markdown_converter.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_material_cache.py +0 -197
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_material_downloader.py +0 -550
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser.py +0 -3514
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser_department_entry.py +0 -214
- package/tools/vds-scripts/audit_orchestrator/tests/collectors/test_registry_parser_flow.py +0 -200
- package/tools/vds-scripts/audit_orchestrator/tests/conftest.py +0 -988
- package/tools/vds-scripts/audit_orchestrator/tests/engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_calibration.py +0 -48
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_confluence_checklist_phase22_helpers.py +0 -6065
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_multi_judge.py +0 -62
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_stability_harness.py +0 -61
- package/tools/vds-scripts/audit_orchestrator/tests/engine/test_structured_metadata.py +0 -419
- package/tools/vds-scripts/audit_orchestrator/tests/factories/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/factories/models.py +0 -534
- package/tools/vds-scripts/audit_orchestrator/tests/factories/templates.py +0 -241
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/compressed.drawio +0 -2
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/mockup.bmpr +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/diagrams/simple.drawio +0 -26
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/branch_permissions_cli.json +0 -26
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/branch_permissions_direct.json +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/repo_conditions_cli.json +0 -14
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/bitbucket/repo_conditions_direct.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/page_cli.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/page_direct.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/search_cli.json +0 -11
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/confluence/search_direct.json +0 -7
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/quality_gate_cli.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/golden/sonarqube/quality_gate_direct.json +0 -12
- package/tools/vds-scripts/audit_orchestrator/tests/fixtures/requirement_strategy_phase115.json +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/integration/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/conftest.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/expected_outcomes.md +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/auth.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/config.py +0 -16
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/db.py +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/main.py +0 -18
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/src/__init__.py +0 -1
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_audit_repo/src/utils.py +0 -22
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_checklist_template.json +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/code_evidence_pack.json +0 -40
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/manifest.json +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/brd.md +0 -19
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/design.md +0 -32
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/security.md +0 -23
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/srs.md +0 -25
- package/tools/vds-scripts/audit_orchestrator/tests/integration/fixtures/mock_evidence/projects/mock-audit-project/test.md +0 -30
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_checkpoint_merge.py +0 -1371
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_decoupling_route_p149.py +0 -176
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_gap_analyzer_batch_p149.py +0 -151
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_hybrid_search.py +0 -799
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_mcp_integration.py +0 -741
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_merge_ranking_p149.py +0 -98
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_modality_mismatch_p149.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase117_118_storage.py +0 -350
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase121_short_circuit.py +0 -732
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase18_workflow.py +0 -223
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase48_e2e_verification.py +0 -763
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_phase81_doc_anchor_regression.py +0 -252
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_provider_failure_finding_p149.py +0 -339
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_readiness_e2e.py +0 -430
- package/tools/vds-scripts/audit_orchestrator/tests/integration/test_refined_workflow.py +0 -1180
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/department_renderer.md +0 -24
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/project_renderer.md +0 -8
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/snapshots/repo_renderer.md +0 -10
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_department_pdf.py +0 -112
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_e2e_pdf.py +0 -135
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_idempotency.py +0 -45
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_md_renderer.py +0 -46
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_cmds.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_snapshot.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_pdf_writer.py +0 -65
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_project_builder.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_public_api.py +0 -135
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_repo_builder.py +0 -246
- package/tools/vds-scripts/audit_orchestrator/tests/pdf/test_workflow_pdf_flags.py +0 -36
- package/tools/vds-scripts/audit_orchestrator/tests/property/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/property/test_properties.py +0 -807
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_agent_error_compat.py +0 -38
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_agentic_skill_policy_skip.py +0 -234
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_event_stream_logging.py +0 -785
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_timeout_policy.py +0 -277
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_base_trace_payload_sanitization.py +0 -92
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_agent.py +0 -2311
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_agent_re_exports.py +0 -25
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_code_analysis_helpers.py +0 -94
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_create_audit_agent_reasoning_effort.py +0 -69
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_docs_agent.py +0 -2044
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_langgraph_workflow_efficiency_metrics.py +0 -71
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_output_validators.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_phase41_toolsets.py +0 -6427
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_pydantic_ai_models.py +0 -1219
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_pydantic_base_url_resolution.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_security_agent.py +0 -2069
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_skill_manager_focus.py +0 -439
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_synthesis_agent.py +0 -1195
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_tool_efficiency_guard_fr120.py +0 -683
- package/tools/vds-scripts/audit_orchestrator/tests/test_agents/test_toolsets.py +0 -716
- package/tools/vds-scripts/audit_orchestrator/tests/test_aggregator_p149.py +0 -171
- package/tools/vds-scripts/audit_orchestrator/tests/test_alembic_migrations.py +0 -287
- package/tools/vds-scripts/audit_orchestrator/tests/test_anchor_allowlist_p149.py +0 -273
- package/tools/vds-scripts/audit_orchestrator/tests/test_audit_otel.py +0 -283
- package/tools/vds-scripts/audit_orchestrator/tests/test_checklist_models.py +0 -583
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/test_base_check.py +0 -211
- package/tools/vds-scripts/audit_orchestrator/tests/test_checks/test_llm_checks.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_analyze_command.py +0 -400
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_archive_stale_page_cli.py +0 -217
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_bitbucket_metadata_cli.py +0 -354
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_cli_impl_profile_availability.py +0 -114
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_codex_profile.py +0 -174
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_compare_backends_cli.py +0 -449
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_confluence_parent_auto_resolve.py +0 -451
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_corpus_purge_cli.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_credentials_preflight.py +0 -106
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_debug_bundle.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_deprecation_phase157.py +0 -484
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_dispatch_concurrency_diagnostics.py +0 -758
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_check_confluence_cli.py +0 -320
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_codex.py +0 -187
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_corpus_status_cli.py +0 -236
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_correlation_cli.py +0 -128
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_crawl_status_cli.py +0 -192
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_credentials_cli.py +0 -86
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_dispatch_status_cli.py +0 -421
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_heartbeat_phase169.py +0 -173
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_hierarchy_status_cli.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_locks_cli.py +0 -134
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_logs_follow_cli.py +0 -305
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_migration.py +0 -333
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_profile_availability_cli.py +0 -151
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_doctor_skills_policy_cli.py +0 -153
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_evidence_quality_cli.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_export_debug_bundle_phase36.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_export_git_manifest_cli.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_file_removal_phase157e.py +0 -770
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_grounding_classifier.py +0 -226
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_logging.py +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_materials_cli.py +0 -9127
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_metadata_completeness_phase92.py +0 -364
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_parent_dispatch_finalization_phase168f.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_parse_cli.py +0 -590
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase117_118_feature_flags.py +0 -219
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase164_control_plane.py +0 -718
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_phase165_runner_scripts.py +0 -230
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_preparation_classifications.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_prepare_cli.py +0 -398
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_publication_quality_gate.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_publish_system_doc_cli.py +0 -158
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_query_checklist_cli.py +0 -219
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_readiness_cli.py +0 -673
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_readiness_cli_integration.py +0 -689
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_removed_flags_phase92.py +0 -36
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_report_cmds.py +0 -1317
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_run_history_index.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_run_management.py +0 -1194
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_runtime_profiles_cli.py +0 -1658
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_smart_run_selection.py +0 -1562
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_state_cli.py +0 -2467
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_state_migration.py +0 -339
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_sync_repos_debug_artifacts.py +0 -1109
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_upload_results_cli.py +0 -809
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_checklist.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_checklist_cli.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_validate_spec_sync_cli.py +0 -519
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_default_parameters_baseline.py +0 -101
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_options.py +0 -7896
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_db_modes.py +0 -6516
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_project_scope.py +0 -831
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_project_target.py +0 -611
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_projects_phase131_lifecycle.py +0 -2488
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_projects_phase131_scaffolding.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_row_key_guard.py +0 -78
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli/test_workflow_summary_artifacts.py +0 -1872
- package/tools/vds-scripts/audit_orchestrator/tests/test_cli_paths_phase2.py +0 -45
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_bitbucket_cli_client.py +0 -124
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_cli_parity.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_confluence_cli_client.py +0 -1149
- package/tools/vds-scripts/audit_orchestrator/tests/test_clients/test_sonarqube_cli_client.py +0 -19
- package/tools/vds-scripts/audit_orchestrator/tests/test_collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_collectors/test_linked_page_tracker.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/test_companion_context_service.py +0 -230
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/conftest.py +0 -11
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_compile_artifact.py +0 -465
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_cross_provider_critique.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_cross_provider_critique_e2e.py +0 -75
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_evaluation.py +0 -515
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_runtime_loader.py +0 -537
- package/tools/vds-scripts/audit_orchestrator/tests/test_dspy_modules/test_signatures_normalization.py +0 -172
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_auditor_applicability.py +0 -68
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_checklist_generator.py +0 -1252
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_checklist_projection.py +0 -54
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_confluence_checklist_projection_consistency.py +0 -1696
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_critique_merger_matrix.py +0 -120
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_cross_check_rules.py +0 -459
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_cross_provider_critique.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_doc_loader.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_drift_detector.py +0 -34
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_evidence_collectors.py +0 -93
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_lease_timeout.py +0 -114
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_loader.py +0 -350
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_loader_parity.py +0 -179
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_low_confidence_reeval.py +0 -691
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_phase145a_completion.py +0 -209
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_phase31_row_consistency_retry_benchmark.py +0 -150
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_profile_detector.py +0 -286
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_regression_guard.py +0 -53
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_result_merger.py +0 -619
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_row_evaluator.py +0 -15783
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_row_failover.py +0 -215
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_scorer.py +0 -597
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_skill_breakdown_telemetry_fr137.py +0 -421
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_targeted_auto_merge.py +0 -229
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_timeout_failover.py +0 -488
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_timeout_telemetry.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_engine/test_validator.py +0 -419
- package/tools/vds-scripts/audit_orchestrator/tests/test_incremental/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_incremental/test_diff_detector.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/test_infra_persistence.py +0 -291
- package/tools/vds-scripts/audit_orchestrator/tests/test_integration/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_integration/test_phase3_integration.py +0 -516
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_cache.py +0 -670
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_model_builder.py +0 -281
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_oauth.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_codex_streaming.py +0 -433
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_cost_tracker.py +0 -27
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_engine.py +0 -876
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_evaluator.py +0 -212
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_instruction_templates.py +0 -639
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_prompt_metadata.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_prompts.py +0 -660
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_provider.py +0 -330
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_provider_contract_sync.py +0 -18
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_reasoning_effort_validation.py +0 -565
- package/tools/vds-scripts/audit_orchestrator/tests/test_llm/test_schemas.py +0 -827
- package/tools/vds-scripts/audit_orchestrator/tests/test_logging_config.py +0 -297
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_enums.py +0 -185
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_findings.py +0 -1159
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_project_profile.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_registry.py +0 -532
- package/tools/vds-scripts/audit_orchestrator/tests/test_models/test_template.py +0 -708
- package/tools/vds-scripts/audit_orchestrator/tests/test_observability/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_observability/test_metrics.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/test_paths_config_phase2.py +0 -21
- package/tools/vds-scripts/audit_orchestrator/tests/test_performance/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_performance/test_fr79_performance_guardrails.py +0 -199
- package/tools/vds-scripts/audit_orchestrator/tests/test_phase156_hardening.py +0 -498
- package/tools/vds-scripts/audit_orchestrator/tests/test_phase93_regression_guards.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/test_pipeline_integration.py +0 -517
- package/tools/vds-scripts/audit_orchestrator/tests/test_profiles/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_profiles/test_detection.py +0 -146
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_bitbucket_link_resolver.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_checklist_renderer.py +0 -84
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_checklist_renderer_projection.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_confluence_macros.py +0 -58
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_confluence_publisher.py +0 -2171
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_evidence_links.py +0 -129
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_field_sanitizer.py +0 -108
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_hierarchy_publisher.py +0 -134
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_incremental_plan_parser.py +0 -62
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_live_data_injector.py +0 -48
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_macro_builder.py +0 -22
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_p161_confluence_optimization.py +0 -168
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_priority_renderer.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_project_aggregate_renderer.py +0 -364
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_storage_validation.py +0 -273
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_summary_refactor.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_system_doc_hierarchy.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_table_builder.py +0 -23
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_vietnamese_templates.py +0 -37
- package/tools/vds-scripts/audit_orchestrator/tests/test_publishers/test_wiring_integration.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_aggregation_report.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_checklist_generator.py +0 -258
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_gap_report.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/test_reports/test_json_generator.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/test_result_merger_p149.py +0 -347
- package/tools/vds-scripts/audit_orchestrator/tests/test_route_mode_p149.py +0 -178
- package/tools/vds-scripts/audit_orchestrator/tests/test_rubric_parser.py +0 -179
- package/tools/vds-scripts/audit_orchestrator/tests/test_scorer.py +0 -110
- package/tools/vds-scripts/audit_orchestrator/tests/test_state/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_state/test_sparse_coverage.py +0 -117
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/test_langgraph_workflow.py +0 -2072
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow/test_p161_runtime_hardening.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_cmds_p149.py +0 -112
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_cmds_p172.py +0 -126
- package/tools/vds-scripts/audit_orchestrator/tests/test_workflow_guidance_p150.py +0 -95
- package/tools/vds-scripts/audit_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_agentic_investigator_phase115.py +0 -42
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_requirement_analysis_agent.py +0 -412
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_security_agent_updates.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_security_scanner.py +0 -397
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_executor.py +0 -316
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_fallback.py +0 -299
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_policy.py +0 -520
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_skill_telemetry.py +0 -306
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_synthesis_fixes.py +0 -761
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_argument_robustness.py +0 -272
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry.py +0 -2548
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_ast_grep.py +0 -87
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_phase123_scoping.py +0 -353
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_phase94_ff.py +0 -445
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_tool_registry_vector_search_phase115.py +0 -35
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_utils.py +0 -1007
- package/tools/vds-scripts/audit_orchestrator/tests/unit/agents/test_vector_evidence_toolset.py +0 -622
- package/tools/vds-scripts/audit_orchestrator/tests/unit/cli/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/cli/test_workflow_cli.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_cache_guard.py +0 -479
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_checklist_parser_phase120.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_diagram_extractor.py +0 -467
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_enrichment_extractor.py +0 -59
- package/tools/vds-scripts/audit_orchestrator/tests/unit/collectors/test_graphify_collector.py +0 -158
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_completeness.py +0 -563
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_freshness_evaluator.py +0 -493
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_material_cache_metrics.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/tests/unit/completeness/test_material_completeness_service.py +0 -2736
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/test_discovery.py +0 -47
- package/tools/vds-scripts/audit_orchestrator/tests/unit/config_resolution/test_redaction.py +0 -15
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_ad_hoc_analyzer.py +0 -576
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_agent_loop.py +0 -1896
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_anchor_filter_cl003.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_batch_evidence_cache.py +0 -155
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_batch_processor.py +0 -3608
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_checklist_contract.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_checklist_scoping.py +0 -371
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_config_companion_phase123.py +0 -142
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_config_evidence_phase123.py +0 -249
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_confluence_checklist_contract_export_parity.py +0 -813
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_cross_repo_config_phase122.py +0 -613
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_dspy_requirement_classifier.py +0 -517
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_evidence_diversity.py +0 -144
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_evidence_truncation.py +0 -108
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_grounding_validator.py +0 -127
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_guidance_injection_phase120.py +0 -105
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_instruction_analysis_phase122.py +0 -761
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_instruction_pre_filter_phase167.py +0 -334
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_llm_row_evaluator_retries.py +0 -3684
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_loader_phase123.py +0 -345
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_manual_check_gating_phase122.py +0 -474
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_parallel_eval.py +0 -263
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_phase122_verifier_phase122.py +0 -169
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_phase166_route_failover.py +0 -437
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_post_eval_cl003_shared_lib.py +0 -267
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_postproc_streaming.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_pre_eval_gating_phase122.py +0 -362
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_prepare_topology_coverage.py +0 -247
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_private_dns_sanitization_phase104.py +0 -397
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_evidence_context.py +0 -450
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_knowledge_store.py +0 -487
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_project_topology.py +0 -1142
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_provider_failure_classifier.py +0 -195
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_readiness_extractor.py +0 -496
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_readiness_synthesizer.py +0 -653
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_repo_type_classifier.py +0 -303
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis.py +0 -508
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_execution_scope.py +0 -239
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_phase114.py +0 -919
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_phase115.py +0 -97
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_analysis_shared_lib.py +0 -340
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_classification_drift.py +0 -729
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_classification_nlp.py +0 -670
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_requirement_scope_phase122.py +0 -615
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_route_matrix.py +0 -258
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_route_override.py +0 -141
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_routing_precision.py +0 -650
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_dual_evidence.py +0 -2987
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_instruction_runtime_phase122.py +0 -365
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_row_evaluator_runtime.py +0 -830
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_runtime_hardening_phase122.py +0 -225
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_scoped_na_skip.py +0 -107
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_scoring_enhancements.py +0 -404
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_library_retrieval_phase123.py +0 -441
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_library_routing_phase123.py +0 -279
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_shared_resource_indexing_phase122.py +0 -188
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skill_recommendation.py +0 -225
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skill_routing_cl003_shared_lib.py +0 -338
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_skills_toolset.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_stability_metric.py +0 -60
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_target_selector.py +0 -958
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_token_tracker.py +0 -121
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_token_wiring.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_tool_first_planner.py +0 -7103
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_topology_knowledge_persistence.py +0 -332
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_topology_query_service.py +0 -55
- package/tools/vds-scripts/audit_orchestrator/tests/unit/engine/test_unverified_ref_retry.py +0 -909
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_evidence.py +0 -515
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_gaps.py +0 -422
- package/tools/vds-scripts/audit_orchestrator/tests/unit/models/test_readiness.py +0 -428
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_confluence_hierarchy.py +0 -227
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_project_title_generation.py +0 -335
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_publisher_registry_helpers.py +0 -290
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_publisher_registry_integration.py +0 -557
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_readiness_renderer.py +0 -381
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_repo_title_consistency.py +0 -266
- package/tools/vds-scripts/audit_orchestrator/tests/unit/publishers/test_upload_hierarchy_integration.py +0 -470
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_dspy.py +0 -177
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_nlp_accuracy.py +0 -72
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_benchmark_retrieval_modes.py +0 -123
- package/tools/vds-scripts/audit_orchestrator/tests/unit/scripts/test_verify_phase111_requirement_analysis.py +0 -409
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/test_seed_chain_cli.py +0 -277
- package/tools/vds-scripts/audit_orchestrator/tests/unit/seed/test_seed_loader.py +0 -502
- package/tools/vds-scripts/audit_orchestrator/tests/unit/skills/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/skills/test_skill_routing.py +0 -209
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_bitbucket_source.py +0 -66
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_non_retryable_markers.py +0 -88
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sources/test_repo_info.py +0 -212
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_completeness.py +0 -598
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_events_contract_phase169.py +0 -100
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_hardening_phase158.py +0 -392
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_dispatch_persistence_phase157.py +0 -914
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_embedding_client.py +0 -64
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_get_latest_completed_run.py +0 -313
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_heartbeat_phase169.py +0 -109
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_hybrid_search.py +0 -398
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_normalize_url.py +0 -262
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_phase152_query_surface.py +0 -59
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_phase98_confluence_document_model.py +0 -202
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_published_pages.py +0 -754
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_readiness_helpers.py +0 -193
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_run_ledger.py +0 -522
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_run_management.py +0 -378
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_schema_contract_phase170.py +0 -755
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_cmds.py +0 -231
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_loaders.py +0 -2151
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_state_run_api.py +0 -2226
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store.py +0 -1435
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_dispatch.py +0 -646
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_dispatch_status_view.py +0 -181
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_store_scope.py +0 -213
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_utilization_persist_phase169.py +0 -77
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vds_search.py +0 -263
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_api.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_runtime.py +0 -175
- package/tools/vds-scripts/audit_orchestrator/tests/unit/state/test_vector_index_store.py +0 -1756
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sync/__init__.py +0 -0
- package/tools/vds-scripts/audit_orchestrator/tests/unit/sync/test_repo_sync.py +0 -257
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_artifact_exclusion.py +0 -119
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_auto_promote_phase158.py +0 -337
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_carry_forward_artifact_filtering.py +0 -317
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_checklist_precache_p160a.py +0 -416
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_cli_decomposition_fr219.py +0 -269
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_code_chunk_carry_forward.py +0 -203
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_config_coherence.py +0 -180
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_config_secret_policy.py +0 -522
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_corpus_project_id_migration.py +0 -318
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_corpus_status_diagnostics.py +0 -239
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_department_priority_ordering.py +0 -131
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_coordinator_phase158.py +0 -402
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_job_identity_p167a.py +0 -238
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatch_ramp_up_phase171.py +0 -434
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_dispatcher.py +0 -911
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_doc_type_en_inference.py +0 -246
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_early_exit_unchunked_repos.py +0 -111
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_errors.py +0 -237
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_errors_taxonomy.py +0 -83
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_chunking_config_phase98.py +0 -73
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_cmds_state_helpers.py +0 -33
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_extract_docs_code_chunking.py +0 -260
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_finalize_dispatch_run_phase168.py +0 -341
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_identity.py +0 -221
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_infrastructure_detection.py +0 -441
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_junction_table_phase95.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_late_binding_assignment_p167c.py +0 -286
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_misc_cmds_fr224_225_hardening.py +0 -194
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_p172_integration.py +0 -306
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_parent_provider_preflight.py +0 -118
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_performance_gates_phase92.py +0 -141
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_performance_gates_phase93.py +0 -50
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase115_search_strategy.py +0 -106
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase154_title_consistency.py +0 -117
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase155_param_forwarding.py +0 -304
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase158_concurrency_defaults.py +0 -207
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase170_doctor_schema.py +0 -319
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase170_regression.py +0 -334
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase94_corpus_lifecycle.py +0 -307
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_phase96_repo_key_migration.py +0 -305
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_pipelined_scheduling.py +0 -130
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_availability_probe.py +0 -616
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_aware_row_timeout.py +0 -102
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_profile_timeout_stagger_p160cd.py +0 -205
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_progress_summary_phase169.py +0 -96
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_registry_checklist_diagnostics.py +0 -124
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_resume_manifest_p167b.py +0 -268
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_risk_mitigations_p160e1.py +0 -348
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_single_row_shards_p160b.py +0 -357
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_state_repo_discovery.py +0 -504
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_sync_metadata_entries.py +0 -57
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_task_models.py +0 -1796
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_utilization_telemetry_p167e.py +0 -259
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_vietnamese_fts_hardening.py +0 -160
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_phase98_enrichment.py +0 -92
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_project_merge_materialization.py +0 -322
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_row_key_migration_guard.py +0 -88
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_short_circuit_phase121.py +0 -564
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_workflow_single_target_row_context.py +0 -49
- package/tools/vds-scripts/audit_orchestrator/tests/unit/test_zero_result_messaging.py +0 -76
- package/tools/vds-scripts/bandit-report.json +0 -2974
- package/tools/vds-scripts/brd_orchestrator/README.md +0 -29
- package/tools/vds-scripts/brd_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/cli.py +0 -187
- package/tools/vds-scripts/brd_orchestrator/src/vds_brd_orchestrator/validator.py +0 -121
- package/tools/vds-scripts/brd_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/brd_orchestrator/tests/test_cli.py +0 -62
- package/tools/vds-scripts/brd_orchestrator/tests/test_validator.py +0 -33
- package/tools/vds-scripts/circular_dependency_orchestrator/README.md +0 -30
- package/tools/vds-scripts/circular_dependency_orchestrator/pyproject.toml +0 -43
- package/tools/vds-scripts/circular_dependency_orchestrator/src/vds_circular_dependency_orchestrator/__init__.py +0 -16
- package/tools/vds-scripts/circular_dependency_orchestrator/src/vds_circular_dependency_orchestrator/cli.py +0 -904
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/circular_dependency_orchestrator/tests/unit/test_cli.py +0 -354
- package/tools/vds-scripts/coverage.json +0 -1
- package/tools/vds-scripts/create_pr.py +0 -57
- package/tools/vds-scripts/diagram_generator/README.md +0 -663
- package/tools/vds-scripts/diagram_generator/ci_validate.sh +0 -16
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-component.puml +0 -23
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-sequence.puml +0 -21
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.png +0 -0
- package/tools/vds-scripts/diagram_generator/docs-nttc/projects/INSURANCE/analysis/current-state/insurance-claim-business/insurance-claim-business-usecase.puml +0 -14
- package/tools/vds-scripts/diagram_generator/examples/github-actions-validate.yml +0 -39
- package/tools/vds-scripts/diagram_generator/generate_all_diagrams.py +0 -827
- package/tools/vds-scripts/diagram_generator/generate_insurance_c4_diagrams.py +0 -261
- package/tools/vds-scripts/diagram_generator/generate_insurance_c4_quick.py +0 -486
- package/tools/vds-scripts/diagram_generator/pyproject.toml +0 -28
- package/tools/vds-scripts/diagram_generator/render_png.py +0 -59
- package/tools/vds-scripts/diagram_generator/src/vds_diagram_generator/__init__.py +0 -3
- package/tools/vds-scripts/diagram_generator/src/vds_diagram_generator/cli.py +0 -50
- package/tools/vds-scripts/diagram_generator/test_c4_hierarchical.py +0 -142
- package/tools/vds-scripts/diagram_generator/test_c4_quick.py +0 -131
- package/tools/vds-scripts/diagram_generator/tests/__init__.py +0 -0
- package/tools/vds-scripts/diagram_generator/tests/test_analyzer_completeness.py +0 -260
- package/tools/vds-scripts/diagram_generator/tests/test_c4_syntax_correctness.py +0 -138
- package/tools/vds-scripts/diagram_generator/tests/test_component_coverage.py +0 -182
- package/tools/vds-scripts/diagram_generator/tests/test_mermaid_output.py +0 -80
- package/tools/vds-scripts/diagram_generator/tests/test_png_generation.py +0 -112
- package/tools/vds-scripts/diagram_generator/tests/test_scenario_templates.py +0 -15
- package/tools/vds-scripts/diagram_generator/tests/test_sequence_accuracy.py +0 -93
- package/tools/vds-scripts/diagram_generator/tests/test_structurizr_export.py +0 -177
- package/tools/vds-scripts/diagram_generator/tests/test_style_consistency.py +0 -174
- package/tools/vds-scripts/diagram_generator/tests/test_usecase_generator.py +0 -201
- package/tools/vds-scripts/diagram_generator/tests/test_usecase_integration.py +0 -124
- package/tools/vds-scripts/docker/compose.phase2-verification.yml +0 -31
- package/tools/vds-scripts/docker-compose.openapi-validator.yml +0 -14
- package/tools/vds-scripts/excel_orchestrator/README.md +0 -288
- package/tools/vds-scripts/excel_orchestrator/RESEARCH_BASED_UPDATES_REPORT.md +0 -261
- package/tools/vds-scripts/excel_orchestrator/add_essential_missing_effort.py +0 -255
- package/tools/vds-scripts/excel_orchestrator/adjust_effort_complexity.py +0 -184
- package/tools/vds-scripts/excel_orchestrator/brd_analysis_and_task_breakdown.py +0 -632
- package/tools/vds-scripts/excel_orchestrator/brd_analysis_comprehensive.py +0 -1029
- package/tools/vds-scripts/excel_orchestrator/check_overlaps_and_brd_coverage.py +0 -570
- package/tools/vds-scripts/excel_orchestrator/clean_remarks_column.py +0 -127
- package/tools/vds-scripts/excel_orchestrator/comprehensive_brd_check.py +0 -322
- package/tools/vds-scripts/excel_orchestrator/create_buffered_summary.py +0 -119
- package/tools/vds-scripts/excel_orchestrator/create_service_totals_sheet.py +0 -118
- package/tools/vds-scripts/excel_orchestrator/examples/basic_operations.py +0 -85
- package/tools/vds-scripts/excel_orchestrator/expand_all_tasks.py +0 -341
- package/tools/vds-scripts/excel_orchestrator/expand_tasks.py +0 -304
- package/tools/vds-scripts/excel_orchestrator/fill_brd_references.py +0 -347
- package/tools/vds-scripts/excel_orchestrator/fill_remarks_and_colors.py +0 -132
- package/tools/vds-scripts/excel_orchestrator/finalize_brd_and_cleanup.py +0 -295
- package/tools/vds-scripts/excel_orchestrator/finalize_brd_coverage.py +0 -327
- package/tools/vds-scripts/excel_orchestrator/fix_all_formulas.py +0 -99
- package/tools/vds-scripts/excel_orchestrator/fix_detail_presentation.py +0 -113
- package/tools/vds-scripts/excel_orchestrator/fix_presentation_and_effort.py +0 -116
- package/tools/vds-scripts/excel_orchestrator/fix_presentation_consistency.py +0 -231
- package/tools/vds-scripts/excel_orchestrator/fix_remarks_matching.py +0 -179
- package/tools/vds-scripts/excel_orchestrator/group_tasks_by_service_id.py +0 -210
- package/tools/vds-scripts/excel_orchestrator/increase_brd_coverage.py +0 -497
- package/tools/vds-scripts/excel_orchestrator/increase_effort_complexity.py +0 -155
- package/tools/vds-scripts/excel_orchestrator/organize_and_deduplicate.py +0 -273
- package/tools/vds-scripts/excel_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/excel_orchestrator/rebuild_all_formulas.py +0 -146
- package/tools/vds-scripts/excel_orchestrator/remove_base_multiplier_and_check_duplicates.py +0 -310
- package/tools/vds-scripts/excel_orchestrator/remove_duplicate_brd_tasks.py +0 -137
- package/tools/vds-scripts/excel_orchestrator/research_based_updates.py +0 -457
- package/tools/vds-scripts/excel_orchestrator/restore_e_values.py +0 -172
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/cli.py +0 -746
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/config.py +0 -74
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/converters.py +0 -226
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/errors.py +0 -88
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/excel_client.py +0 -443
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/formatters.py +0 -211
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/logging.py +0 -57
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/source_contract.py +0 -29
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/target_state_status.py +0 -837
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/ulnc_alignment.py +0 -1291
- package/tools/vds-scripts/excel_orchestrator/src/vds_excel_orchestrator/validators.py +0 -164
- package/tools/vds-scripts/excel_orchestrator/sync_detail_and_total_sheets.py +0 -211
- package/tools/vds-scripts/excel_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/excel_orchestrator/tests/conftest.py +0 -36
- package/tools/vds-scripts/excel_orchestrator/tests/test_cli.py +0 -383
- package/tools/vds-scripts/excel_orchestrator/tests/test_excel_client.py +0 -129
- package/tools/vds-scripts/excel_orchestrator/tests/test_ulnc_alignment.py +0 -373
- package/tools/vds-scripts/excel_orchestrator/tests/test_validators.py +0 -64
- package/tools/vds-scripts/excel_orchestrator/update_api_database_effort.py +0 -261
- package/tools/vds-scripts/excel_orchestrator/update_buffers_inline.py +0 -115
- package/tools/vds-scripts/excel_orchestrator/update_complex_services_and_add_new.py +0 -336
- package/tools/vds-scripts/excel_orchestrator/update_responsibility_and_fix_rows.py +0 -208
- package/tools/vds-scripts/excel_orchestrator/update_task_breakdown_vietnamese.py +0 -309
- package/tools/vds-scripts/excel_orchestrator/update_vietnamese_and_responsibility.py +0 -415
- package/tools/vds-scripts/excel_orchestrator/verify_brd_coverage_comprehensive.py +0 -401
- package/tools/vds-scripts/hexagonal_orchestrator/README.md +0 -530
- package/tools/vds-scripts/hexagonal_orchestrator/pyproject.toml +0 -48
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/__init__.py +0 -39
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/__init__.py +0 -19
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/base.py +0 -95
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/fallback.py +0 -614
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/java.py +0 -372
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/analyzers/python.py +0 -437
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/cache.py +0 -331
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/classifier.py +0 -263
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/cli.py +0 -554
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/config.py +0 -577
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/models.py +0 -159
- package/tools/vds-scripts/hexagonal_orchestrator/src/vds_hexagonal_orchestrator/profiler.py +0 -451
- package/tools/vds-scripts/hexagonal_orchestrator/test-config.yaml +0 -38
- package/tools/vds-scripts/hexagonal_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/adapter/driven/persistence/InMemoryUserRepository.java +0 -62
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/adapter/driving/api/UserController.java +0 -101
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/port/EmailService.java +0 -33
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/port/UserRepository.java +0 -45
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/application/usecase/CreateUser.java +0 -58
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/domain/entity/Email.java +0 -80
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-compliant/domain/entity/User.java +0 -98
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-noncompliant/domain/User.java +0 -64
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-with-frameworks/domain/Menu.java +0 -13
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/java-with-frameworks/domain/Product.java +0 -16
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/email_service.py +0 -60
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/application/ports/user_repository.py +0 -78
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/entities/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/entities/user.py +0 -56
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/value_objects/__init__.py +0 -1
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-compliant/domain/value_objects/email.py +0 -63
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-noncompliant/application/user_service.py +0 -1837
- package/tools/vds-scripts/hexagonal_orchestrator/tests/fixtures/python-noncompliant/domain/user.py +0 -43
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cache.py +0 -458
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cli_integration.py +0 -942
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cli_unit.py +0 -557
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_cross_repo_pollution.py +0 -275
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_foundation.py +0 -129
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_integration.py +0 -1524
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_java_analyzer.py +0 -642
- package/tools/vds-scripts/hexagonal_orchestrator/tests/test_timing_unit.py +0 -60
- package/tools/vds-scripts/intellij_orchestrator/README.md +0 -55
- package/tools/vds-scripts/intellij_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/__init__.py +0 -17
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/cli.py +0 -210
- package/tools/vds-scripts/intellij_orchestrator/src/vds_intellij_orchestrator/core.py +0 -260
- package/tools/vds-scripts/intellij_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/intellij_orchestrator/tests/test_cli.py +0 -112
- package/tools/vds-scripts/intellij_orchestrator/tests/test_core.py +0 -83
- package/tools/vds-scripts/links_orchestrator/README.md +0 -63
- package/tools/vds-scripts/links_orchestrator/pyproject.toml +0 -64
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/__init__.py +0 -10
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/cli.py +0 -254
- package/tools/vds-scripts/links_orchestrator/src/vds_links_orchestrator/validator.py +0 -244
- package/tools/vds-scripts/links_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/links_orchestrator/tests/test_cli.py +0 -128
- package/tools/vds-scripts/links_orchestrator/tests/test_validator.py +0 -76
- package/tools/vds-scripts/lsp_orchestrator/.dockerignore +0 -69
- package/tools/vds-scripts/lsp_orchestrator/ARCHITECTURE.md +0 -383
- package/tools/vds-scripts/lsp_orchestrator/CODE_QUALITY_IMPROVEMENTS.md +0 -196
- package/tools/vds-scripts/lsp_orchestrator/COMMANDS.md +0 -870
- package/tools/vds-scripts/lsp_orchestrator/Dockerfile +0 -59
- package/tools/vds-scripts/lsp_orchestrator/IMPLEMENTATION_SUMMARY.md +0 -490
- package/tools/vds-scripts/lsp_orchestrator/LSP_ISSUES_AND_FINDINGS.md +0 -380
- package/tools/vds-scripts/lsp_orchestrator/README.md +0 -616
- package/tools/vds-scripts/lsp_orchestrator/SETUP.md +0 -143
- package/tools/vds-scripts/lsp_orchestrator/TEST_COVERAGE_SUMMARY.md +0 -255
- package/tools/vds-scripts/lsp_orchestrator/VERIFICATION_CHECKLIST.md +0 -814
- package/tools/vds-scripts/lsp_orchestrator/docker-compose.yml +0 -102
- package/tools/vds-scripts/lsp_orchestrator/docs/FOR_LLMS.md +0 -401
- package/tools/vds-scripts/lsp_orchestrator/docs/explanation/lsp-response-matching.md +0 -79
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/automate-with-json.md +0 -159
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/docker-mode.md +0 -256
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/navigate-code.md +0 -116
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/parallel-processing.md +0 -179
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/project-tool-detection.md +0 -320
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/type-check-code.md +0 -46
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/use-daemon-mode.md +0 -78
- package/tools/vds-scripts/lsp_orchestrator/docs/how-to-guides/wsl2-optimization.md +0 -227
- package/tools/vds-scripts/lsp_orchestrator/docs/index.md +0 -88
- package/tools/vds-scripts/lsp_orchestrator/docs/operator-hover-definition.md +0 -143
- package/tools/vds-scripts/lsp_orchestrator/docs/reference/commands.md +0 -581
- package/tools/vds-scripts/lsp_orchestrator/docs/reference/configuration.md +0 -422
- package/tools/vds-scripts/lsp_orchestrator/docs/tutorials/00-quick-start.md +0 -169
- package/tools/vds-scripts/lsp_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/lsp_orchestrator/src/test_file.py +0 -5
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/aggregator.py +0 -340
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/basedpyright_runner.py +0 -167
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/cli.py +0 -3370
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/code_actions.py +0 -79
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/core.py +0 -3295
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_client.py +0 -672
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_manager.py +0 -577
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/daemon_server.py +0 -1040
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/detectors/__init__.py +0 -9
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/detectors/project_detector.py +0 -537
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/formatters.py +0 -141
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ipc_protocol.py +0 -225
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/lsp_client.py +0 -957
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/lsp_router.py +0 -335
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/mcp_server.py +0 -181
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/__init__.py +0 -201
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/project_detector.py +0 -646
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models/project_tools.py +0 -114
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/models.py +0 -399
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/mypy_runner.py +0 -209
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/protocols.py +0 -52
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ruff_lsp_client.py +0 -109
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/ruff_runner.py +0 -44
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/utils.py +0 -959
- package/tools/vds-scripts/lsp_orchestrator/src/vds_lsp_orchestrator/workspace_indexer.py +0 -1037
- package/tools/vds-scripts/lsp_orchestrator/test_workspace_lsp.py +0 -6
- package/tools/vds-scripts/lsp_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/lsp_orchestrator/tests/conftest.py +0 -6
- package/tools/vds-scripts/lsp_orchestrator/tests/test_aggregator.py +0 -59
- package/tools/vds-scripts/lsp_orchestrator/tests/test_cli.py +0 -111
- package/tools/vds-scripts/lsp_orchestrator/tests/test_detect_tools_command.py +0 -186
- package/tools/vds-scripts/lsp_orchestrator/tests/test_formatter_linter_detection.py +0 -519
- package/tools/vds-scripts/lsp_orchestrator/tests/test_integration_phase9_10_11.py +0 -367
- package/tools/vds-scripts/lsp_orchestrator/tests/test_mypy_runner.py +0 -482
- package/tools/vds-scripts/lsp_orchestrator/tests/test_package_manager_detection.py +0 -399
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase10.py +0 -389
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase11.py +0 -327
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase12_integration.py +0 -634
- package/tools/vds-scripts/lsp_orchestrator/tests/test_phase9.py +0 -196
- package/tools/vds-scripts/lsp_orchestrator/tests/test_project_detector.py +0 -377
- package/tools/vds-scripts/lsp_orchestrator/tests/test_test_runner_detection.py +0 -549
- package/tools/vds-scripts/lsp_orchestrator/tests/test_type_checker_routing.py +0 -362
- package/tools/vds-scripts/lsp_orchestrator/tests/test_workspace_indexer.py +0 -144
- package/tools/vds-scripts/markdown_orchestrator/README.md +0 -72
- package/tools/vds-scripts/markdown_orchestrator/pyproject.toml +0 -39
- package/tools/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/markdown_orchestrator/src/vds_markdown_orchestrator/cli.py +0 -102
- package/tools/vds-scripts/multi_agent_orchestrator/Dockerfile +0 -65
- package/tools/vds-scripts/multi_agent_orchestrator/README.md +0 -306
- package/tools/vds-scripts/multi_agent_orchestrator/postman/README.md +0 -264
- package/tools/vds-scripts/multi_agent_orchestrator/postman/TEST_RESULTS_SUMMARY.md +0 -197
- package/tools/vds-scripts/multi_agent_orchestrator/postman/VDS-Multi-Agent-Orchestrator-API.postman_collection.json +0 -1010
- package/tools/vds-scripts/multi_agent_orchestrator/postman/environments/local-development.postman_environment.json +0 -55
- package/tools/vds-scripts/multi_agent_orchestrator/postman/test-results.json +0 -24146
- package/tools/vds-scripts/multi_agent_orchestrator/pyproject.toml +0 -63
- package/tools/vds-scripts/multi_agent_orchestrator/run_api.py +0 -9
- package/tools/vds-scripts/multi_agent_orchestrator/run_mock_api.py +0 -9
- package/tools/vds-scripts/multi_agent_orchestrator/simple_test.py +0 -53
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/__init__.py +0 -25
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/agent_pool.py +0 -433
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/__init__.py +0 -5
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/main.py +0 -722
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/api/mock_main.py +0 -812
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/change_log.py +0 -515
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/cli.py +0 -424
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/config.py +0 -220
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/conflict_resolver.py +0 -462
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/coordinator.py +0 -627
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/models.py +0 -389
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/progress_dashboard.py +0 -380
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/redis_client.py +0 -245
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/scheduler_subscriber.py +0 -272
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/task_manager.py +0 -536
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/task_tracking.py +0 -550
- package/tools/vds-scripts/multi_agent_orchestrator/src/vds_multi_agent_orchestrator/vds_ai_memory_client.py +0 -352
- package/tools/vds-scripts/multi_agent_orchestrator/test_complete_system.py +0 -149
- package/tools/vds-scripts/multi_agent_orchestrator/test_infrastructure_only.py +0 -194
- package/tools/vds-scripts/multi_agent_orchestrator/test_integration.py +0 -108
- package/tools/vds-scripts/multi_agent_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_agent_registration_credential_validator.py +0 -223
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_config.py +0 -210
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_models.py +0 -195
- package/tools/vds-scripts/multi_agent_orchestrator/tests/test_w9_agent_routes.py +0 -321
- package/tools/vds-scripts/openapi_orchestrator/README.md +0 -197
- package/tools/vds-scripts/openapi_orchestrator/pyproject.toml +0 -106
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/__init__.py +0 -29
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/cli.py +0 -345
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/full_validator.py +0 -183
- package/tools/vds-scripts/openapi_orchestrator/src/vds_openapi_orchestrator/spec_validator.py +0 -197
- package/tools/vds-scripts/openapi_orchestrator/tests/__init__.py +0 -1
- package/tools/vds-scripts/openapi_orchestrator/tests/test_cli.py +0 -234
- package/tools/vds-scripts/openapi_orchestrator/tests/test_full_validator.py +0 -203
- package/tools/vds-scripts/openapi_orchestrator/tests/test_spec_validator.py +0 -295
- package/tools/vds-scripts/pdf_orchestrator/.dockerignore +0 -93
- package/tools/vds-scripts/pdf_orchestrator/.env.example +0 -40
- package/tools/vds-scripts/pdf_orchestrator/.ruff_rules.py +0 -350
- package/tools/vds-scripts/pdf_orchestrator/.yamllint.yml +0 -43
- package/tools/vds-scripts/pdf_orchestrator/DEVELOPMENT_PLAN.md +0 -80
- package/tools/vds-scripts/pdf_orchestrator/Dockerfile +0 -87
- package/tools/vds-scripts/pdf_orchestrator/README.md +0 -608
- package/tools/vds-scripts/pdf_orchestrator/cli_verification_test/test.md +0 -6
- package/tools/vds-scripts/pdf_orchestrator/cli_verification_test/test.pdf +0 -0
- package/tools/vds-scripts/pdf_orchestrator/config/alertmanager.yml +0 -83
- package/tools/vds-scripts/pdf_orchestrator/config/prometheus.prod.yml +0 -98
- package/tools/vds-scripts/pdf_orchestrator/config/prometheus.yml +0 -40
- package/tools/vds-scripts/pdf_orchestrator/config/redis.conf +0 -78
- package/tools/vds-scripts/pdf_orchestrator/docs/COMPETITIVE_ANALYSIS_REPORT.md +0 -309
- package/tools/vds-scripts/pdf_orchestrator/docs/FEATURES_GUIDE.md +0 -518
- package/tools/vds-scripts/pdf_orchestrator/docs/MULTI_USER_DEPLOYMENT_GUIDE.md +0 -615
- package/tools/vds-scripts/pdf_orchestrator/docs/USER_GUIDE.md +0 -829
- package/tools/vds-scripts/pdf_orchestrator/pyproject.toml +0 -87
- package/tools/vds-scripts/pdf_orchestrator/pytest.ini +0 -71
- package/tools/vds-scripts/pdf_orchestrator/ruff.toml +0 -6
- package/tools/vds-scripts/pdf_orchestrator/scripts/debug_security_report.py +0 -59
- package/tools/vds-scripts/pdf_orchestrator/scripts/demo_library_selector.py +0 -109
- package/tools/vds-scripts/pdf_orchestrator/scripts/generate_project_stats.py +0 -52
- package/tools/vds-scripts/pdf_orchestrator/scripts/generate_styled_pdf.py +0 -95
- package/tools/vds-scripts/pdf_orchestrator/scripts/migrate_render_pdfs.py +0 -285
- package/tools/vds-scripts/pdf_orchestrator/scripts/setup_team.bat +0 -283
- package/tools/vds-scripts/pdf_orchestrator/scripts/setup_team.sh +0 -324
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/cli.py +0 -542
- package/tools/vds-scripts/pdf_orchestrator/src/vds_pdf_orchestrator/config.py +0 -33
- package/tools/vds-scripts/pdf_orchestrator/tests/README.md +0 -650
- package/tools/vds-scripts/pdf_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/pdf_orchestrator/tests/conftest.py +0 -520
- package/tools/vds-scripts/pdf_orchestrator/tests/requirements.txt +0 -51
- package/tools/vds-scripts/pdf_orchestrator/tests/run_tests.py +0 -659
- package/tools/vds-scripts/pdf_orchestrator/tests/test_config.py +0 -36
- package/tools/vds-scripts/progress_report_orchestrator/Dockerfile +0 -77
- package/tools/vds-scripts/progress_report_orchestrator/README.md +0 -39
- package/tools/vds-scripts/progress_report_orchestrator/alembic/env.py +0 -42
- package/tools/vds-scripts/progress_report_orchestrator/alembic/script.py.mako +0 -28
- package/tools/vds-scripts/progress_report_orchestrator/alembic/versions/0001_initial_progress_schema.py +0 -180
- package/tools/vds-scripts/progress_report_orchestrator/alembic.ini +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/pyproject.toml +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/endpoint_scanner.py +0 -238
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/git_activity.py +0 -159
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/hexagonal.py +0 -100
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/analyzers/test_scanner.py +0 -136
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/cli.py +0 -743
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/config.py +0 -50
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/db/__init__.py +0 -12
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/db/alembic_filters.py +0 -64
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/memory.py +0 -82
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/analysis.py +0 -84
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/report.py +0 -117
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/models/topology.py +0 -101
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/kg_parser.py +0 -252
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/parsers/uc_reader.py +0 -159
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/concurrency.py +0 -39
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/llm_eval.py +0 -570
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/report.py +0 -1256
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/structural.py +0 -384
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/pipeline/sync.py +0 -143
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/__init__.py +0 -5
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/engine.py +0 -105
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/recommendations/templates.py +0 -236
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/scheduler_subscriber.py +0 -238
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/README.md +0 -56
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/srs-architecture-reviewer/SKILL.md +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/skills/srs-endpoint-matcher/SKILL.md +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/state/__init__.py +0 -1
- package/tools/vds-scripts/progress_report_orchestrator/src/progress_report_orchestrator/state/schema.py +0 -625
- package/tools/vds-scripts/progress_report_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/.gitkeep +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/doc-dependencies.yaml +0 -79
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/fr-to-docs.yaml +0 -478
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/fr-to-services.yaml +0 -18
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/kg/registry.yaml +0 -346
- package/tools/vds-scripts/progress_report_orchestrator/tests/fixtures/phase3_baseline_standard.md +0 -564
- package/tools/vds-scripts/progress_report_orchestrator/tests/integration/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/integration/test_checkpoint.py +0 -276
- package/tools/vds-scripts/progress_report_orchestrator/tests/test_alembic_migrations.py +0 -265
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/__init__.py +0 -0
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_analyzers.py +0 -267
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_bounded_gather.py +0 -176
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_cli_phase_report.py +0 -119
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_delta.py +0 -169
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_error_handling.py +0 -150
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_gate_exit_codes.py +0 -230
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_git_activity.py +0 -215
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_kg_parser.py +0 -267
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_llm_autodetect.py +0 -183
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_llm_eval.py +0 -529
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_memory_integration.py +0 -151
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_migration_contract.py +0 -254
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_mode_rendering.py +0 -576
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_models.py +0 -251
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_progress_llm_config.py +0 -67
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_recommendations.py +0 -480
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_report_enhancements.py +0 -415
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_resume_reload.py +0 -343
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_trend_regression.py +0 -294
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_uc_reader.py +0 -169
- package/tools/vds-scripts/progress_report_orchestrator/tests/unit/test_valence_gap.py +0 -293
- package/tools/vds-scripts/project-cycle-report.json +0 -14
- package/tools/vds-scripts/project-dependency-graph.json +0 -11361
- package/tools/vds-scripts/project-topology.json +0 -99
- package/tools/vds-scripts/public_interface_boundary_orchestrator/pyproject.toml +0 -18
- package/tools/vds-scripts/public_interface_boundary_orchestrator/src/vds_public_interface_boundary_orchestrator/__init__.py +0 -0
- package/tools/vds-scripts/public_interface_boundary_orchestrator/src/vds_public_interface_boundary_orchestrator/cli.py +0 -232
- package/tools/vds-scripts/public_interface_boundary_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/public_interface_boundary_orchestrator/tests/test_cli.py +0 -108
- package/tools/vds-scripts/research_orchestrator/README.md +0 -68
- package/tools/vds-scripts/research_orchestrator/py.typed +0 -0
- package/tools/vds-scripts/research_orchestrator/pyproject.toml +0 -95
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/__init__.py +0 -3
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/_env.py +0 -11
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/cli.py +0 -335
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/config.py +0 -43
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/models.py +0 -89
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/evidence/scoring.py +0 -102
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/exceptions.py +0 -78
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/http_client.py +0 -160
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/logging.py +0 -49
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/output/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/output/formatters.py +0 -93
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/py.typed +0 -1
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/build.py +0 -156
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/report/format.py +0 -147
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/health.py +0 -66
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/health_graph.py +0 -52
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/registry.py +0 -127
- package/tools/vds-scripts/research_orchestrator/src/vds_research_orchestrator/tools/search.py +0 -230
- package/tools/vds-scripts/research_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/research_orchestrator/tests/conftest.py +0 -53
- package/tools/vds-scripts/research_orchestrator/tests/test_cli.py +0 -222
- package/tools/vds-scripts/research_orchestrator/tests/test_config.py +0 -23
- package/tools/vds-scripts/research_orchestrator/tests/test_exceptions.py +0 -62
- package/tools/vds-scripts/research_orchestrator/tests/test_formatters.py +0 -89
- package/tools/vds-scripts/research_orchestrator/tests/test_graph_integration.py +0 -149
- package/tools/vds-scripts/research_orchestrator/tests/test_http_client.py +0 -134
- package/tools/vds-scripts/research_orchestrator/tests/test_report_build.py +0 -128
- package/tools/vds-scripts/research_orchestrator/tests/test_report_format.py +0 -91
- package/tools/vds-scripts/research_orchestrator/tests/test_scoring.py +0 -95
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/__init__.py +0 -1
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_health.py +0 -139
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_registry.py +0 -135
- package/tools/vds-scripts/research_orchestrator/tests/vds_research_orchestrator/test_tools/test_search.py +0 -238
- package/tools/vds-scripts/run-history.json +0 -26
- package/tools/vds-scripts/schema_converter/README.md +0 -109
- package/tools/vds-scripts/schema_converter/pyproject.toml +0 -37
- package/tools/vds-scripts/schema_converter/src/vds_schema_converter/__init__.py +0 -3
- package/tools/vds-scripts/schema_converter/src/vds_schema_converter/cli.py +0 -50
- package/tools/vds-scripts/schema_converter/tests/__init__.py +0 -0
- package/tools/vds-scripts/schema_converter/tests/test_json_schema_generator.py +0 -115
- package/tools/vds-scripts/schema_converter/tests/test_mermaid_generator.py +0 -112
- package/tools/vds-scripts/schema_converter/tests/test_parser.py +0 -111
- package/tools/vds-scripts/schema_converter/tests/test_plantuml_generator.py +0 -112
- package/tools/vds-scripts/schema_converter/tests/test_plantuml_validator.py +0 -69
- package/tools/vds-scripts/schema_converter/tests/test_prisma_generator.py +0 -113
- package/tools/vds-scripts/schema_converter/tests/test_sql_generator.py +0 -138
- package/tools/vds-scripts/schema_converter/tests/test_typeorm_generator.py +0 -110
- package/tools/vds-scripts/schema_converter/tests/test_validators.py +0 -96
- package/tools/vds-scripts/spec_orchestrator/README.md +0 -13
- package/tools/vds-scripts/spec_orchestrator/pyproject.toml +0 -40
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/__init__.py +0 -5
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/cli.py +0 -162
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/core.py +0 -575
- package/tools/vds-scripts/spec_orchestrator/src/vds_spec_orchestrator/sync.py +0 -306
- package/tools/vds-scripts/spec_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/spec_orchestrator/tests/test_frontmatter_drift.py +0 -243
- package/tools/vds-scripts/spec_orchestrator/tests/test_sync.py +0 -342
- package/tools/vds-scripts/structure_orchestrator/README.md +0 -60
- package/tools/vds-scripts/structure_orchestrator/pyproject.toml +0 -103
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/__init__.py +0 -13
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/cli.py +0 -308
- package/tools/vds-scripts/structure_orchestrator/src/vds_structure_orchestrator/validator.py +0 -257
- package/tools/vds-scripts/structure_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/structure_orchestrator/tests/test_cli.py +0 -161
- package/tools/vds-scripts/structure_orchestrator/tests/test_helpers.py +0 -115
- package/tools/vds-scripts/structure_orchestrator/tests/test_validator.py +0 -104
- package/tools/vds-scripts/task_orchestrator/README.md +0 -50
- package/tools/vds-scripts/task_orchestrator/__init__.py +0 -18
- package/tools/vds-scripts/task_orchestrator/pyproject.toml +0 -43
- package/tools/vds-scripts/task_orchestrator/scripts/run_excel_sync.py +0 -36
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/__init__.py +0 -13
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/audit.py +0 -134
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/cli.py +0 -127
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/debug.py +0 -133
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/normalize.py +0 -113
- package/tools/vds-scripts/task_orchestrator/src/vds_task_orchestrator/refine.py +0 -201
- package/tools/vds-scripts/task_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/task_orchestrator/tests/test_task_orchestrator.py +0 -84
- package/tools/vds-scripts/temp_query_projects.py +0 -2
- package/tools/vds-scripts/test_small.md +0 -1
- package/tools/vds-scripts/text_utils_orchestrator/pyproject.toml +0 -20
- package/tools/vds-scripts/text_utils_orchestrator/src/vds_text_utils/__init__.py +0 -7
- package/tools/vds-scripts/text_utils_orchestrator/src/vds_text_utils/i18n.py +0 -143
- package/tools/vds-scripts/text_utils_orchestrator/tests/__init__.py +0 -0
- package/tools/vds-scripts/text_utils_orchestrator/tests/test_i18n.py +0 -53
- package/tools/vds-scripts/upgrade_major.py +0 -61
- package/tools/vds-scripts/upgrade_major_v2.py +0 -64
- package/tools/vds-scripts/verify_violations.py +0 -57
- package/tools/vds-scripts/workflow-summary.json +0 -325
- package/tools/vds-scripts/workflow-summary.md +0 -8
|
@@ -1,4130 +0,0 @@
|
|
|
1
|
-
"""Agentic investigation helpers extracted from CodeAnalysisAgent."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
import os
|
|
7
|
-
import re
|
|
8
|
-
import time
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from typing import TYPE_CHECKING, Any
|
|
11
|
-
from urllib.parse import urlparse
|
|
12
|
-
|
|
13
|
-
from vds_agent_core.config import LLMProtocolType
|
|
14
|
-
from vds_agent_core.skills.manager import SkillManager
|
|
15
|
-
|
|
16
|
-
from vds_audit_orchestrator.agents.code_analysis_prompts import CODE_ANALYSIS_SYSTEM_PROMPT
|
|
17
|
-
from vds_audit_orchestrator.agents.pydantic_base import AuditDeps, CodeFindings, _build_toolsets
|
|
18
|
-
from vds_audit_orchestrator.agents.tool_efficiency_guard import CadencePolicy, ToolEfficiencyGuard
|
|
19
|
-
from vds_audit_orchestrator.config import get_config
|
|
20
|
-
from vds_audit_orchestrator.engine.requirement_analysis import (
|
|
21
|
-
CodeSearchStrategyHint,
|
|
22
|
-
RequirementAnalysisResult,
|
|
23
|
-
derive_code_search_strategy,
|
|
24
|
-
)
|
|
25
|
-
from vds_audit_orchestrator.evidence.code_pack import CodeEvidencePack, CodePackBuilder
|
|
26
|
-
from vds_audit_orchestrator.skills.skill_routing import AuditSkillRouter
|
|
27
|
-
|
|
28
|
-
if TYPE_CHECKING:
|
|
29
|
-
from vds_audit_orchestrator.evidence.corpus import EvidenceCorpus
|
|
30
|
-
from vds_audit_orchestrator.models.evidence import EvidenceBundle
|
|
31
|
-
|
|
32
|
-
# =============================================================================
|
|
33
|
-
# Agentic Code Analysis System Prompt (Phase 41)
|
|
34
|
-
# =============================================================================
|
|
35
|
-
|
|
36
|
-
AGENTIC_CODE_ANALYSIS_SYSTEM_PROMPT = """You are a senior code quality analyst with access to repository exploration tools.
|
|
37
|
-
|
|
38
|
-
Operate in TOOL-FIRST mode:
|
|
39
|
-
- Do not assume provided snippets are complete.
|
|
40
|
-
- Explore the repository and evidence corpus to gather precise evidence.
|
|
41
|
-
- Prefer targeted retrieval over broad reads.
|
|
42
|
-
|
|
43
|
-
- **list_directory**: Browse repository structure to find relevant files.
|
|
44
|
-
- **read_file**: Read specific files or line ranges for deeper analysis.
|
|
45
|
-
- **grep_search**: Search for patterns, function names, or keywords across the repo.
|
|
46
|
-
- **rg_search**: Explicit ripgrep alias for exact/regex search.
|
|
47
|
-
- **ast_grep_search**: Structural AST search for syntax-aware matching.
|
|
48
|
-
- **list_evidence_documents**: List available Confluence/docs evidence in the corpus.
|
|
49
|
-
- **search_evidence**: Search docs evidence by keyword.
|
|
50
|
-
- **read_evidence_document**: Read a specific evidence document.
|
|
51
|
-
- **list_skills**: List available skills.
|
|
52
|
-
- **load_skill**: Load one skill when it is directly relevant.
|
|
53
|
-
- **read_skill_resource**: Read a specific skill resource when needed.
|
|
54
|
-
- **run_skill_script**: Execute a skill script only when it materially improves evidence quality.
|
|
55
|
-
|
|
56
|
-
## Evidence Scopes
|
|
57
|
-
|
|
58
|
-
The `search_code` and `read_code_file` tools accept a `scope` parameter to target specific evidence domains:
|
|
59
|
-
|
|
60
|
-
- **scope="code"** (default): Search/read source code files (*.py, *.java, *.kt, *.go, *.ts, etc.). Use for implementation logic, API routes, error handling, and business logic.
|
|
61
|
-
- **scope="config"**: Search/read configuration files (*.yaml, *.yml, *.json, *.toml, *.ini, *.properties, *.env, *.cfg, *.conf). Use for environment configs, deployment settings, feature flags, and infrastructure parameters.
|
|
62
|
-
- **scope="lib"**: Search/read shared library files across auxiliary repositories. Use for cross-cutting concerns, shared utilities, and common modules referenced by the main codebase.
|
|
63
|
-
- **scope="all"**: Search across all evidence domains without filtering. Use sparingly when the target domain is unknown.
|
|
64
|
-
|
|
65
|
-
When investigating configuration-related checklist items (e.g., environment separation, secret management, deployment configs), prefer `scope="config"`. When investigating shared libraries or cross-repo dependencies, use `scope="lib"`.
|
|
66
|
-
|
|
67
|
-
## Investigation Strategy
|
|
68
|
-
|
|
69
|
-
1. Start with lightweight repository orientation (one discovery call only: grep_search preferred, list_directory only when needed).
|
|
70
|
-
2. Retrieve only files/docs relevant to the checklist row and findings hypothesis.
|
|
71
|
-
3. Correlate code findings with documentation evidence when possible.
|
|
72
|
-
4. Keep tool usage focused - avoid exhaustive repo scans and avoid repeating identical list_directory calls on the same path.
|
|
73
|
-
- Do not perform path-by-path directory descent (e.g., repo -> src -> main -> java -> ...).
|
|
74
|
-
- After at most two list_directory calls, pivot to grep_search/rg_search/search_code_vector/read_file.
|
|
75
|
-
5. After gathering sufficient evidence, produce your final assessment.
|
|
76
|
-
6. Quality-first behavior: use focused tool calls; stop broad searching once two consecutive searches add no new evidence.
|
|
77
|
-
7. Call exactly one tool per turn; wait for its result before the next tool call.
|
|
78
|
-
8. Do not return a final answer before at least one repository tool call is completed.
|
|
79
|
-
|
|
80
|
-
## Evaluation Criteria
|
|
81
|
-
|
|
82
|
-
Same criteria as standard code analysis:
|
|
83
|
-
- Code Structure (25%): module organization, separation of concerns
|
|
84
|
-
- Error Handling (25%): try/except patterns, error propagation
|
|
85
|
-
- Naming Conventions (20%): PEP 8 compliance, clarity
|
|
86
|
-
- Security Practices (15%): input validation, credential handling
|
|
87
|
-
- Maintainability (15%): complexity, documentation, test coverage
|
|
88
|
-
|
|
89
|
-
## Output Requirements
|
|
90
|
-
|
|
91
|
-
Provide the same structured output as standard analysis:
|
|
92
|
-
1. Overall score (0-10) based on weighted criteria
|
|
93
|
-
2. Specific issues with file paths, severity, and recommendations
|
|
94
|
-
3. Detected patterns (both positive practices and anti-patterns)
|
|
95
|
-
4. Confidence level based on evidence quality
|
|
96
|
-
5. Clear reasoning for your assessment
|
|
97
|
-
|
|
98
|
-
Be specific and actionable. Only report real issues found in the evidence."""
|
|
99
|
-
|
|
100
|
-
AGENTIC_CODE_ANALYSIS_SYSTEM_PROMPT_OLLAMA_COMPACT = """You are a code analyst in strict TOOL-FIRST mode.
|
|
101
|
-
|
|
102
|
-
Rules:
|
|
103
|
-
- Start with grep_search or rg_search, then read_file on a concrete hit.
|
|
104
|
-
- grep_search/rg_search match FILE CONTENT (not filenames). Use code/security patterns (e.g. "class ", "@RestController", "password", "TODO") with include globs.
|
|
105
|
-
- Never use overly broad regex patterns such as "^", "$", ".", ".*", "\\s*", or empty pattern values.
|
|
106
|
-
- Prefer specific tokens/patterns and include globs that narrow file scope (e.g. "**/*.java", "**/*.yml").
|
|
107
|
-
- Use ast_grep_search when structural matching is needed.
|
|
108
|
-
- Use list_directory only if grep_search cannot locate relevant files.
|
|
109
|
-
- Never do path-by-path directory descent; maximum two list_directory calls before pivoting.
|
|
110
|
-
- Never call read_file on "." or any directory path; read only concrete files.
|
|
111
|
-
- Call one tool per turn and avoid repeating the same low-signal pattern.
|
|
112
|
-
- If vector retrieval is available, use search_evidence_vector (docs) or search_code_vector (code) for grounding.
|
|
113
|
-
- search_code and read_code_file accept scope: "code" (default, source files), "config" (configuration files), "lib" (shared libraries), "all" (unfiltered).
|
|
114
|
-
- Use scope="config" for environment/deployment/secret checks; scope="lib" for shared library checks.
|
|
115
|
-
- Ground each issue in concrete evidence and return only real, verifiable findings.
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
PATH_RESOLUTION_RECOVERABLE_ERRORS = (OSError, RuntimeError)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def _render_phase115_strategy_guidance(strategy_hint: CodeSearchStrategyHint) -> str:
|
|
122
|
-
tool_text = ", ".join(strategy_hint.preferred_tools) or "search_code, read_code_file"
|
|
123
|
-
patterns_text = ", ".join(strategy_hint.file_pattern_hints) or "no specific file-pattern hints"
|
|
124
|
-
lines = ["\n## [Search strategy guidance] (Phase 115)"]
|
|
125
|
-
lines.append(f"- Strategy: {strategy_hint.strategy}")
|
|
126
|
-
lines.append(f"- Preferred tools: {tool_text}")
|
|
127
|
-
if strategy_hint.scope_hint:
|
|
128
|
-
lines.append(f"- Scope hint: {strategy_hint.scope_hint}")
|
|
129
|
-
if strategy_hint.query_variant:
|
|
130
|
-
lines.append(f"- Query variant: {strategy_hint.query_variant}")
|
|
131
|
-
if strategy_hint.requirement_type_tag:
|
|
132
|
-
lines.append(f"- Requirement type: {strategy_hint.requirement_type_tag}")
|
|
133
|
-
if strategy_hint.file_pattern_hints:
|
|
134
|
-
lines.append(f"- File pattern hints: {patterns_text}")
|
|
135
|
-
|
|
136
|
-
if strategy_hint.strategy == "targeted_file":
|
|
137
|
-
lines.append("- Guidance: search for specific artifacts first, then confirm with focused reads.")
|
|
138
|
-
elif strategy_hint.strategy == "structural_pattern":
|
|
139
|
-
lines.append(
|
|
140
|
-
"- Guidance: use structural/vector discovery first, then confirm architecture boundaries with concrete code reads."
|
|
141
|
-
)
|
|
142
|
-
elif strategy_hint.strategy == "multi_pass":
|
|
143
|
-
lines.append(
|
|
144
|
-
"- Guidance: run an initial domain-specific pass, then broaden scope only if the first pass is insufficient."
|
|
145
|
-
)
|
|
146
|
-
elif strategy_hint.strategy == "vector_semantic":
|
|
147
|
-
lines.append(
|
|
148
|
-
"- Guidance: use search_code_vector as the primary discovery tool when available, then pivot to concrete reads."
|
|
149
|
-
)
|
|
150
|
-
else:
|
|
151
|
-
lines.append("- Guidance: use semantic grep first, then read the most relevant concrete files.")
|
|
152
|
-
|
|
153
|
-
if strategy_hint.escalation_scope:
|
|
154
|
-
lines.append(f"- Escalation scope: {strategy_hint.escalation_scope}")
|
|
155
|
-
return "\n".join(lines) + "\n"
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
AGENTIC_SETUP_RECOVERABLE_ERRORS = (
|
|
159
|
-
AttributeError,
|
|
160
|
-
ImportError,
|
|
161
|
-
OSError,
|
|
162
|
-
RuntimeError,
|
|
163
|
-
TypeError,
|
|
164
|
-
ValueError,
|
|
165
|
-
)
|
|
166
|
-
CODE_PACK_RECOVERABLE_ERRORS = (OSError, RuntimeError, TypeError, ValueError)
|
|
167
|
-
STRUCTURED_OUTPUT_RECOVERABLE_ERRORS = (TypeError, ValueError)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class AgenticInvestigator:
|
|
171
|
-
"""Mixin containing the AGENTIC investigation flow for code analysis."""
|
|
172
|
-
|
|
173
|
-
_SKILL_TOOL_NAMES: frozenset[str] = frozenset(
|
|
174
|
-
{
|
|
175
|
-
"list_skills",
|
|
176
|
-
"load_skill",
|
|
177
|
-
"read_skill_resource",
|
|
178
|
-
"run_skill_script",
|
|
179
|
-
}
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
@staticmethod
|
|
183
|
-
def _get_runtime_config():
|
|
184
|
-
"""Return runtime config for agentic setup."""
|
|
185
|
-
return get_config()
|
|
186
|
-
|
|
187
|
-
@staticmethod
|
|
188
|
-
def _build_runtime_toolsets(llm_config: Any):
|
|
189
|
-
"""Build runtime toolsets from LLM config."""
|
|
190
|
-
return _build_toolsets(llm_config)
|
|
191
|
-
|
|
192
|
-
@staticmethod
|
|
193
|
-
def _runtime_protocol_type():
|
|
194
|
-
"""Return protocol enum used by agentic runtime routing."""
|
|
195
|
-
return LLMProtocolType
|
|
196
|
-
|
|
197
|
-
@staticmethod
|
|
198
|
-
def _parse_env_bool(name: str) -> bool | None:
|
|
199
|
-
"""Parse optional boolean env flag."""
|
|
200
|
-
raw = os.getenv(name)
|
|
201
|
-
if raw is None:
|
|
202
|
-
return None
|
|
203
|
-
value = raw.strip().lower()
|
|
204
|
-
if value in {"1", "true", "yes", "on"}:
|
|
205
|
-
return True
|
|
206
|
-
if value in {"0", "false", "no", "off"}:
|
|
207
|
-
return False
|
|
208
|
-
return None
|
|
209
|
-
|
|
210
|
-
def _runtime_protocol_value(self) -> str:
|
|
211
|
-
"""Resolve protocol value used by the active runtime model endpoint."""
|
|
212
|
-
return str(self.settings.protocol.value)
|
|
213
|
-
|
|
214
|
-
def _uses_local_openai_protocol(self) -> bool:
|
|
215
|
-
"""Return True when runtime uses OpenAI protocol against a local endpoint."""
|
|
216
|
-
if self._runtime_protocol_value() != "openai":
|
|
217
|
-
return False
|
|
218
|
-
endpoint_value = getattr(self.settings, "base_url", None)
|
|
219
|
-
endpoint = endpoint_value.strip() if isinstance(endpoint_value, str) else ""
|
|
220
|
-
if not endpoint:
|
|
221
|
-
endpoint = "http://127.0.0.1:11434"
|
|
222
|
-
if not endpoint:
|
|
223
|
-
return False
|
|
224
|
-
parsed = urlparse(endpoint)
|
|
225
|
-
host = (parsed.hostname or "").lower()
|
|
226
|
-
return host in {"localhost", "127.0.0.1", "0.0.0.0", "::1"}
|
|
227
|
-
|
|
228
|
-
def _is_agentic_skills_toolset_enabled(self, llm_config: Any) -> bool:
|
|
229
|
-
"""Resolve effective skill-toolset flag for agentic code analysis."""
|
|
230
|
-
code_override = self._parse_env_bool("VDS_AUDIT_AGENTIC_CODE_ENABLE_SKILLS_TOOLSET")
|
|
231
|
-
if code_override is not None:
|
|
232
|
-
return code_override
|
|
233
|
-
generic_override = self._parse_env_bool("VDS_AUDIT_AGENTIC_ENABLE_SKILLS_TOOLSET")
|
|
234
|
-
if generic_override is not None:
|
|
235
|
-
return generic_override
|
|
236
|
-
return bool(getattr(llm_config, "skills_toolset_enabled", False))
|
|
237
|
-
|
|
238
|
-
@staticmethod
|
|
239
|
-
def _has_default_skills_toolset_available() -> bool:
|
|
240
|
-
try:
|
|
241
|
-
from vds_audit_orchestrator.agents.toolsets.skills_toolset import DEFAULT_AUDIT_SKILLS
|
|
242
|
-
except Exception:
|
|
243
|
-
return False
|
|
244
|
-
return bool(list(DEFAULT_AUDIT_SKILLS or []))
|
|
245
|
-
|
|
246
|
-
@classmethod
|
|
247
|
-
def _requires_requirement_driven_skill_toolset(cls, state_context: dict[str, Any] | None) -> bool:
|
|
248
|
-
interpretation = cls._extract_requirement_interpretation_from_state_context(state_context)
|
|
249
|
-
objectives = interpretation.get("skill_objectives") if isinstance(interpretation, dict) else []
|
|
250
|
-
normalized_objectives = {
|
|
251
|
-
str(item).strip() for item in (objectives if isinstance(objectives, list) else []) if str(item).strip()
|
|
252
|
-
}
|
|
253
|
-
return bool(
|
|
254
|
-
normalized_objectives
|
|
255
|
-
& {
|
|
256
|
-
"discover_app_config",
|
|
257
|
-
"resolve_environment_specific_config",
|
|
258
|
-
"analyze_datasource_isolation",
|
|
259
|
-
"compare_cross_service_config_separation",
|
|
260
|
-
}
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
def _resolve_agentic_runtime(self) -> dict[str, Any] | None:
|
|
264
|
-
"""Resolve effective runtime settings for bounded AGENTIC execution.
|
|
265
|
-
|
|
266
|
-
Returns None when AGENTIC runtime cannot be initialized.
|
|
267
|
-
"""
|
|
268
|
-
try:
|
|
269
|
-
config = self._get_runtime_config()
|
|
270
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
271
|
-
self.logger.warning(
|
|
272
|
-
"agentic_config_load_failed",
|
|
273
|
-
error=str(exc),
|
|
274
|
-
error_type=type(exc).__name__,
|
|
275
|
-
handler="_resolve_agentic_runtime",
|
|
276
|
-
)
|
|
277
|
-
return None
|
|
278
|
-
|
|
279
|
-
agentic_cfg = config.agentic
|
|
280
|
-
mode_value = getattr(self, "agentic_mode", None)
|
|
281
|
-
if mode_value is None:
|
|
282
|
-
mode_value = getattr(self, "_agentic_mode", "")
|
|
283
|
-
forced_agentic_mode = str(mode_value).strip().lower() == "on"
|
|
284
|
-
if not agentic_cfg.enabled:
|
|
285
|
-
if not forced_agentic_mode:
|
|
286
|
-
self.logger.info("agentic_disabled_in_config")
|
|
287
|
-
return None
|
|
288
|
-
self.logger.warning("agentic_force_enabled_by_mode_override")
|
|
289
|
-
|
|
290
|
-
safe_extensions = tuple(ext for ext in agentic_cfg.safe_extensions if isinstance(ext, str) and ext)
|
|
291
|
-
if not safe_extensions:
|
|
292
|
-
self.logger.warning("agentic_safe_extensions_empty")
|
|
293
|
-
return None
|
|
294
|
-
|
|
295
|
-
max_turns = int(agentic_cfg.max_turns)
|
|
296
|
-
max_tool_calls = int(agentic_cfg.max_tool_calls)
|
|
297
|
-
strict_cap_max_turns = int(getattr(agentic_cfg, "strict_cap_max_turns", 10))
|
|
298
|
-
strict_cap_max_tool_calls = int(getattr(agentic_cfg, "strict_cap_max_tool_calls", 24))
|
|
299
|
-
llm_skills_toolset_enabled = self._is_agentic_skills_toolset_enabled(config.llm)
|
|
300
|
-
raw_state_context = getattr(self, "_state_context", None)
|
|
301
|
-
state_context = dict(raw_state_context) if isinstance(raw_state_context, dict) else {}
|
|
302
|
-
if (
|
|
303
|
-
not llm_skills_toolset_enabled
|
|
304
|
-
and self._requires_requirement_driven_skill_toolset(state_context)
|
|
305
|
-
and self._has_default_skills_toolset_available()
|
|
306
|
-
):
|
|
307
|
-
llm_skills_toolset_enabled = True
|
|
308
|
-
self.logger.info(
|
|
309
|
-
"agentic_skills_toolset_auto_enabled_for_requirement",
|
|
310
|
-
reason="requirement_driven_app_config_skill",
|
|
311
|
-
)
|
|
312
|
-
compact_max_turns_override: int | None = None
|
|
313
|
-
compact_max_tool_calls_override: int | None = None
|
|
314
|
-
compact_default_max_turns = 8
|
|
315
|
-
compact_default_max_tool_calls = 20
|
|
316
|
-
raw_compact_turns = str(os.getenv("VDS_AUDIT_AGENTIC_COMPACT_MAX_TURNS", "")).strip()
|
|
317
|
-
raw_compact_tools = str(os.getenv("VDS_AUDIT_AGENTIC_COMPACT_MAX_TOOL_CALLS", "")).strip()
|
|
318
|
-
raw_compact_default_turns = str(
|
|
319
|
-
os.getenv("VDS_AUDIT_AGENTIC_COMPACT_DEFAULT_MAX_TURNS", str(compact_default_max_turns))
|
|
320
|
-
).strip()
|
|
321
|
-
raw_compact_default_tools = str(
|
|
322
|
-
os.getenv("VDS_AUDIT_AGENTIC_COMPACT_DEFAULT_MAX_TOOL_CALLS", str(compact_default_max_tool_calls))
|
|
323
|
-
).strip()
|
|
324
|
-
if raw_compact_turns.isdigit():
|
|
325
|
-
parsed_turns = int(raw_compact_turns)
|
|
326
|
-
if parsed_turns > 0:
|
|
327
|
-
compact_max_turns_override = parsed_turns
|
|
328
|
-
if raw_compact_tools.isdigit():
|
|
329
|
-
parsed_tools = int(raw_compact_tools)
|
|
330
|
-
if parsed_tools > 0:
|
|
331
|
-
compact_max_tool_calls_override = parsed_tools
|
|
332
|
-
if raw_compact_default_turns.isdigit():
|
|
333
|
-
parsed_default_turns = int(raw_compact_default_turns)
|
|
334
|
-
if parsed_default_turns > 0:
|
|
335
|
-
compact_default_max_turns = parsed_default_turns
|
|
336
|
-
if raw_compact_default_tools.isdigit():
|
|
337
|
-
parsed_default_tools = int(raw_compact_default_tools)
|
|
338
|
-
if parsed_default_tools > 0:
|
|
339
|
-
compact_default_max_tool_calls = parsed_default_tools
|
|
340
|
-
if forced_agentic_mode and not agentic_cfg.enabled:
|
|
341
|
-
# Guardrail for forced explicit mode: avoid low default caps causing
|
|
342
|
-
# immediate request-limit exits before meaningful tool exploration.
|
|
343
|
-
max_turns = max(max_turns, 12)
|
|
344
|
-
max_tool_calls = max(max_tool_calls, 40)
|
|
345
|
-
# Strict fail-fast mode: preserve tool-first quality, but cap runaway loops.
|
|
346
|
-
# This keeps analysis focused and forces earlier synthesis/guard handling.
|
|
347
|
-
if bool(agentic_cfg.strict_no_fallback):
|
|
348
|
-
if self._uses_local_openai_protocol():
|
|
349
|
-
max_turns = min(max_turns, strict_cap_max_turns)
|
|
350
|
-
max_tool_calls = min(max_tool_calls, strict_cap_max_tool_calls)
|
|
351
|
-
if compact_max_turns_override is not None:
|
|
352
|
-
max_turns = min(max_turns, compact_max_turns_override)
|
|
353
|
-
else:
|
|
354
|
-
max_turns = min(max_turns, compact_default_max_turns)
|
|
355
|
-
if compact_max_tool_calls_override is not None:
|
|
356
|
-
max_tool_calls = min(max_tool_calls, compact_max_tool_calls_override)
|
|
357
|
-
else:
|
|
358
|
-
max_tool_calls = min(max_tool_calls, compact_default_max_tool_calls)
|
|
359
|
-
else:
|
|
360
|
-
max_turns = min(max_turns, 12)
|
|
361
|
-
max_tool_calls = min(max_tool_calls, 24)
|
|
362
|
-
|
|
363
|
-
return {
|
|
364
|
-
"enabled": True,
|
|
365
|
-
"max_turns": max_turns,
|
|
366
|
-
"max_tool_calls": max_tool_calls,
|
|
367
|
-
"tool_timeout_sec": int(agentic_cfg.tool_timeout_sec),
|
|
368
|
-
"safe_extensions": safe_extensions,
|
|
369
|
-
"max_read_bytes": int(agentic_cfg.max_read_bytes),
|
|
370
|
-
"max_read_lines": int(agentic_cfg.max_read_lines),
|
|
371
|
-
"strict_no_fallback": bool(agentic_cfg.strict_no_fallback),
|
|
372
|
-
"strict_cap_max_turns": strict_cap_max_turns,
|
|
373
|
-
"strict_cap_max_tool_calls": strict_cap_max_tool_calls,
|
|
374
|
-
"compact_max_turns_override": compact_max_turns_override,
|
|
375
|
-
"compact_max_tool_calls_override": compact_max_tool_calls_override,
|
|
376
|
-
"compact_default_max_turns": compact_default_max_turns,
|
|
377
|
-
"compact_default_max_tool_calls": compact_default_max_tool_calls,
|
|
378
|
-
"local_openai_synthesis_max_turns": int(getattr(agentic_cfg, "local_openai_synthesis_max_turns", 4)),
|
|
379
|
-
"local_openai_synthesis_max_tool_calls": int(
|
|
380
|
-
getattr(agentic_cfg, "local_openai_synthesis_max_tool_calls", 2)
|
|
381
|
-
),
|
|
382
|
-
"local_openai_hard_synthesis_max_turns": int(
|
|
383
|
-
getattr(agentic_cfg, "local_openai_hard_synthesis_max_turns", 2)
|
|
384
|
-
),
|
|
385
|
-
"local_openai_hard_synthesis_max_tool_calls": int(
|
|
386
|
-
getattr(agentic_cfg, "local_openai_hard_synthesis_max_tool_calls", 0)
|
|
387
|
-
),
|
|
388
|
-
"synthesis_max_turns": int(getattr(agentic_cfg, "synthesis_max_turns", 4)),
|
|
389
|
-
"synthesis_max_tool_calls": int(getattr(agentic_cfg, "synthesis_max_tool_calls", 2)),
|
|
390
|
-
"hard_synthesis_max_turns": int(getattr(agentic_cfg, "hard_synthesis_max_turns", 2)),
|
|
391
|
-
"hard_synthesis_max_tool_calls": int(getattr(agentic_cfg, "hard_synthesis_max_tool_calls", 0)),
|
|
392
|
-
"skills_toolset_enabled": llm_skills_toolset_enabled,
|
|
393
|
-
"non_progress_policy": agentic_cfg.non_progress_policy.model_dump(),
|
|
394
|
-
"tool_allowlist": list(agentic_cfg.tool_allowlists.get("code", [])),
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
@staticmethod
|
|
398
|
-
def _extract_tool_usage(telemetry: dict[str, Any] | None) -> tuple[int, int]:
|
|
399
|
-
if not isinstance(telemetry, dict):
|
|
400
|
-
return (0, 0)
|
|
401
|
-
usage = telemetry.get("usage")
|
|
402
|
-
usage_tool_calls = int(usage.get("tool_calls", 0) or 0) if isinstance(usage, dict) else 0
|
|
403
|
-
event_tool_calls = int(telemetry.get("event_tool_calls_completed", telemetry.get("event_tool_calls", 0)) or 0)
|
|
404
|
-
event_skill_tool_calls = int(telemetry.get("event_skill_tool_calls", 0) or 0)
|
|
405
|
-
tool_calls = max(usage_tool_calls, event_tool_calls)
|
|
406
|
-
skill_calls = event_skill_tool_calls
|
|
407
|
-
return (tool_calls, skill_calls)
|
|
408
|
-
|
|
409
|
-
@staticmethod
|
|
410
|
-
def _extract_docs_tool_usage(telemetry: dict[str, Any] | None) -> int:
|
|
411
|
-
"""Return count of evidence-doc tool calls observed in telemetry."""
|
|
412
|
-
if not isinstance(telemetry, dict):
|
|
413
|
-
return 0
|
|
414
|
-
by_name = telemetry.get("event_tool_count_by_name")
|
|
415
|
-
if not isinstance(by_name, dict):
|
|
416
|
-
return 0
|
|
417
|
-
return sum(
|
|
418
|
-
int(by_name.get(name, 0) or 0)
|
|
419
|
-
for name in ("list_evidence_documents", "search_evidence", "read_evidence_document")
|
|
420
|
-
)
|
|
421
|
-
|
|
422
|
-
@staticmethod
|
|
423
|
-
def _extract_docs_read_tool_usage(telemetry: dict[str, Any] | None) -> int:
|
|
424
|
-
"""Return count of concrete evidence-doc reads (not just discovery/search)."""
|
|
425
|
-
if not isinstance(telemetry, dict):
|
|
426
|
-
return 0
|
|
427
|
-
by_name = telemetry.get("event_tool_count_by_name")
|
|
428
|
-
if not isinstance(by_name, dict):
|
|
429
|
-
return 0
|
|
430
|
-
return int(by_name.get("read_evidence_document", 0) or 0)
|
|
431
|
-
|
|
432
|
-
@staticmethod
|
|
433
|
-
def _extract_vector_docs_tool_usage(telemetry: dict[str, Any] | None) -> int:
|
|
434
|
-
"""Return count of vector-evidence tool calls observed in telemetry."""
|
|
435
|
-
if not isinstance(telemetry, dict):
|
|
436
|
-
return 0
|
|
437
|
-
by_name = telemetry.get("event_tool_count_by_name")
|
|
438
|
-
if not isinstance(by_name, dict):
|
|
439
|
-
return 0
|
|
440
|
-
return int(by_name.get("search_evidence_vector", 0) or 0) + int(by_name.get("search_code_vector", 0) or 0)
|
|
441
|
-
|
|
442
|
-
@staticmethod
|
|
443
|
-
def _extract_code_read_tool_usage(telemetry: dict[str, Any] | None) -> int:
|
|
444
|
-
"""Return count of concrete code-reading/navigation tool calls from telemetry."""
|
|
445
|
-
if not isinstance(telemetry, dict):
|
|
446
|
-
return 0
|
|
447
|
-
by_name = telemetry.get("event_tool_count_by_name")
|
|
448
|
-
if not isinstance(by_name, dict):
|
|
449
|
-
return 0
|
|
450
|
-
return sum(
|
|
451
|
-
int(by_name.get(name, 0) or 0)
|
|
452
|
-
for name in ("read_file", "get_definition", "find_references", "workspace_symbol")
|
|
453
|
-
)
|
|
454
|
-
|
|
455
|
-
@staticmethod
|
|
456
|
-
def _extract_skill_effective_usage(telemetry: dict[str, Any] | None) -> int:
|
|
457
|
-
"""Return count of effective skill tool calls (execution-class) from telemetry."""
|
|
458
|
-
if not isinstance(telemetry, dict):
|
|
459
|
-
return 0
|
|
460
|
-
if "event_skill_execution_effective_tool_calls" in telemetry:
|
|
461
|
-
return int(telemetry.get("event_skill_execution_effective_tool_calls", 0) or 0)
|
|
462
|
-
if "event_skill_effective_tool_calls" in telemetry:
|
|
463
|
-
return int(telemetry.get("event_skill_effective_tool_calls", 0) or 0)
|
|
464
|
-
usage = telemetry.get("event_skill_tool_usage")
|
|
465
|
-
if isinstance(usage, list):
|
|
466
|
-
effective_execution = 0
|
|
467
|
-
for entry in usage:
|
|
468
|
-
if not isinstance(entry, dict):
|
|
469
|
-
continue
|
|
470
|
-
tool_name = str(entry.get("tool") or "").strip()
|
|
471
|
-
if tool_name not in {"read_skill_resource", "run_skill_script"}:
|
|
472
|
-
continue
|
|
473
|
-
if bool(entry.get("effective")):
|
|
474
|
-
effective_execution += 1
|
|
475
|
-
if effective_execution > 0:
|
|
476
|
-
return effective_execution
|
|
477
|
-
by_name = telemetry.get("event_skill_tool_count_by_name")
|
|
478
|
-
if isinstance(by_name, dict):
|
|
479
|
-
return int(by_name.get("read_skill_resource", 0) or 0) + int(by_name.get("run_skill_script", 0) or 0)
|
|
480
|
-
if "event_skill_execution_tool_calls" in telemetry:
|
|
481
|
-
return int(telemetry.get("event_skill_execution_tool_calls", 0) or 0)
|
|
482
|
-
return 0
|
|
483
|
-
|
|
484
|
-
@staticmethod
|
|
485
|
-
def _merge_retry_telemetry(aggregate: dict[str, Any], attempt: dict[str, Any] | None) -> dict[str, Any]:
|
|
486
|
-
"""Merge one attempt telemetry snapshot into aggregate counters."""
|
|
487
|
-
if not isinstance(attempt, dict):
|
|
488
|
-
return aggregate
|
|
489
|
-
observed_keys = {
|
|
490
|
-
"event_tool_calls",
|
|
491
|
-
"event_tool_calls_started",
|
|
492
|
-
"event_tool_calls_completed",
|
|
493
|
-
"event_tool_effective_calls",
|
|
494
|
-
"event_skill_tool_calls",
|
|
495
|
-
"event_skill_discovery_tool_calls",
|
|
496
|
-
"event_skill_bootstrap_tool_calls",
|
|
497
|
-
"event_skill_execution_tool_calls",
|
|
498
|
-
"event_skill_execution_effective_tool_calls",
|
|
499
|
-
"event_skill_effective_tool_calls",
|
|
500
|
-
"event_turn_effectiveness",
|
|
501
|
-
"event_tool_names",
|
|
502
|
-
"event_tool_signatures",
|
|
503
|
-
"event_tool_count_by_name",
|
|
504
|
-
"event_tool_effective_count_by_name",
|
|
505
|
-
"event_skill_tool_count_by_name",
|
|
506
|
-
"event_tool_latencies_ms",
|
|
507
|
-
"usage",
|
|
508
|
-
"skill_policy_diagnostics",
|
|
509
|
-
}
|
|
510
|
-
if not any(key in attempt for key in observed_keys):
|
|
511
|
-
return aggregate
|
|
512
|
-
|
|
513
|
-
numeric_keys = (
|
|
514
|
-
"event_tool_calls",
|
|
515
|
-
"event_tool_calls_started",
|
|
516
|
-
"event_tool_calls_completed",
|
|
517
|
-
"event_tool_effective_calls",
|
|
518
|
-
"event_skill_tool_calls",
|
|
519
|
-
"event_skill_discovery_tool_calls",
|
|
520
|
-
"event_skill_bootstrap_tool_calls",
|
|
521
|
-
"event_skill_execution_tool_calls",
|
|
522
|
-
"event_skill_execution_effective_tool_calls",
|
|
523
|
-
"event_skill_effective_tool_calls",
|
|
524
|
-
)
|
|
525
|
-
for key in numeric_keys:
|
|
526
|
-
if key not in attempt and key not in aggregate:
|
|
527
|
-
continue
|
|
528
|
-
aggregate[key] = int(aggregate.get(key, 0) or 0) + int(attempt.get(key, 0) or 0)
|
|
529
|
-
|
|
530
|
-
tool_names = aggregate.get("event_tool_names")
|
|
531
|
-
if not isinstance(tool_names, list):
|
|
532
|
-
tool_names = []
|
|
533
|
-
for name in attempt.get("event_tool_names", []):
|
|
534
|
-
if isinstance(name, str) and name and name not in tool_names:
|
|
535
|
-
tool_names.append(name)
|
|
536
|
-
aggregate["event_tool_names"] = tool_names
|
|
537
|
-
|
|
538
|
-
tool_signatures = aggregate.get("event_tool_signatures")
|
|
539
|
-
if not isinstance(tool_signatures, list):
|
|
540
|
-
tool_signatures = []
|
|
541
|
-
if isinstance(attempt.get("event_tool_signatures"), list):
|
|
542
|
-
tool_signatures.extend(str(sig) for sig in attempt["event_tool_signatures"])
|
|
543
|
-
aggregate["event_tool_signatures"] = tool_signatures
|
|
544
|
-
|
|
545
|
-
for map_key in (
|
|
546
|
-
"event_tool_count_by_name",
|
|
547
|
-
"event_tool_effective_count_by_name",
|
|
548
|
-
"event_skill_tool_count_by_name",
|
|
549
|
-
):
|
|
550
|
-
merged = aggregate.get(map_key)
|
|
551
|
-
if not isinstance(merged, dict):
|
|
552
|
-
merged = {}
|
|
553
|
-
source = attempt.get(map_key)
|
|
554
|
-
if isinstance(source, dict):
|
|
555
|
-
for name, count in source.items():
|
|
556
|
-
key = str(name)
|
|
557
|
-
merged[key] = int(merged.get(key, 0) or 0) + int(count or 0)
|
|
558
|
-
aggregate[map_key] = merged
|
|
559
|
-
|
|
560
|
-
turn_effectiveness = aggregate.get("event_turn_effectiveness")
|
|
561
|
-
if not isinstance(turn_effectiveness, dict):
|
|
562
|
-
turn_effectiveness = {}
|
|
563
|
-
next_turn_index = max(
|
|
564
|
-
(int(str(turn_key)) for turn_key in turn_effectiveness if str(turn_key).strip().isdigit()),
|
|
565
|
-
default=0,
|
|
566
|
-
)
|
|
567
|
-
attempt_turn_effectiveness = attempt.get("event_turn_effectiveness")
|
|
568
|
-
if isinstance(attempt_turn_effectiveness, dict):
|
|
569
|
-
for _, payload in sorted(
|
|
570
|
-
(
|
|
571
|
-
(int(str(turn_key)), value)
|
|
572
|
-
for turn_key, value in attempt_turn_effectiveness.items()
|
|
573
|
-
if str(turn_key).strip().isdigit() and isinstance(value, dict)
|
|
574
|
-
),
|
|
575
|
-
key=lambda item: item[0],
|
|
576
|
-
):
|
|
577
|
-
next_turn_index += 1
|
|
578
|
-
turn_effectiveness[str(next_turn_index)] = dict(payload)
|
|
579
|
-
if turn_effectiveness:
|
|
580
|
-
aggregate["event_turn_effectiveness"] = turn_effectiveness
|
|
581
|
-
aggregate["event_turn_index"] = next_turn_index
|
|
582
|
-
|
|
583
|
-
latencies = aggregate.get("event_tool_latencies_ms")
|
|
584
|
-
if not isinstance(latencies, list):
|
|
585
|
-
latencies = []
|
|
586
|
-
if isinstance(attempt.get("event_tool_latencies_ms"), list):
|
|
587
|
-
latencies.extend(
|
|
588
|
-
int(value) for value in attempt["event_tool_latencies_ms"] if isinstance(value, (int, float))
|
|
589
|
-
)
|
|
590
|
-
aggregate["event_tool_latencies_ms"] = latencies
|
|
591
|
-
|
|
592
|
-
usage = aggregate.get("usage")
|
|
593
|
-
if not isinstance(usage, dict):
|
|
594
|
-
usage = {}
|
|
595
|
-
attempt_usage = attempt.get("usage")
|
|
596
|
-
if isinstance(attempt_usage, dict):
|
|
597
|
-
usage["requests"] = int(usage.get("requests", 0) or 0) + int(attempt_usage.get("requests", 0) or 0)
|
|
598
|
-
usage["input_tokens"] = int(usage.get("input_tokens", 0) or 0) + int(
|
|
599
|
-
attempt_usage.get("input_tokens", 0) or 0
|
|
600
|
-
)
|
|
601
|
-
usage["output_tokens"] = int(usage.get("output_tokens", 0) or 0) + int(
|
|
602
|
-
attempt_usage.get("output_tokens", 0) or 0
|
|
603
|
-
)
|
|
604
|
-
usage["tool_calls"] = int(usage.get("tool_calls", 0) or 0) + int(attempt_usage.get("tool_calls", 0) or 0)
|
|
605
|
-
aggregate["usage"] = usage
|
|
606
|
-
skill_policy_diagnostics = attempt.get("skill_policy_diagnostics")
|
|
607
|
-
if isinstance(skill_policy_diagnostics, dict):
|
|
608
|
-
aggregate["skill_policy_diagnostics"] = dict(skill_policy_diagnostics)
|
|
609
|
-
aggregate["retry_attempts"] = int(aggregate.get("retry_attempts", 0) or 0) + 1
|
|
610
|
-
return aggregate
|
|
611
|
-
|
|
612
|
-
@staticmethod
|
|
613
|
-
def _parse_skill_name_from_error(error: str) -> str | None:
|
|
614
|
-
return SkillManager.parse_skill_name_from_error(error)
|
|
615
|
-
|
|
616
|
-
@staticmethod
|
|
617
|
-
def _drop_skill_from_toolsets(toolsets: list[Any], skill_name: str) -> tuple[list[Any], int]:
|
|
618
|
-
return SkillManager.drop_skill_from_toolsets(toolsets, skill_name)
|
|
619
|
-
|
|
620
|
-
def _prevalidate_skill_toolsets(self, toolsets: list[Any]) -> list[Any]:
|
|
621
|
-
import vds_audit_orchestrator.agents.toolsets.skills_toolset as _st
|
|
622
|
-
|
|
623
|
-
class _HashValidator:
|
|
624
|
-
def validate(self, item: Any, *, raise_on_mismatch: bool = False) -> bool:
|
|
625
|
-
return _st.validate_skill_content_hash(item, raise_on_mismatch=raise_on_mismatch)
|
|
626
|
-
|
|
627
|
-
return SkillManager.prevalidate_skill_toolsets(toolsets, logger=self.logger, hash_validator=_HashValidator())
|
|
628
|
-
|
|
629
|
-
@staticmethod
|
|
630
|
-
def _is_tool_efficiency_kpi_unsatisfied(
|
|
631
|
-
summary: dict[str, Any] | None,
|
|
632
|
-
cadence_policy: CadencePolicy | None = None,
|
|
633
|
-
) -> bool:
|
|
634
|
-
return ToolEfficiencyGuard.is_tool_efficiency_kpi_unsatisfied(summary, cadence_policy=cadence_policy)
|
|
635
|
-
|
|
636
|
-
@staticmethod
|
|
637
|
-
def _build_tool_efficiency_corrective_prompt(
|
|
638
|
-
base_prompt: str,
|
|
639
|
-
cadence_policy: CadencePolicy | None = None,
|
|
640
|
-
) -> str:
|
|
641
|
-
return ToolEfficiencyGuard.build_tool_efficiency_corrective_prompt(base_prompt, cadence_policy=cadence_policy)
|
|
642
|
-
|
|
643
|
-
@staticmethod
|
|
644
|
-
def _collect_available_skill_names(toolsets: list[Any]) -> list[str]:
|
|
645
|
-
return SkillManager.collect_available_skill_names(toolsets, require_skill_tool_bindings=True)
|
|
646
|
-
|
|
647
|
-
@staticmethod
|
|
648
|
-
def _build_preloaded_skill_context(
|
|
649
|
-
toolsets: list[Any],
|
|
650
|
-
available_skill_names: list[str],
|
|
651
|
-
*,
|
|
652
|
-
max_skills: int = 2,
|
|
653
|
-
max_chars_per_skill: int = 1400,
|
|
654
|
-
preferred_skill_names: list[str] | None = None,
|
|
655
|
-
) -> tuple[str, list[str]]:
|
|
656
|
-
return SkillManager.build_preloaded_skill_context(
|
|
657
|
-
toolsets=toolsets,
|
|
658
|
-
available_skill_names=available_skill_names,
|
|
659
|
-
max_skills=max_skills,
|
|
660
|
-
max_chars_per_skill=max_chars_per_skill,
|
|
661
|
-
preferred_skill_names=preferred_skill_names,
|
|
662
|
-
)
|
|
663
|
-
|
|
664
|
-
@classmethod
|
|
665
|
-
def _recommend_skills_for_state_context(
|
|
666
|
-
cls,
|
|
667
|
-
*,
|
|
668
|
-
state_context: dict[str, Any] | None,
|
|
669
|
-
available_skill_names: list[str],
|
|
670
|
-
limit: int = 3,
|
|
671
|
-
) -> list[str]:
|
|
672
|
-
state = dict(state_context or {}) if isinstance(state_context, dict) else {}
|
|
673
|
-
interpretation = cls._extract_requirement_interpretation_from_state_context(state)
|
|
674
|
-
requirement_text = str(
|
|
675
|
-
interpretation.get("intent") or state.get("requirement_text") or state.get("row_requirement_text") or ""
|
|
676
|
-
).strip()
|
|
677
|
-
requirement_category = str(
|
|
678
|
-
interpretation.get("control_objective")
|
|
679
|
-
or state.get("requirement_category")
|
|
680
|
-
or state.get("row_requirement_category")
|
|
681
|
-
or ""
|
|
682
|
-
).strip()
|
|
683
|
-
return AuditSkillRouter.recommend_skills_for_requirement(
|
|
684
|
-
requirement_text=requirement_text,
|
|
685
|
-
requirement_category=requirement_category,
|
|
686
|
-
requirement_interpretation=interpretation,
|
|
687
|
-
available_skill_names=available_skill_names,
|
|
688
|
-
limit=limit,
|
|
689
|
-
)
|
|
690
|
-
|
|
691
|
-
@staticmethod
|
|
692
|
-
def _focus_skills_in_toolsets(
|
|
693
|
-
toolsets: list[Any],
|
|
694
|
-
allowed_skill_names: list[str],
|
|
695
|
-
) -> tuple[list[Any], int]:
|
|
696
|
-
return SkillManager.retain_skills_in_toolsets(toolsets=toolsets, allowed_skill_names=allowed_skill_names)
|
|
697
|
-
|
|
698
|
-
@staticmethod
|
|
699
|
-
def _normalize_string_list(value: Any) -> list[str]:
|
|
700
|
-
if not isinstance(value, list):
|
|
701
|
-
return []
|
|
702
|
-
return [str(item).strip() for item in value if str(item).strip()]
|
|
703
|
-
|
|
704
|
-
@staticmethod
|
|
705
|
-
def _remove_tool_names(toolsets: list[Any], blocked_names: set[str] | frozenset[str]) -> tuple[list[Any], int]:
|
|
706
|
-
"""Remove tool bindings by exact name across all toolsets."""
|
|
707
|
-
blocked = {str(name).strip() for name in blocked_names if str(name).strip()}
|
|
708
|
-
if not blocked:
|
|
709
|
-
return list(toolsets), 0
|
|
710
|
-
filtered: list[Any] = []
|
|
711
|
-
removed = 0
|
|
712
|
-
for toolset in toolsets:
|
|
713
|
-
tools_map = getattr(toolset, "tools", None)
|
|
714
|
-
if isinstance(tools_map, dict):
|
|
715
|
-
for name in list(tools_map):
|
|
716
|
-
if name in blocked:
|
|
717
|
-
tools_map.pop(name, None)
|
|
718
|
-
removed += 1
|
|
719
|
-
if not tools_map:
|
|
720
|
-
continue
|
|
721
|
-
filtered.append(toolset)
|
|
722
|
-
return filtered, removed
|
|
723
|
-
|
|
724
|
-
@staticmethod
|
|
725
|
-
def _is_doc_like_ref(ref: str) -> bool:
|
|
726
|
-
normalized = str(ref or "").strip().lower()
|
|
727
|
-
if not normalized:
|
|
728
|
-
return False
|
|
729
|
-
if normalized.startswith("chunk:"):
|
|
730
|
-
return True
|
|
731
|
-
if "/docs/" in normalized or normalized.startswith("docs/"):
|
|
732
|
-
return True
|
|
733
|
-
if "openapi" in normalized or "swagger" in normalized or "readme" in normalized:
|
|
734
|
-
return True
|
|
735
|
-
return normalized.endswith((".md", ".mdx", ".adoc", ".rst", ".txt", ".pdf", ".yaml", ".yml"))
|
|
736
|
-
|
|
737
|
-
@staticmethod
|
|
738
|
-
def _is_code_like_ref(ref: str) -> bool:
|
|
739
|
-
normalized = str(ref or "").strip().lower()
|
|
740
|
-
if not normalized:
|
|
741
|
-
return False
|
|
742
|
-
return normalized.endswith(
|
|
743
|
-
(
|
|
744
|
-
".py",
|
|
745
|
-
".java",
|
|
746
|
-
".kt",
|
|
747
|
-
".kts",
|
|
748
|
-
".js",
|
|
749
|
-
".jsx",
|
|
750
|
-
".ts",
|
|
751
|
-
".tsx",
|
|
752
|
-
".go",
|
|
753
|
-
".rb",
|
|
754
|
-
".php",
|
|
755
|
-
".cs",
|
|
756
|
-
".c",
|
|
757
|
-
".h",
|
|
758
|
-
".cpp",
|
|
759
|
-
".cc",
|
|
760
|
-
".rs",
|
|
761
|
-
".swift",
|
|
762
|
-
".scala",
|
|
763
|
-
)
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
@classmethod
|
|
767
|
-
def _extract_evidence_refs_from_state_context(cls, state_context: dict[str, Any] | None) -> list[str]:
|
|
768
|
-
if not isinstance(state_context, dict):
|
|
769
|
-
return []
|
|
770
|
-
|
|
771
|
-
refs: list[str] = []
|
|
772
|
-
|
|
773
|
-
def _append_from(value: Any) -> None:
|
|
774
|
-
if isinstance(value, list):
|
|
775
|
-
refs.extend(str(item).strip() for item in value if str(item).strip())
|
|
776
|
-
elif isinstance(value, str) and value.strip():
|
|
777
|
-
refs.append(value.strip())
|
|
778
|
-
|
|
779
|
-
_append_from(state_context.get("evidence_refs"))
|
|
780
|
-
for key in ("row_context", "context", "row", "tool_get_row_context_output", "retrieval_trace"):
|
|
781
|
-
container = state_context.get(key)
|
|
782
|
-
if isinstance(container, dict):
|
|
783
|
-
_append_from(container.get("evidence_refs"))
|
|
784
|
-
|
|
785
|
-
return list(dict.fromkeys(refs))
|
|
786
|
-
|
|
787
|
-
@classmethod
|
|
788
|
-
def _extract_evidence_context_text(cls, state_context: dict[str, Any] | None) -> str:
|
|
789
|
-
if not isinstance(state_context, dict):
|
|
790
|
-
return ""
|
|
791
|
-
|
|
792
|
-
for key in ("evidence_context",):
|
|
793
|
-
value = state_context.get(key)
|
|
794
|
-
if isinstance(value, str) and value.strip():
|
|
795
|
-
return value.strip()
|
|
796
|
-
|
|
797
|
-
for key in ("row_context", "context", "row", "tool_get_row_context_output", "retrieval_trace"):
|
|
798
|
-
container = state_context.get(key)
|
|
799
|
-
if isinstance(container, dict):
|
|
800
|
-
value = container.get("evidence_context")
|
|
801
|
-
if isinstance(value, str) and value.strip():
|
|
802
|
-
return value.strip()
|
|
803
|
-
|
|
804
|
-
return ""
|
|
805
|
-
|
|
806
|
-
@classmethod
|
|
807
|
-
def _should_skip_advisory_skill_sequence(
|
|
808
|
-
cls,
|
|
809
|
-
*,
|
|
810
|
-
state_context: dict[str, Any] | None,
|
|
811
|
-
interpretation: dict[str, Any] | None,
|
|
812
|
-
) -> bool:
|
|
813
|
-
"""Return True when advisory skill usage should be suppressed for grounded rows."""
|
|
814
|
-
interp = dict(interpretation or {}) if isinstance(interpretation, dict) else {}
|
|
815
|
-
refs = cls._extract_evidence_refs_from_state_context(state_context)
|
|
816
|
-
evidence_context = cls._extract_evidence_context_text(state_context)
|
|
817
|
-
evidence_targets = {
|
|
818
|
-
str(item).strip().lower() for item in (interp.get("evidence_targets") or []) if str(item).strip()
|
|
819
|
-
}
|
|
820
|
-
objectives = {str(item).strip().lower() for item in (interp.get("skill_objectives") or []) if str(item).strip()}
|
|
821
|
-
|
|
822
|
-
has_doc_ref = any(cls._is_doc_like_ref(ref) for ref in refs)
|
|
823
|
-
has_code_ref = any(cls._is_code_like_ref(ref) for ref in refs)
|
|
824
|
-
has_context_signal = len(evidence_context) >= 200
|
|
825
|
-
|
|
826
|
-
# Docs-anchored rows with explicit documentation-analysis objectives are
|
|
827
|
-
# frequently over-triggering discovery-only skill loops. Keep skills
|
|
828
|
-
# advisory-only when baseline grounding is already present.
|
|
829
|
-
if "analyze_documentation_artifacts" in objectives and (
|
|
830
|
-
len(refs) >= 2 and (has_doc_ref or "docs" in evidence_targets) and (has_context_signal or len(refs) >= 3)
|
|
831
|
-
):
|
|
832
|
-
return True
|
|
833
|
-
|
|
834
|
-
if len(refs) < 4:
|
|
835
|
-
return False
|
|
836
|
-
if not ("docs" in evidence_targets and "code" in evidence_targets):
|
|
837
|
-
return False
|
|
838
|
-
if not (has_doc_ref and has_code_ref):
|
|
839
|
-
return False
|
|
840
|
-
return len(evidence_context) >= 800 or len(refs) >= 5
|
|
841
|
-
|
|
842
|
-
@classmethod
|
|
843
|
-
def _extract_requirement_interpretation_from_state_context(
|
|
844
|
-
cls,
|
|
845
|
-
state_context: dict[str, Any] | None,
|
|
846
|
-
) -> dict[str, Any]:
|
|
847
|
-
"""Extract requirement interpretation artifact from state context variants."""
|
|
848
|
-
if not isinstance(state_context, dict):
|
|
849
|
-
return {}
|
|
850
|
-
|
|
851
|
-
def _extract_from_container(container: dict[str, Any] | None) -> dict[str, Any]:
|
|
852
|
-
if not isinstance(container, dict):
|
|
853
|
-
return {}
|
|
854
|
-
direct_interpretation = container.get("requirement_interpretation")
|
|
855
|
-
if isinstance(direct_interpretation, dict):
|
|
856
|
-
return dict(direct_interpretation)
|
|
857
|
-
nested_context = container.get("context")
|
|
858
|
-
if isinstance(nested_context, dict):
|
|
859
|
-
nested_interpretation = nested_context.get("requirement_interpretation")
|
|
860
|
-
if isinstance(nested_interpretation, dict):
|
|
861
|
-
return dict(nested_interpretation)
|
|
862
|
-
return {}
|
|
863
|
-
|
|
864
|
-
direct = state_context.get("requirement_interpretation")
|
|
865
|
-
if isinstance(direct, dict):
|
|
866
|
-
return dict(direct)
|
|
867
|
-
|
|
868
|
-
for key in (
|
|
869
|
-
"row_context",
|
|
870
|
-
"context",
|
|
871
|
-
"row",
|
|
872
|
-
"tool_get_row_context_output",
|
|
873
|
-
"retrieval_trace",
|
|
874
|
-
):
|
|
875
|
-
extracted = _extract_from_container(state_context.get(key))
|
|
876
|
-
if extracted:
|
|
877
|
-
return extracted
|
|
878
|
-
|
|
879
|
-
fallback_keys = {
|
|
880
|
-
"intent",
|
|
881
|
-
"control_objective",
|
|
882
|
-
"evidence_targets",
|
|
883
|
-
"code_targets",
|
|
884
|
-
"acceptance_signals",
|
|
885
|
-
"skill_objectives",
|
|
886
|
-
}
|
|
887
|
-
if any(key in state_context for key in fallback_keys):
|
|
888
|
-
return {key: state_context.get(key) for key in fallback_keys if key in state_context}
|
|
889
|
-
return {}
|
|
890
|
-
|
|
891
|
-
@classmethod
|
|
892
|
-
def _resolve_requirement_skill_activation_decision(
|
|
893
|
-
cls,
|
|
894
|
-
*,
|
|
895
|
-
state_context: dict[str, Any] | None,
|
|
896
|
-
) -> dict[str, Any]:
|
|
897
|
-
"""Resolve requirement-driven skill activation decision (FR-122)."""
|
|
898
|
-
state = dict(state_context) if isinstance(state_context, dict) else {}
|
|
899
|
-
interpretation = cls._extract_requirement_interpretation_from_state_context(state)
|
|
900
|
-
|
|
901
|
-
explicit_state_decision = state.get("skills_needed")
|
|
902
|
-
if isinstance(explicit_state_decision, bool):
|
|
903
|
-
explicit_state_reason = str(state.get("skills_needed_reason") or "").strip()
|
|
904
|
-
return {
|
|
905
|
-
"skills_needed": explicit_state_decision,
|
|
906
|
-
"reason": explicit_state_reason or "state_context_explicit_skills_needed",
|
|
907
|
-
"decision_source": "state_context",
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
explicit_interpretation_decision = interpretation.get("skills_needed")
|
|
911
|
-
if isinstance(explicit_interpretation_decision, bool):
|
|
912
|
-
explicit_interpretation_reason = str(interpretation.get("skills_needed_reason") or "").strip()
|
|
913
|
-
return {
|
|
914
|
-
"skills_needed": explicit_interpretation_decision,
|
|
915
|
-
"reason": explicit_interpretation_reason or "requirement_interpretation_explicit_skills_needed",
|
|
916
|
-
"decision_source": "requirement_interpretation",
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
intent = str(
|
|
920
|
-
interpretation.get("intent") or state.get("requirement_text") or state.get("row_requirement_text") or ""
|
|
921
|
-
).strip()
|
|
922
|
-
control_objective = str(
|
|
923
|
-
interpretation.get("control_objective")
|
|
924
|
-
or state.get("requirement_category")
|
|
925
|
-
or state.get("row_requirement_category")
|
|
926
|
-
or ""
|
|
927
|
-
).strip()
|
|
928
|
-
evidence_targets = [
|
|
929
|
-
target.lower() for target in cls._normalize_string_list(interpretation.get("evidence_targets"))
|
|
930
|
-
]
|
|
931
|
-
code_targets = cls._normalize_string_list(interpretation.get("code_targets"))
|
|
932
|
-
acceptance_signals = cls._normalize_string_list(interpretation.get("acceptance_signals"))
|
|
933
|
-
skill_objectives = cls._normalize_string_list(interpretation.get("skill_objectives"))
|
|
934
|
-
|
|
935
|
-
if not interpretation and not intent and not control_objective:
|
|
936
|
-
return {
|
|
937
|
-
"skills_needed": False,
|
|
938
|
-
"reason": "requirement_interpretation_missing",
|
|
939
|
-
"decision_source": "fallback",
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
if skill_objectives:
|
|
943
|
-
return {
|
|
944
|
-
"skills_needed": True,
|
|
945
|
-
"reason": "requirement_interpretation_skill_objectives_present",
|
|
946
|
-
"decision_source": "requirement_interpretation",
|
|
947
|
-
"skill_objectives": skill_objectives[:4],
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
combined_text = " ".join(
|
|
951
|
-
part
|
|
952
|
-
for part in [
|
|
953
|
-
intent.lower(),
|
|
954
|
-
control_objective.lower(),
|
|
955
|
-
" ".join(signal.lower() for signal in acceptance_signals[:4]),
|
|
956
|
-
]
|
|
957
|
-
if part
|
|
958
|
-
)
|
|
959
|
-
keyword_list = (
|
|
960
|
-
"workflow",
|
|
961
|
-
"orchestrator",
|
|
962
|
-
"runbook",
|
|
963
|
-
"playbook",
|
|
964
|
-
"cli",
|
|
965
|
-
"command",
|
|
966
|
-
"tooling",
|
|
967
|
-
"lsp",
|
|
968
|
-
"mypy",
|
|
969
|
-
"pyright",
|
|
970
|
-
"ruff",
|
|
971
|
-
"uv",
|
|
972
|
-
"typer",
|
|
973
|
-
"confluence",
|
|
974
|
-
"bitbucket",
|
|
975
|
-
"grafana",
|
|
976
|
-
"bpmn",
|
|
977
|
-
"spec",
|
|
978
|
-
"automation",
|
|
979
|
-
"script",
|
|
980
|
-
"sync",
|
|
981
|
-
"integration guide",
|
|
982
|
-
"documentation process",
|
|
983
|
-
)
|
|
984
|
-
keyword_hits = [keyword for keyword in keyword_list if keyword in combined_text]
|
|
985
|
-
docs_targeted = "docs" in evidence_targets
|
|
986
|
-
code_targeted = "code" in evidence_targets or bool(code_targets)
|
|
987
|
-
operational_skill_keywords = {
|
|
988
|
-
"script",
|
|
989
|
-
"automation",
|
|
990
|
-
"runbook",
|
|
991
|
-
"playbook",
|
|
992
|
-
"cli",
|
|
993
|
-
"command",
|
|
994
|
-
"tooling",
|
|
995
|
-
"confluence",
|
|
996
|
-
"grafana",
|
|
997
|
-
"bitbucket",
|
|
998
|
-
"integration guide",
|
|
999
|
-
"documentation process",
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
if keyword_hits and (docs_targeted or not code_targeted):
|
|
1003
|
-
return {
|
|
1004
|
-
"skills_needed": True,
|
|
1005
|
-
"reason": f"requirement_interpretation_keyword:{keyword_hits[0]}",
|
|
1006
|
-
"decision_source": "heuristic",
|
|
1007
|
-
"keyword_hits": keyword_hits[:4],
|
|
1008
|
-
}
|
|
1009
|
-
if keyword_hits and any(keyword in operational_skill_keywords for keyword in keyword_hits):
|
|
1010
|
-
return {
|
|
1011
|
-
"skills_needed": True,
|
|
1012
|
-
"reason": f"requirement_interpretation_operational_keyword:{keyword_hits[0]}",
|
|
1013
|
-
"decision_source": "heuristic",
|
|
1014
|
-
"keyword_hits": keyword_hits[:4],
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
return {
|
|
1018
|
-
"skills_needed": False,
|
|
1019
|
-
"reason": "requirement_interpretation_code_first_no_skill_signal",
|
|
1020
|
-
"decision_source": "heuristic",
|
|
1021
|
-
"keyword_hits": keyword_hits[:4],
|
|
1022
|
-
"evidence_targets": evidence_targets[:4],
|
|
1023
|
-
"code_target_count": len(code_targets),
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
@staticmethod
|
|
1027
|
-
def _apply_tool_allowlist(toolsets: list[Any], allowlist: list[str]) -> list[Any]:
|
|
1028
|
-
"""Filter toolset-exposed tools to the configured allowlist."""
|
|
1029
|
-
allowed = {name for name in allowlist if isinstance(name, str) and name.strip()}
|
|
1030
|
-
if not allowed:
|
|
1031
|
-
return list(toolsets)
|
|
1032
|
-
filtered: list[Any] = []
|
|
1033
|
-
for toolset in toolsets:
|
|
1034
|
-
tools_map = getattr(toolset, "tools", None)
|
|
1035
|
-
if isinstance(tools_map, dict):
|
|
1036
|
-
for name in list(tools_map):
|
|
1037
|
-
if name not in allowed:
|
|
1038
|
-
tools_map.pop(name, None)
|
|
1039
|
-
if not tools_map:
|
|
1040
|
-
continue
|
|
1041
|
-
filtered.append(toolset)
|
|
1042
|
-
return filtered
|
|
1043
|
-
|
|
1044
|
-
@staticmethod
|
|
1045
|
-
def _is_repetitive_non_progress_tool_usage(
|
|
1046
|
-
telemetry: dict[str, Any] | None,
|
|
1047
|
-
cadence_policy: CadencePolicy | None = None,
|
|
1048
|
-
) -> bool:
|
|
1049
|
-
return ToolEfficiencyGuard.is_repetitive_non_progress_tool_usage(telemetry, cadence_policy=cadence_policy)
|
|
1050
|
-
|
|
1051
|
-
@staticmethod
|
|
1052
|
-
def _is_invalid_tool_usage_error(error: str) -> bool:
|
|
1053
|
-
return ToolEfficiencyGuard.is_invalid_tool_usage_error(error)
|
|
1054
|
-
|
|
1055
|
-
@staticmethod
|
|
1056
|
-
def _parse_tool_name_from_invalid_tool_error(error: str) -> str | None:
|
|
1057
|
-
return ToolEfficiencyGuard.parse_tool_name_from_invalid_tool_error(error)
|
|
1058
|
-
|
|
1059
|
-
@staticmethod
|
|
1060
|
-
def _build_tool_allowlist_guard_prompt(
|
|
1061
|
-
base_prompt: str,
|
|
1062
|
-
*,
|
|
1063
|
-
allowed_tools: list[str],
|
|
1064
|
-
attempted_tool: str | None,
|
|
1065
|
-
) -> str:
|
|
1066
|
-
return ToolEfficiencyGuard.build_tool_allowlist_guard_prompt(
|
|
1067
|
-
base_prompt,
|
|
1068
|
-
allowed_tools=allowed_tools,
|
|
1069
|
-
attempted_tool=attempted_tool,
|
|
1070
|
-
)
|
|
1071
|
-
|
|
1072
|
-
@staticmethod
|
|
1073
|
-
def _is_list_directory_churn(
|
|
1074
|
-
telemetry: dict[str, Any] | None,
|
|
1075
|
-
*,
|
|
1076
|
-
min_calls: int = 4,
|
|
1077
|
-
dominance_ratio: float = 0.6,
|
|
1078
|
-
) -> bool:
|
|
1079
|
-
return ToolEfficiencyGuard.is_list_directory_churn(
|
|
1080
|
-
telemetry,
|
|
1081
|
-
min_calls=min_calls,
|
|
1082
|
-
dominance_ratio=dominance_ratio,
|
|
1083
|
-
)
|
|
1084
|
-
|
|
1085
|
-
@staticmethod
|
|
1086
|
-
def _is_usage_limit_error(exc: Exception) -> bool:
|
|
1087
|
-
"""Return True when an exception indicates request/tool budget exhaustion."""
|
|
1088
|
-
message = str(exc).lower()
|
|
1089
|
-
cause = getattr(exc, "__cause__", None)
|
|
1090
|
-
cause_message = str(cause).lower() if cause is not None else ""
|
|
1091
|
-
combined = f"{message}\n{cause_message}"
|
|
1092
|
-
return (
|
|
1093
|
-
"request_limit" in combined
|
|
1094
|
-
or "tool_calls_limit" in combined
|
|
1095
|
-
or "usagelimitexceeded" in combined
|
|
1096
|
-
or "usage limit exceeded" in combined
|
|
1097
|
-
)
|
|
1098
|
-
|
|
1099
|
-
@staticmethod
|
|
1100
|
-
def _is_output_validation_retry_error(exc: Exception) -> bool:
|
|
1101
|
-
"""Return True when provider exhausted output validation retries."""
|
|
1102
|
-
message = str(exc).lower()
|
|
1103
|
-
cause = getattr(exc, "__cause__", None)
|
|
1104
|
-
cause_message = str(cause).lower() if cause is not None else ""
|
|
1105
|
-
combined = f"{message}\n{cause_message}"
|
|
1106
|
-
return "output validation" in combined and "exceeded maximum retries" in combined
|
|
1107
|
-
|
|
1108
|
-
@staticmethod
|
|
1109
|
-
def _has_concrete_reasoning_evidence_refs(reasoning: str) -> bool:
|
|
1110
|
-
"""Return True when reasoning includes concrete path:line or quoted document evidence refs."""
|
|
1111
|
-
text = str(reasoning or "").strip()
|
|
1112
|
-
if not text:
|
|
1113
|
-
return False
|
|
1114
|
-
|
|
1115
|
-
file_line_ref = re.search(r"(?<!\w)(?:[A-Za-z]:)?[A-Za-z0-9_./\\-]+\.[A-Za-z0-9_]{1,10}:\d+(?!\w)", text)
|
|
1116
|
-
if file_line_ref is not None:
|
|
1117
|
-
return True
|
|
1118
|
-
|
|
1119
|
-
document_title_ref = re.search(
|
|
1120
|
-
r"\b(?:doc|document|confluence)\b[^\n]{0,80}[\"'`][^\"'`\n]{3,120}[\"'`]",
|
|
1121
|
-
text,
|
|
1122
|
-
flags=re.IGNORECASE,
|
|
1123
|
-
)
|
|
1124
|
-
return document_title_ref is not None
|
|
1125
|
-
|
|
1126
|
-
@staticmethod
|
|
1127
|
-
def _build_issue_grounded_reasoning(output: CodeFindings | None) -> str:
|
|
1128
|
-
"""Synthesize a grounded reasoning fallback from structured issue outputs.
|
|
1129
|
-
|
|
1130
|
-
Some providers intermittently return empty `reasoning` while still returning
|
|
1131
|
-
grounded `issues`. This fallback keeps strict quality gates meaningful without
|
|
1132
|
-
adding tool/fallback retries.
|
|
1133
|
-
"""
|
|
1134
|
-
if output is None:
|
|
1135
|
-
return ""
|
|
1136
|
-
issues = getattr(output, "issues", None)
|
|
1137
|
-
if not isinstance(issues, list) or not issues:
|
|
1138
|
-
return ""
|
|
1139
|
-
|
|
1140
|
-
evidence_bits: list[str] = []
|
|
1141
|
-
for issue in issues[:3]:
|
|
1142
|
-
file_path = str(getattr(issue, "file_path", "") or "").strip() or "unknown"
|
|
1143
|
-
line_number = getattr(issue, "line_number", None)
|
|
1144
|
-
severity = str(getattr(issue, "severity", "") or "medium").lower()
|
|
1145
|
-
description = str(getattr(issue, "description", "") or "Issue detected").strip()
|
|
1146
|
-
ref = f"{file_path}:{line_number}" if line_number else file_path
|
|
1147
|
-
evidence_bits.append(f"{severity} issue at {ref}: {description}.")
|
|
1148
|
-
|
|
1149
|
-
score = float(getattr(output, "score", 0.0) or 0.0)
|
|
1150
|
-
confidence = float(getattr(output, "confidence", 0.0) or 0.0)
|
|
1151
|
-
files_analyzed = int(getattr(output, "files_analyzed", 0) or 0)
|
|
1152
|
-
stack = [str(item).strip() for item in (getattr(output, "tech_stack", []) or []) if str(item).strip()]
|
|
1153
|
-
stack_summary = ", ".join(stack[:4]) if stack else "undetermined stack"
|
|
1154
|
-
return (
|
|
1155
|
-
f"Code analysis found {len(issues)} issue(s) across approximately {max(files_analyzed, len(issues))} file(s) "
|
|
1156
|
-
f"with score {score:.1f}/10 and confidence {confidence:.2f}. "
|
|
1157
|
-
f"Primary evidence: {' '.join(evidence_bits)} "
|
|
1158
|
-
f"Observed stack context: {stack_summary}. "
|
|
1159
|
-
"Residual uncertainty: additional deep-path files may contain further edge cases not covered in this pass."
|
|
1160
|
-
)
|
|
1161
|
-
|
|
1162
|
-
@staticmethod
|
|
1163
|
-
def _has_grounded_issue_paths(output: CodeFindings | None, repo_path: Path) -> bool:
|
|
1164
|
-
"""Return True when findings reference at least one concrete file under repo_path.
|
|
1165
|
-
|
|
1166
|
-
This is a defensive quality gate for providers where tool-call telemetry
|
|
1167
|
-
can be inconsistent in some runs. It does not replace tool usage checks;
|
|
1168
|
-
it only allows an explicit, logged degraded pass when findings are still
|
|
1169
|
-
grounded to real repository files.
|
|
1170
|
-
"""
|
|
1171
|
-
if output is None:
|
|
1172
|
-
return False
|
|
1173
|
-
issues = getattr(output, "issues", None)
|
|
1174
|
-
if not isinstance(issues, list) or not issues:
|
|
1175
|
-
return False
|
|
1176
|
-
|
|
1177
|
-
repo_root = repo_path.resolve()
|
|
1178
|
-
for issue in issues:
|
|
1179
|
-
file_path = str(getattr(issue, "file_path", "") or "").strip()
|
|
1180
|
-
if not file_path or file_path.lower() == "unknown":
|
|
1181
|
-
continue
|
|
1182
|
-
|
|
1183
|
-
candidate = Path(file_path)
|
|
1184
|
-
if not candidate.is_absolute():
|
|
1185
|
-
candidate = repo_root / candidate
|
|
1186
|
-
|
|
1187
|
-
try:
|
|
1188
|
-
resolved = candidate.resolve()
|
|
1189
|
-
except PATH_RESOLUTION_RECOVERABLE_ERRORS:
|
|
1190
|
-
continue
|
|
1191
|
-
|
|
1192
|
-
if resolved.is_file() and (resolved == repo_root or repo_root in resolved.parents):
|
|
1193
|
-
return True
|
|
1194
|
-
return False
|
|
1195
|
-
|
|
1196
|
-
@staticmethod
|
|
1197
|
-
def _has_productive_agentic_output(
|
|
1198
|
-
output: CodeFindings | None,
|
|
1199
|
-
efficiency_summary: dict[str, Any] | None,
|
|
1200
|
-
) -> bool:
|
|
1201
|
-
return ToolEfficiencyGuard.has_productive_agentic_output(output, efficiency_summary)
|
|
1202
|
-
|
|
1203
|
-
async def _run_agentic_analysis(
|
|
1204
|
-
self,
|
|
1205
|
-
evidence: EvidenceBundle,
|
|
1206
|
-
profile: dict[str, Any] | None,
|
|
1207
|
-
repo_path: Path,
|
|
1208
|
-
*,
|
|
1209
|
-
runtime: dict[str, Any] | None,
|
|
1210
|
-
) -> CodeFindings | None:
|
|
1211
|
-
"""Run agentic investigation with filesystem + LSP toolsets (Phase 41).
|
|
1212
|
-
|
|
1213
|
-
Attaches bounded, read-only toolsets to the PydanticAI agent and runs
|
|
1214
|
-
a multi-turn investigation loop.
|
|
1215
|
-
|
|
1216
|
-
Args:
|
|
1217
|
-
evidence: EvidenceBundle with git_evidence to analyze.
|
|
1218
|
-
profile: Optional project profile for context.
|
|
1219
|
-
repo_path: Absolute path to the repository.
|
|
1220
|
-
|
|
1221
|
-
Returns:
|
|
1222
|
-
CodeFindings from agentic investigation, or None on failure.
|
|
1223
|
-
"""
|
|
1224
|
-
from vds_audit_orchestrator.agents.toolsets.evidence_corpus import (
|
|
1225
|
-
create_evidence_corpus_toolset,
|
|
1226
|
-
)
|
|
1227
|
-
from vds_audit_orchestrator.agents.toolsets.filesystem import create_filesystem_toolset
|
|
1228
|
-
from vds_audit_orchestrator.agents.toolsets.lsp import create_lsp_toolset
|
|
1229
|
-
from vds_audit_orchestrator.agents.toolsets.skills_toolset import get_default_skills_toolset
|
|
1230
|
-
from vds_audit_orchestrator.agents.toolsets.vector_evidence import (
|
|
1231
|
-
create_vector_evidence_toolset,
|
|
1232
|
-
is_vector_evidence_ready,
|
|
1233
|
-
)
|
|
1234
|
-
|
|
1235
|
-
if runtime is None:
|
|
1236
|
-
self.logger.info("agentic_runtime_unavailable")
|
|
1237
|
-
raise RuntimeError("agentic runtime unavailable")
|
|
1238
|
-
|
|
1239
|
-
tool_timeout_sec = int(runtime["tool_timeout_sec"])
|
|
1240
|
-
safe_extensions = tuple(runtime["safe_extensions"])
|
|
1241
|
-
max_read_bytes = int(runtime["max_read_bytes"])
|
|
1242
|
-
max_read_lines = int(runtime.get("max_read_lines", 300))
|
|
1243
|
-
strict_no_fallback = bool(runtime.get("strict_no_fallback", True))
|
|
1244
|
-
non_progress_policy = runtime.get("non_progress_policy", {}) if isinstance(runtime, dict) else {}
|
|
1245
|
-
row_context = runtime.get("row_context") if isinstance(runtime, dict) else None
|
|
1246
|
-
cadence_policy = ToolEfficiencyGuard.create_policy_for_row(
|
|
1247
|
-
row_context if isinstance(row_context, dict) else None,
|
|
1248
|
-
overrides=non_progress_policy if isinstance(non_progress_policy, dict) and non_progress_policy else None,
|
|
1249
|
-
)
|
|
1250
|
-
tool_allowlist = list(runtime.get("tool_allowlist", [])) if isinstance(runtime, dict) else []
|
|
1251
|
-
max_turns = int(runtime["max_turns"])
|
|
1252
|
-
max_tool_calls = int(runtime["max_tool_calls"])
|
|
1253
|
-
strict_cap_max_turns = int(runtime.get("strict_cap_max_turns", 10))
|
|
1254
|
-
strict_cap_max_tool_calls = int(runtime.get("strict_cap_max_tool_calls", 24))
|
|
1255
|
-
local_openai_synthesis_max_turns = int(
|
|
1256
|
-
runtime.get("synthesis_max_turns", runtime.get("local_openai_synthesis_max_turns", 4))
|
|
1257
|
-
)
|
|
1258
|
-
local_openai_synthesis_max_tool_calls = int(
|
|
1259
|
-
runtime.get("synthesis_max_tool_calls", runtime.get("local_openai_synthesis_max_tool_calls", 2))
|
|
1260
|
-
)
|
|
1261
|
-
local_openai_hard_synthesis_max_turns = int(
|
|
1262
|
-
runtime.get("hard_synthesis_max_turns", runtime.get("local_openai_hard_synthesis_max_turns", 2))
|
|
1263
|
-
)
|
|
1264
|
-
local_openai_hard_synthesis_max_tool_calls = int(
|
|
1265
|
-
runtime.get("hard_synthesis_max_tool_calls", runtime.get("local_openai_hard_synthesis_max_tool_calls", 0))
|
|
1266
|
-
)
|
|
1267
|
-
skills_toolset_enabled = bool(runtime.get("skills_toolset_enabled", True))
|
|
1268
|
-
mode_value = getattr(self, "agentic_mode", None)
|
|
1269
|
-
if mode_value is None:
|
|
1270
|
-
mode_value = getattr(self, "_agentic_mode", "")
|
|
1271
|
-
forced_agentic_mode = str(mode_value).strip().lower() == "on"
|
|
1272
|
-
|
|
1273
|
-
local_openai_protocol = self._uses_local_openai_protocol()
|
|
1274
|
-
if (
|
|
1275
|
-
strict_no_fallback
|
|
1276
|
-
and local_openai_protocol
|
|
1277
|
-
and (max_tool_calls > strict_cap_max_tool_calls or max_turns > strict_cap_max_turns)
|
|
1278
|
-
):
|
|
1279
|
-
self.logger.info(
|
|
1280
|
-
"agentic_budget_adjusted_for_local_openai_protocol",
|
|
1281
|
-
original_max_turns=max_turns,
|
|
1282
|
-
original_max_tool_calls=max_tool_calls,
|
|
1283
|
-
adjusted_max_turns=strict_cap_max_turns,
|
|
1284
|
-
adjusted_max_tool_calls=strict_cap_max_tool_calls,
|
|
1285
|
-
forced_agentic_mode=forced_agentic_mode,
|
|
1286
|
-
)
|
|
1287
|
-
max_turns = min(max_turns, strict_cap_max_turns)
|
|
1288
|
-
max_tool_calls = min(max_tool_calls, strict_cap_max_tool_calls)
|
|
1289
|
-
|
|
1290
|
-
# Build toolsets scoped to repo_path.
|
|
1291
|
-
base_toolsets: list[Any] = []
|
|
1292
|
-
try:
|
|
1293
|
-
base_toolsets = self._build_runtime_toolsets(self._get_runtime_config().llm)
|
|
1294
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1295
|
-
self.logger.warning(
|
|
1296
|
-
"agentic_base_toolsets_failed",
|
|
1297
|
-
error=str(exc),
|
|
1298
|
-
error_type=type(exc).__name__,
|
|
1299
|
-
handler="_run_agentic_analysis._build_runtime_toolsets",
|
|
1300
|
-
)
|
|
1301
|
-
skills_toolset_present = any(
|
|
1302
|
-
isinstance(getattr(toolset, "_vds_skill_metadata", None), list)
|
|
1303
|
-
and len(getattr(toolset, "_vds_skill_metadata", [])) > 0
|
|
1304
|
-
for toolset in base_toolsets
|
|
1305
|
-
)
|
|
1306
|
-
if not skills_toolset_present and skills_toolset_enabled:
|
|
1307
|
-
try:
|
|
1308
|
-
default_skills_toolset = get_default_skills_toolset()
|
|
1309
|
-
base_toolsets.append(default_skills_toolset)
|
|
1310
|
-
self.logger.info("agentic_default_skills_toolset_attached")
|
|
1311
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1312
|
-
self.logger.warning(
|
|
1313
|
-
"agentic_default_skills_toolset_unavailable",
|
|
1314
|
-
error=str(exc),
|
|
1315
|
-
error_type=type(exc).__name__,
|
|
1316
|
-
handler="_run_agentic_analysis.get_default_skills_toolset",
|
|
1317
|
-
)
|
|
1318
|
-
elif not skills_toolset_enabled:
|
|
1319
|
-
self.logger.info("agentic_skills_toolset_disabled")
|
|
1320
|
-
|
|
1321
|
-
agentic_toolsets: list[Any] = []
|
|
1322
|
-
try:
|
|
1323
|
-
fs_toolset = create_filesystem_toolset(
|
|
1324
|
-
repo_path,
|
|
1325
|
-
safe_extensions=safe_extensions,
|
|
1326
|
-
max_read_bytes=max_read_bytes,
|
|
1327
|
-
max_read_lines=max_read_lines,
|
|
1328
|
-
grep_timeout_sec=tool_timeout_sec,
|
|
1329
|
-
)
|
|
1330
|
-
agentic_toolsets.append(fs_toolset)
|
|
1331
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1332
|
-
self.logger.warning(
|
|
1333
|
-
"filesystem_toolset_creation_failed",
|
|
1334
|
-
error=str(exc),
|
|
1335
|
-
error_type=type(exc).__name__,
|
|
1336
|
-
handler="_run_agentic_analysis.create_filesystem_toolset",
|
|
1337
|
-
repo_path=str(repo_path),
|
|
1338
|
-
)
|
|
1339
|
-
|
|
1340
|
-
try:
|
|
1341
|
-
lsp_toolset = create_lsp_toolset(repo_path, timeout_sec=tool_timeout_sec)
|
|
1342
|
-
agentic_toolsets.append(lsp_toolset)
|
|
1343
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1344
|
-
self.logger.warning(
|
|
1345
|
-
"lsp_toolset_creation_failed",
|
|
1346
|
-
error=str(exc),
|
|
1347
|
-
error_type=type(exc).__name__,
|
|
1348
|
-
handler="_run_agentic_analysis.create_lsp_toolset",
|
|
1349
|
-
repo_path=str(repo_path),
|
|
1350
|
-
)
|
|
1351
|
-
|
|
1352
|
-
if not agentic_toolsets:
|
|
1353
|
-
self.logger.warning("agentic_no_toolsets_available")
|
|
1354
|
-
raise RuntimeError("agentic toolsets unavailable")
|
|
1355
|
-
|
|
1356
|
-
toolsets = list(base_toolsets)
|
|
1357
|
-
toolsets.extend(agentic_toolsets)
|
|
1358
|
-
toolsets = self._prevalidate_skill_toolsets(toolsets)
|
|
1359
|
-
toolsets = self._apply_tool_allowlist(toolsets, tool_allowlist)
|
|
1360
|
-
|
|
1361
|
-
# Build dependencies.
|
|
1362
|
-
deps = AuditDeps.from_evidence_bundle(
|
|
1363
|
-
evidence=evidence,
|
|
1364
|
-
profile=profile,
|
|
1365
|
-
settings=self.settings,
|
|
1366
|
-
evidence_corpus=self._evidence_corpus,
|
|
1367
|
-
)
|
|
1368
|
-
|
|
1369
|
-
state_context = dict(self._state_context) if isinstance(self._state_context, dict) else {}
|
|
1370
|
-
|
|
1371
|
-
postgres_evidence_ready = bool(state_context.get("state_dsn")) and bool(
|
|
1372
|
-
state_context.get("project_key") or state_context.get("project_storage_key")
|
|
1373
|
-
)
|
|
1374
|
-
deps.settings = {
|
|
1375
|
-
**deps.settings,
|
|
1376
|
-
"state_context": state_context,
|
|
1377
|
-
"agentic": {
|
|
1378
|
-
"max_turns": max_turns,
|
|
1379
|
-
"max_tool_calls": max_tool_calls,
|
|
1380
|
-
"tool_timeout_sec": tool_timeout_sec,
|
|
1381
|
-
"safe_extensions": list(safe_extensions),
|
|
1382
|
-
"max_read_bytes": max_read_bytes,
|
|
1383
|
-
"max_read_lines": max_read_lines,
|
|
1384
|
-
"grep_timeout_sec": tool_timeout_sec,
|
|
1385
|
-
"lsp_timeout_sec": tool_timeout_sec,
|
|
1386
|
-
},
|
|
1387
|
-
}
|
|
1388
|
-
if deps.evidence_corpus is not None:
|
|
1389
|
-
try:
|
|
1390
|
-
evidence_toolset = create_evidence_corpus_toolset()
|
|
1391
|
-
toolsets.append(evidence_toolset)
|
|
1392
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1393
|
-
self.logger.warning(
|
|
1394
|
-
"evidence_corpus_toolset_creation_failed",
|
|
1395
|
-
error=str(exc),
|
|
1396
|
-
error_type=type(exc).__name__,
|
|
1397
|
-
handler="_run_agentic_analysis.create_evidence_corpus_toolset",
|
|
1398
|
-
)
|
|
1399
|
-
available_skill_names = self._collect_available_skill_names(toolsets)
|
|
1400
|
-
skills_available = len(available_skill_names) > 0
|
|
1401
|
-
preloaded_skill_context, preloaded_skill_names = self._build_preloaded_skill_context(
|
|
1402
|
-
toolsets=toolsets,
|
|
1403
|
-
available_skill_names=available_skill_names,
|
|
1404
|
-
max_skills=1 if local_openai_protocol else 2,
|
|
1405
|
-
max_chars_per_skill=500 if local_openai_protocol else 1400,
|
|
1406
|
-
)
|
|
1407
|
-
if preloaded_skill_names:
|
|
1408
|
-
self.logger.info(
|
|
1409
|
-
"agentic_skill_bootstrap_preloaded",
|
|
1410
|
-
preloaded_skill_count=len(preloaded_skill_names),
|
|
1411
|
-
preloaded_skill_names=preloaded_skill_names,
|
|
1412
|
-
preloaded_skill_chars=len(preloaded_skill_context),
|
|
1413
|
-
)
|
|
1414
|
-
self._log_trace_payload(
|
|
1415
|
-
event_name="agentic_trace_runtime_context_assembly",
|
|
1416
|
-
elapsed_sec=0.0,
|
|
1417
|
-
payload={
|
|
1418
|
-
"repo_path": str(repo_path),
|
|
1419
|
-
"runtime": {
|
|
1420
|
-
"max_turns": max_turns,
|
|
1421
|
-
"max_tool_calls": max_tool_calls,
|
|
1422
|
-
"tool_timeout_sec": tool_timeout_sec,
|
|
1423
|
-
"safe_extension_count": len(safe_extensions),
|
|
1424
|
-
"max_read_bytes": max_read_bytes,
|
|
1425
|
-
"max_read_lines": max_read_lines,
|
|
1426
|
-
},
|
|
1427
|
-
"state_context_key_count": len(state_context),
|
|
1428
|
-
"state_context_keys": sorted(str(key) for key in state_context)[:20],
|
|
1429
|
-
"base_toolset_count": len(base_toolsets),
|
|
1430
|
-
"agentic_toolset_count": len(agentic_toolsets),
|
|
1431
|
-
"toolset_types": [type(toolset).__name__ for toolset in toolsets][:16],
|
|
1432
|
-
"skills_available": skills_available,
|
|
1433
|
-
"available_skill_names": available_skill_names[:8],
|
|
1434
|
-
"preloaded_skill_names": preloaded_skill_names,
|
|
1435
|
-
"docs_required": bool(deps.evidence_corpus and deps.evidence_corpus.documents),
|
|
1436
|
-
"postgres_evidence_ready": postgres_evidence_ready,
|
|
1437
|
-
},
|
|
1438
|
-
)
|
|
1439
|
-
docs_required = bool(deps.evidence_corpus and deps.evidence_corpus.documents)
|
|
1440
|
-
vector_docs_required = False
|
|
1441
|
-
try:
|
|
1442
|
-
vector_docs_required = is_vector_evidence_ready(deps=deps)
|
|
1443
|
-
if vector_docs_required:
|
|
1444
|
-
vector_toolset = create_vector_evidence_toolset()
|
|
1445
|
-
toolsets.append(vector_toolset)
|
|
1446
|
-
self.logger.info("vector_evidence_toolset_attached")
|
|
1447
|
-
except AGENTIC_SETUP_RECOVERABLE_ERRORS as exc:
|
|
1448
|
-
self.logger.warning(
|
|
1449
|
-
"vector_evidence_toolset_unavailable",
|
|
1450
|
-
error=str(exc),
|
|
1451
|
-
error_type=type(exc).__name__,
|
|
1452
|
-
handler="_run_agentic_analysis.vector_evidence_setup",
|
|
1453
|
-
repo_path=str(repo_path),
|
|
1454
|
-
)
|
|
1455
|
-
vector_docs_required = False
|
|
1456
|
-
self.logger.info(
|
|
1457
|
-
"agentic_vector_readiness_resolved",
|
|
1458
|
-
vector_docs_required=vector_docs_required,
|
|
1459
|
-
postgres_evidence_ready=postgres_evidence_ready,
|
|
1460
|
-
docs_required=docs_required,
|
|
1461
|
-
state_project_key=(
|
|
1462
|
-
state_context.get("project_storage_key")
|
|
1463
|
-
or state_context.get("project_key")
|
|
1464
|
-
or state_context.get("project_id")
|
|
1465
|
-
),
|
|
1466
|
-
state_repo_key=(state_context.get("repo_storage_key") or state_context.get("repo_key")),
|
|
1467
|
-
)
|
|
1468
|
-
strict_require_effective_skill_env = self._parse_env_bool("VDS_AUDIT_AGENTIC_STRICT_REQUIRE_EFFECTIVE_SKILL")
|
|
1469
|
-
strict_require_effective_skill = (
|
|
1470
|
-
True if strict_require_effective_skill_env is None else strict_require_effective_skill_env
|
|
1471
|
-
)
|
|
1472
|
-
strict_skip_post_guard_retries = bool(
|
|
1473
|
-
strict_no_fallback and self._parse_env_bool("VDS_AUDIT_AGENTIC_STRICT_SKIP_POST_GUARD_RETRIES")
|
|
1474
|
-
)
|
|
1475
|
-
interpretation = self._extract_requirement_interpretation_from_state_context(state_context)
|
|
1476
|
-
skill_activation_decision = self._resolve_requirement_skill_activation_decision(
|
|
1477
|
-
state_context=state_context,
|
|
1478
|
-
)
|
|
1479
|
-
skills_needed = bool(skill_activation_decision.get("skills_needed"))
|
|
1480
|
-
skills_needed_reason = str(skill_activation_decision.get("reason") or "unspecified")
|
|
1481
|
-
recommended_skill_names: list[str] = []
|
|
1482
|
-
if skills_needed and skills_available and skills_toolset_enabled:
|
|
1483
|
-
recommended_skill_names = self._recommend_skills_for_state_context(
|
|
1484
|
-
state_context=state_context,
|
|
1485
|
-
available_skill_names=available_skill_names,
|
|
1486
|
-
limit=3,
|
|
1487
|
-
)
|
|
1488
|
-
if recommended_skill_names:
|
|
1489
|
-
toolsets, removed_skill_entries = self._focus_skills_in_toolsets(toolsets, recommended_skill_names)
|
|
1490
|
-
if removed_skill_entries > 0:
|
|
1491
|
-
available_skill_names = self._collect_available_skill_names(toolsets)
|
|
1492
|
-
skills_available = len(available_skill_names) > 0
|
|
1493
|
-
preloaded_skill_context, preloaded_skill_names = self._build_preloaded_skill_context(
|
|
1494
|
-
toolsets=toolsets,
|
|
1495
|
-
available_skill_names=available_skill_names,
|
|
1496
|
-
max_skills=1 if local_openai_protocol else 2,
|
|
1497
|
-
max_chars_per_skill=500 if local_openai_protocol else 1400,
|
|
1498
|
-
preferred_skill_names=recommended_skill_names,
|
|
1499
|
-
)
|
|
1500
|
-
self.logger.info(
|
|
1501
|
-
"agentic_skill_allowlist_focused",
|
|
1502
|
-
recommended_skill_names=recommended_skill_names,
|
|
1503
|
-
removed_skill_entries=removed_skill_entries,
|
|
1504
|
-
available_skill_count=len(available_skill_names),
|
|
1505
|
-
)
|
|
1506
|
-
if preloaded_skill_names:
|
|
1507
|
-
self.logger.info(
|
|
1508
|
-
"agentic_skill_bootstrap_preloaded",
|
|
1509
|
-
preloaded_skill_count=len(preloaded_skill_names),
|
|
1510
|
-
preloaded_skill_names=preloaded_skill_names,
|
|
1511
|
-
preloaded_skill_chars=len(preloaded_skill_context),
|
|
1512
|
-
source="focused",
|
|
1513
|
-
)
|
|
1514
|
-
advisory_skill_sequence_skipped = bool(
|
|
1515
|
-
skills_needed
|
|
1516
|
-
and skills_available
|
|
1517
|
-
and skills_toolset_enabled
|
|
1518
|
-
and (not strict_require_effective_skill)
|
|
1519
|
-
and self._should_skip_advisory_skill_sequence(
|
|
1520
|
-
state_context=state_context,
|
|
1521
|
-
interpretation=interpretation,
|
|
1522
|
-
)
|
|
1523
|
-
)
|
|
1524
|
-
if advisory_skill_sequence_skipped:
|
|
1525
|
-
toolsets, removed_skill_tool_bindings = self._remove_tool_names(toolsets, self._SKILL_TOOL_NAMES)
|
|
1526
|
-
skills_toolset_enabled = False
|
|
1527
|
-
available_skill_names = self._collect_available_skill_names(toolsets)
|
|
1528
|
-
skills_available = len(available_skill_names) > 0
|
|
1529
|
-
preloaded_skill_context = ""
|
|
1530
|
-
preloaded_skill_names = []
|
|
1531
|
-
self.logger.info(
|
|
1532
|
-
"agentic_advisory_skill_tools_suppressed",
|
|
1533
|
-
removed_tool_bindings=removed_skill_tool_bindings,
|
|
1534
|
-
skills_needed=skills_needed,
|
|
1535
|
-
strict_require_effective_skill=strict_require_effective_skill,
|
|
1536
|
-
skills_available_after_filter=skills_available,
|
|
1537
|
-
)
|
|
1538
|
-
self.logger.info(
|
|
1539
|
-
"agentic_skill_activation_decision",
|
|
1540
|
-
skills_needed=skills_needed,
|
|
1541
|
-
skills_needed_reason=skills_needed_reason,
|
|
1542
|
-
decision_source=str(skill_activation_decision.get("decision_source") or "unknown"),
|
|
1543
|
-
skills_available=skills_available,
|
|
1544
|
-
skills_toolset_enabled=skills_toolset_enabled,
|
|
1545
|
-
strict_no_fallback=strict_no_fallback,
|
|
1546
|
-
advisory_skill_sequence_skipped=advisory_skill_sequence_skipped,
|
|
1547
|
-
recommended_skill_names=recommended_skill_names,
|
|
1548
|
-
requirement_interpretation_present=bool(interpretation),
|
|
1549
|
-
)
|
|
1550
|
-
# Strict mode can optionally enforce an effective skill call, but this is now
|
|
1551
|
-
# configurable so requirement-driven runs can avoid low-value skill churn.
|
|
1552
|
-
skills_required = bool(
|
|
1553
|
-
strict_no_fallback
|
|
1554
|
-
and skills_available
|
|
1555
|
-
and skills_toolset_enabled
|
|
1556
|
-
and strict_require_effective_skill
|
|
1557
|
-
and skills_needed
|
|
1558
|
-
)
|
|
1559
|
-
|
|
1560
|
-
user_prompt = self._build_agentic_investigation_prompt(
|
|
1561
|
-
evidence=evidence,
|
|
1562
|
-
profile=profile,
|
|
1563
|
-
repo_path=repo_path,
|
|
1564
|
-
evidence_corpus=deps.evidence_corpus,
|
|
1565
|
-
skills_available=skills_available,
|
|
1566
|
-
available_skill_names=available_skill_names,
|
|
1567
|
-
vector_docs_required=vector_docs_required,
|
|
1568
|
-
preloaded_skill_context=preloaded_skill_context,
|
|
1569
|
-
postgres_evidence_ready=postgres_evidence_ready,
|
|
1570
|
-
compact_mode=local_openai_protocol,
|
|
1571
|
-
strict_skill_required=skills_required,
|
|
1572
|
-
skills_needed=skills_needed,
|
|
1573
|
-
skills_needed_reason=skills_needed_reason,
|
|
1574
|
-
)
|
|
1575
|
-
|
|
1576
|
-
self.logger.info(
|
|
1577
|
-
"agentic_analysis_started",
|
|
1578
|
-
repo_path=str(repo_path),
|
|
1579
|
-
toolset_count=len(toolsets),
|
|
1580
|
-
base_toolsets=len(base_toolsets),
|
|
1581
|
-
agentic_toolsets=len(agentic_toolsets),
|
|
1582
|
-
max_turns=max_turns,
|
|
1583
|
-
max_tool_calls=max_tool_calls,
|
|
1584
|
-
tool_timeout_sec=tool_timeout_sec,
|
|
1585
|
-
)
|
|
1586
|
-
system_prompt = (
|
|
1587
|
-
AGENTIC_CODE_ANALYSIS_SYSTEM_PROMPT_OLLAMA_COMPACT
|
|
1588
|
-
if local_openai_protocol
|
|
1589
|
-
else AGENTIC_CODE_ANALYSIS_SYSTEM_PROMPT
|
|
1590
|
-
)
|
|
1591
|
-
|
|
1592
|
-
start_time = time.monotonic()
|
|
1593
|
-
if local_openai_protocol and strict_no_fallback:
|
|
1594
|
-
retry_turn_cap = max(max_turns + 2, int(max_turns * 1.25))
|
|
1595
|
-
retry_tool_call_cap = max(max_tool_calls + 6, int(max_tool_calls * 1.25))
|
|
1596
|
-
else:
|
|
1597
|
-
retry_turn_cap = max(max_turns + 6, int(max_turns * 1.5))
|
|
1598
|
-
retry_tool_call_cap = max(max_tool_calls + 24, int(max_tool_calls * 1.5))
|
|
1599
|
-
aggregate_retry_telemetry: dict[str, Any] = {}
|
|
1600
|
-
corrective_budget_initial = max(
|
|
1601
|
-
0,
|
|
1602
|
-
int(
|
|
1603
|
-
runtime.get(
|
|
1604
|
-
"corrective_budget_remaining",
|
|
1605
|
-
runtime.get("corrective_budget_initial", 5),
|
|
1606
|
-
)
|
|
1607
|
-
),
|
|
1608
|
-
)
|
|
1609
|
-
corrective_budget_remaining = corrective_budget_initial
|
|
1610
|
-
corrective_budget_events: list[dict[str, Any]] = []
|
|
1611
|
-
corrective_budget_exhausted = corrective_budget_remaining <= 0
|
|
1612
|
-
local_openai_hard_synthesis_used = False
|
|
1613
|
-
strict_budget_hard_synthesis_used = False
|
|
1614
|
-
hard_synthesis_quality_retry_used = False
|
|
1615
|
-
|
|
1616
|
-
def _sync_corrective_budget_telemetry(target: dict[str, Any]) -> None:
|
|
1617
|
-
if not isinstance(target, dict):
|
|
1618
|
-
return
|
|
1619
|
-
target["corrective_budget_initial"] = corrective_budget_initial
|
|
1620
|
-
target["corrective_budget_remaining"] = corrective_budget_remaining
|
|
1621
|
-
target["corrective_budget_consumed"] = max(0, corrective_budget_initial - corrective_budget_remaining)
|
|
1622
|
-
target["corrective_budget_exhausted"] = bool(corrective_budget_exhausted)
|
|
1623
|
-
target["corrective_budget_events"] = [dict(entry) for entry in corrective_budget_events]
|
|
1624
|
-
|
|
1625
|
-
def _record_corrective_budget_event(
|
|
1626
|
-
event_name: str,
|
|
1627
|
-
*,
|
|
1628
|
-
guard_class: str | None = None,
|
|
1629
|
-
reason: str | None = None,
|
|
1630
|
-
) -> None:
|
|
1631
|
-
entry: dict[str, Any] = {
|
|
1632
|
-
"event": str(event_name),
|
|
1633
|
-
"remaining": corrective_budget_remaining,
|
|
1634
|
-
"consumed": max(0, corrective_budget_initial - corrective_budget_remaining),
|
|
1635
|
-
}
|
|
1636
|
-
if guard_class:
|
|
1637
|
-
entry["guard_class"] = str(guard_class)
|
|
1638
|
-
if reason:
|
|
1639
|
-
entry["reason"] = str(reason)
|
|
1640
|
-
corrective_budget_events.append(entry)
|
|
1641
|
-
_sync_corrective_budget_telemetry(aggregate_retry_telemetry)
|
|
1642
|
-
|
|
1643
|
-
def _consume_corrective_budget(
|
|
1644
|
-
*,
|
|
1645
|
-
guard_class: str,
|
|
1646
|
-
reason: str,
|
|
1647
|
-
) -> bool:
|
|
1648
|
-
nonlocal corrective_budget_remaining
|
|
1649
|
-
nonlocal corrective_budget_exhausted
|
|
1650
|
-
if corrective_budget_remaining <= 0:
|
|
1651
|
-
corrective_budget_exhausted = True
|
|
1652
|
-
_record_corrective_budget_event(
|
|
1653
|
-
"exhausted",
|
|
1654
|
-
guard_class=guard_class,
|
|
1655
|
-
reason=reason,
|
|
1656
|
-
)
|
|
1657
|
-
self.logger.warning(
|
|
1658
|
-
"agentic_corrective_budget_exhausted",
|
|
1659
|
-
guard_class=guard_class,
|
|
1660
|
-
reason=reason,
|
|
1661
|
-
corrective_budget_initial=corrective_budget_initial,
|
|
1662
|
-
corrective_budget_remaining=corrective_budget_remaining,
|
|
1663
|
-
corrective_budget_consumed=max(0, corrective_budget_initial - corrective_budget_remaining),
|
|
1664
|
-
)
|
|
1665
|
-
return False
|
|
1666
|
-
corrective_budget_remaining = max(0, corrective_budget_remaining - 1)
|
|
1667
|
-
corrective_budget_exhausted = corrective_budget_remaining <= 0
|
|
1668
|
-
_record_corrective_budget_event(
|
|
1669
|
-
"consumed",
|
|
1670
|
-
guard_class=guard_class,
|
|
1671
|
-
reason=reason,
|
|
1672
|
-
)
|
|
1673
|
-
self.logger.info(
|
|
1674
|
-
"agentic_corrective_budget_consumed",
|
|
1675
|
-
guard_class=guard_class,
|
|
1676
|
-
reason=reason,
|
|
1677
|
-
corrective_budget_initial=corrective_budget_initial,
|
|
1678
|
-
corrective_budget_remaining=corrective_budget_remaining,
|
|
1679
|
-
corrective_budget_consumed=max(0, corrective_budget_initial - corrective_budget_remaining),
|
|
1680
|
-
corrective_budget_exhausted=corrective_budget_exhausted,
|
|
1681
|
-
)
|
|
1682
|
-
if corrective_budget_exhausted:
|
|
1683
|
-
_record_corrective_budget_event(
|
|
1684
|
-
"exhausted",
|
|
1685
|
-
guard_class=guard_class,
|
|
1686
|
-
reason=reason,
|
|
1687
|
-
)
|
|
1688
|
-
self.logger.warning(
|
|
1689
|
-
"agentic_corrective_budget_exhausted",
|
|
1690
|
-
guard_class=guard_class,
|
|
1691
|
-
reason=reason,
|
|
1692
|
-
corrective_budget_initial=corrective_budget_initial,
|
|
1693
|
-
corrective_budget_remaining=corrective_budget_remaining,
|
|
1694
|
-
corrective_budget_consumed=max(0, corrective_budget_initial - corrective_budget_remaining),
|
|
1695
|
-
)
|
|
1696
|
-
return True
|
|
1697
|
-
|
|
1698
|
-
def _build_corrective_budget_degraded_output(
|
|
1699
|
-
*,
|
|
1700
|
-
guard_class: str,
|
|
1701
|
-
reason: str,
|
|
1702
|
-
output_hint: CodeFindings | None,
|
|
1703
|
-
telemetry_hint: dict[str, Any] | None,
|
|
1704
|
-
) -> CodeFindings:
|
|
1705
|
-
tool_count_by_name = (
|
|
1706
|
-
telemetry_hint.get("event_tool_count_by_name") if isinstance(telemetry_hint, dict) else {}
|
|
1707
|
-
)
|
|
1708
|
-
read_file_calls = (
|
|
1709
|
-
int(tool_count_by_name.get("read_file", 0) or 0) if isinstance(tool_count_by_name, dict) else 0
|
|
1710
|
-
)
|
|
1711
|
-
base_reasoning = str(getattr(output_hint, "reasoning", "") or "").strip()
|
|
1712
|
-
bounded_reasoning = base_reasoning[:320]
|
|
1713
|
-
score_hint = float(getattr(output_hint, "score", 0.0) or 0.0) if output_hint is not None else 0.0
|
|
1714
|
-
confidence_hint = float(getattr(output_hint, "confidence", 0.4) or 0.4) if output_hint is not None else 0.4
|
|
1715
|
-
files_analyzed_hint = int(getattr(output_hint, "files_analyzed", 0) or 0) if output_hint is not None else 0
|
|
1716
|
-
files_analyzed = max(files_analyzed_hint, read_file_calls, 0)
|
|
1717
|
-
issues = list(getattr(output_hint, "issues", []) or [])[:10] if output_hint is not None else []
|
|
1718
|
-
patterns = list(getattr(output_hint, "patterns", []) or [])[:10] if output_hint is not None else []
|
|
1719
|
-
tech_stack = (
|
|
1720
|
-
[str(item) for item in (getattr(output_hint, "tech_stack", []) or []) if str(item)][:10]
|
|
1721
|
-
if output_hint is not None
|
|
1722
|
-
else []
|
|
1723
|
-
)
|
|
1724
|
-
reasoning = (
|
|
1725
|
-
"Degraded finalize: corrective budget exhausted; returning bounded grounded partial output. "
|
|
1726
|
-
f"guard={guard_class}; reason={reason}."
|
|
1727
|
-
)
|
|
1728
|
-
if bounded_reasoning:
|
|
1729
|
-
reasoning = f"{reasoning} Prior synthesis: {bounded_reasoning}"
|
|
1730
|
-
return CodeFindings(
|
|
1731
|
-
score=max(0.0, min(score_hint, 10.0)),
|
|
1732
|
-
confidence=max(0.0, min(confidence_hint, 1.0)),
|
|
1733
|
-
issues=issues,
|
|
1734
|
-
patterns=patterns,
|
|
1735
|
-
reasoning=reasoning,
|
|
1736
|
-
files_analyzed=files_analyzed,
|
|
1737
|
-
tech_stack=tech_stack,
|
|
1738
|
-
)
|
|
1739
|
-
|
|
1740
|
-
def _degraded_finalize_for_corrective_budget(
|
|
1741
|
-
*,
|
|
1742
|
-
guard_class: str,
|
|
1743
|
-
reason: str,
|
|
1744
|
-
output_hint: CodeFindings | None,
|
|
1745
|
-
telemetry_hint: dict[str, Any] | None,
|
|
1746
|
-
) -> CodeFindings:
|
|
1747
|
-
_record_corrective_budget_event(
|
|
1748
|
-
"degraded_finalize",
|
|
1749
|
-
guard_class=guard_class,
|
|
1750
|
-
reason=reason,
|
|
1751
|
-
)
|
|
1752
|
-
degraded_output = _build_corrective_budget_degraded_output(
|
|
1753
|
-
guard_class=guard_class,
|
|
1754
|
-
reason=reason,
|
|
1755
|
-
output_hint=output_hint,
|
|
1756
|
-
telemetry_hint=telemetry_hint,
|
|
1757
|
-
)
|
|
1758
|
-
self.logger.warning(
|
|
1759
|
-
"agentic_corrective_budget_degraded_finalize",
|
|
1760
|
-
guard_class=guard_class,
|
|
1761
|
-
reason=reason,
|
|
1762
|
-
corrective_budget_initial=corrective_budget_initial,
|
|
1763
|
-
corrective_budget_remaining=corrective_budget_remaining,
|
|
1764
|
-
corrective_budget_consumed=max(0, corrective_budget_initial - corrective_budget_remaining),
|
|
1765
|
-
corrective_budget_exhausted=corrective_budget_exhausted,
|
|
1766
|
-
observed_tool_names=(
|
|
1767
|
-
telemetry_hint.get("event_tool_names") if isinstance(telemetry_hint, dict) else None
|
|
1768
|
-
),
|
|
1769
|
-
)
|
|
1770
|
-
_sync_corrective_budget_telemetry(aggregate_retry_telemetry)
|
|
1771
|
-
if isinstance(aggregate_retry_telemetry, dict):
|
|
1772
|
-
self._last_agent_run_telemetry = dict(aggregate_retry_telemetry)
|
|
1773
|
-
return degraded_output
|
|
1774
|
-
|
|
1775
|
-
_record_corrective_budget_event("initialized")
|
|
1776
|
-
self.logger.info(
|
|
1777
|
-
"agentic_corrective_budget_initialized",
|
|
1778
|
-
corrective_budget_initial=corrective_budget_initial,
|
|
1779
|
-
corrective_budget_remaining=corrective_budget_remaining,
|
|
1780
|
-
corrective_budget_consumed=0,
|
|
1781
|
-
corrective_budget_exhausted=corrective_budget_exhausted,
|
|
1782
|
-
)
|
|
1783
|
-
|
|
1784
|
-
def _update_cadence_from_telemetry(
|
|
1785
|
-
telemetry_snapshot: dict[str, Any] | None,
|
|
1786
|
-
*,
|
|
1787
|
-
row_index: int | None = None,
|
|
1788
|
-
) -> None:
|
|
1789
|
-
"""Update cadence_policy from aggregate telemetry tool counts (FR-120)."""
|
|
1790
|
-
nonlocal cadence_policy
|
|
1791
|
-
if not isinstance(telemetry_snapshot, dict):
|
|
1792
|
-
return
|
|
1793
|
-
tool_count_by_name = telemetry_snapshot.get("event_tool_count_by_name")
|
|
1794
|
-
if not isinstance(tool_count_by_name, dict) or not tool_count_by_name:
|
|
1795
|
-
return
|
|
1796
|
-
for t_name, count in tool_count_by_name.items():
|
|
1797
|
-
if not isinstance(t_name, str) or t_name == "final_result":
|
|
1798
|
-
continue
|
|
1799
|
-
result_useful = int(count or 0) > 0
|
|
1800
|
-
previous_ceiling = cadence_policy.tool_family_ceilings.get(t_name, cadence_policy.base_tool_budget)
|
|
1801
|
-
cadence_policy = ToolEfficiencyGuard.update_tool_signal(cadence_policy, t_name, result_useful)
|
|
1802
|
-
new_ceiling = cadence_policy.tool_family_ceilings.get(t_name, cadence_policy.base_tool_budget)
|
|
1803
|
-
if new_ceiling != previous_ceiling:
|
|
1804
|
-
cadence_event = ToolEfficiencyGuard.build_cadence_telemetry(
|
|
1805
|
-
cadence_policy,
|
|
1806
|
-
t_name,
|
|
1807
|
-
previous_ceiling,
|
|
1808
|
-
"snr_adjustment",
|
|
1809
|
-
row_index=row_index,
|
|
1810
|
-
)
|
|
1811
|
-
cadence_event_name = str(cadence_event.get("event") or "cadence_ceiling_adjusted")
|
|
1812
|
-
cadence_event_payload = {k: v for k, v in cadence_event.items() if k != "event"}
|
|
1813
|
-
self.logger.info(
|
|
1814
|
-
cadence_event_name,
|
|
1815
|
-
**cadence_event_payload,
|
|
1816
|
-
)
|
|
1817
|
-
|
|
1818
|
-
async def _invoke_agentic(
|
|
1819
|
-
user_prompt_payload: str,
|
|
1820
|
-
turns: int,
|
|
1821
|
-
tool_calls_limit: int,
|
|
1822
|
-
*,
|
|
1823
|
-
active_toolsets: list[Any],
|
|
1824
|
-
) -> CodeFindings:
|
|
1825
|
-
nonlocal skills_available
|
|
1826
|
-
nonlocal skills_required
|
|
1827
|
-
nonlocal aggregate_retry_telemetry
|
|
1828
|
-
nonlocal local_openai_hard_synthesis_used
|
|
1829
|
-
nonlocal strict_budget_hard_synthesis_used
|
|
1830
|
-
nonlocal cadence_policy
|
|
1831
|
-
|
|
1832
|
-
current_turns = turns
|
|
1833
|
-
current_tool_calls = tool_calls_limit
|
|
1834
|
-
current_toolsets = list(active_toolsets)
|
|
1835
|
-
current_prompt = user_prompt_payload
|
|
1836
|
-
used_invalid_tool_args_retry = False
|
|
1837
|
-
used_invalid_tool_usage_retry = False
|
|
1838
|
-
used_missing_skill_script_retry = False
|
|
1839
|
-
used_missing_skill_resource_retry = False
|
|
1840
|
-
used_missing_skill_name_retry = False
|
|
1841
|
-
used_request_limit_synthesis_retry = False
|
|
1842
|
-
used_stall_synthesis_retry = False
|
|
1843
|
-
used_strict_budget_synthesis_retry = False
|
|
1844
|
-
used_strict_budget_hard_synthesis_retry = False
|
|
1845
|
-
used_non_progress_final_retry = False
|
|
1846
|
-
used_list_directory_synthesis_retry = False
|
|
1847
|
-
used_output_validation_synthesis_retry = False
|
|
1848
|
-
budget_retry_attempts = 0
|
|
1849
|
-
synthesis_tool_allowlist = [
|
|
1850
|
-
"read_file",
|
|
1851
|
-
"read_evidence_document",
|
|
1852
|
-
"list_evidence_documents",
|
|
1853
|
-
"search_evidence",
|
|
1854
|
-
"search_evidence_vector",
|
|
1855
|
-
"search_code_vector",
|
|
1856
|
-
]
|
|
1857
|
-
|
|
1858
|
-
def _to_synthesis_toolset(active_toolsets: list[Any]) -> list[Any]:
|
|
1859
|
-
"""Keep a tiny read-focused toolset to avoid zero-tool deadlocks."""
|
|
1860
|
-
reduced = self._apply_tool_allowlist(list(active_toolsets), synthesis_tool_allowlist)
|
|
1861
|
-
return reduced if reduced else []
|
|
1862
|
-
|
|
1863
|
-
def _synthesis_retry_caps(has_toolsets: bool) -> tuple[int, int]:
|
|
1864
|
-
if local_openai_protocol and strict_no_fallback:
|
|
1865
|
-
turns_cap = max(1, local_openai_synthesis_max_turns)
|
|
1866
|
-
if has_toolsets:
|
|
1867
|
-
tools_cap = max(0, local_openai_synthesis_max_tool_calls)
|
|
1868
|
-
else:
|
|
1869
|
-
tools_cap = max(0, min(local_openai_synthesis_max_tool_calls, 1))
|
|
1870
|
-
return turns_cap, tools_cap
|
|
1871
|
-
return 4, (8 if has_toolsets else 4)
|
|
1872
|
-
|
|
1873
|
-
# Local OpenAI-compatible runtimes can repeat low-signal tool loops.
|
|
1874
|
-
# Keep retries bounded more aggressively to avoid long runaway cycles.
|
|
1875
|
-
if strict_no_fallback:
|
|
1876
|
-
max_budget_retry_attempts = 0
|
|
1877
|
-
elif local_openai_protocol:
|
|
1878
|
-
max_budget_retry_attempts = 1
|
|
1879
|
-
else:
|
|
1880
|
-
max_budget_retry_attempts = 2
|
|
1881
|
-
|
|
1882
|
-
while True:
|
|
1883
|
-
try:
|
|
1884
|
-
output = await self._run_pydantic_agent(
|
|
1885
|
-
system_prompt=system_prompt,
|
|
1886
|
-
user_prompt=current_prompt,
|
|
1887
|
-
result_type=CodeFindings,
|
|
1888
|
-
complexity="standard",
|
|
1889
|
-
deps=deps,
|
|
1890
|
-
toolsets=current_toolsets,
|
|
1891
|
-
max_turns=current_turns,
|
|
1892
|
-
max_tool_calls=current_tool_calls,
|
|
1893
|
-
pre_retry_telemetry=aggregate_retry_telemetry
|
|
1894
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
1895
|
-
else None,
|
|
1896
|
-
)
|
|
1897
|
-
latest_telemetry = getattr(self, "_last_agent_run_telemetry", {})
|
|
1898
|
-
if isinstance(latest_telemetry, dict):
|
|
1899
|
-
aggregate_retry_telemetry = self._merge_retry_telemetry(
|
|
1900
|
-
aggregate_retry_telemetry,
|
|
1901
|
-
latest_telemetry,
|
|
1902
|
-
)
|
|
1903
|
-
_sync_corrective_budget_telemetry(aggregate_retry_telemetry)
|
|
1904
|
-
_update_cadence_from_telemetry(latest_telemetry)
|
|
1905
|
-
return output
|
|
1906
|
-
except Exception as exc:
|
|
1907
|
-
latest_telemetry = getattr(self, "_last_agent_run_telemetry", {})
|
|
1908
|
-
if isinstance(latest_telemetry, dict):
|
|
1909
|
-
aggregate_retry_telemetry = self._merge_retry_telemetry(
|
|
1910
|
-
aggregate_retry_telemetry, latest_telemetry
|
|
1911
|
-
)
|
|
1912
|
-
_sync_corrective_budget_telemetry(aggregate_retry_telemetry)
|
|
1913
|
-
_update_cadence_from_telemetry(latest_telemetry)
|
|
1914
|
-
message = str(exc).lower()
|
|
1915
|
-
invalid_tool_args = "invalid tool call arguments" in message
|
|
1916
|
-
if invalid_tool_args and not used_invalid_tool_args_retry:
|
|
1917
|
-
# Retry once with stricter instructions but keep skill toolsets enabled.
|
|
1918
|
-
self.logger.warning(
|
|
1919
|
-
"agentic_invalid_tool_args_retry_with_skills",
|
|
1920
|
-
error=str(exc),
|
|
1921
|
-
toolsets=len(current_toolsets),
|
|
1922
|
-
)
|
|
1923
|
-
used_invalid_tool_args_retry = True
|
|
1924
|
-
current_prompt = (
|
|
1925
|
-
user_prompt_payload
|
|
1926
|
-
+ "\n\nTOOL ARGUMENT GUARD:\n"
|
|
1927
|
-
+ "- Call one tool per turn.\n"
|
|
1928
|
-
+ "- Provide a valid JSON object for tool args.\n"
|
|
1929
|
-
+ "- Keep skill tools enabled and use them when relevant."
|
|
1930
|
-
)
|
|
1931
|
-
continue
|
|
1932
|
-
|
|
1933
|
-
invalid_tool_usage = self._is_invalid_tool_usage_error(message)
|
|
1934
|
-
if invalid_tool_usage and not used_invalid_tool_usage_retry:
|
|
1935
|
-
attempted_tool = self._parse_tool_name_from_invalid_tool_error(str(exc))
|
|
1936
|
-
self.logger.warning(
|
|
1937
|
-
"agentic_invalid_tool_usage_allowlist",
|
|
1938
|
-
error=str(exc),
|
|
1939
|
-
attempted_tool=attempted_tool,
|
|
1940
|
-
allowed_tools=tool_allowlist,
|
|
1941
|
-
)
|
|
1942
|
-
used_invalid_tool_usage_retry = True
|
|
1943
|
-
current_prompt = self._build_tool_allowlist_guard_prompt(
|
|
1944
|
-
user_prompt_payload,
|
|
1945
|
-
allowed_tools=tool_allowlist,
|
|
1946
|
-
attempted_tool=attempted_tool,
|
|
1947
|
-
)
|
|
1948
|
-
continue
|
|
1949
|
-
if invalid_tool_usage:
|
|
1950
|
-
attempted_tool = self._parse_tool_name_from_invalid_tool_error(str(exc))
|
|
1951
|
-
raise RuntimeError(
|
|
1952
|
-
"agentic tool policy violation: invalid tool usage "
|
|
1953
|
-
f"(attempted={attempted_tool or 'unknown'}, allowlist={tool_allowlist})"
|
|
1954
|
-
) from exc
|
|
1955
|
-
|
|
1956
|
-
missing_skill_script = "script '" in message and "not found in skill" in message
|
|
1957
|
-
if missing_skill_script and not used_missing_skill_script_retry:
|
|
1958
|
-
failing_skill = self._parse_skill_name_from_error(str(exc))
|
|
1959
|
-
updated_toolsets, removed_count = self._drop_skill_from_toolsets(
|
|
1960
|
-
current_toolsets,
|
|
1961
|
-
failing_skill or "",
|
|
1962
|
-
)
|
|
1963
|
-
self.logger.warning(
|
|
1964
|
-
"agentic_missing_skill_script_retry_degraded_skill",
|
|
1965
|
-
error=str(exc),
|
|
1966
|
-
failing_skill=failing_skill,
|
|
1967
|
-
removed_toolsets=removed_count,
|
|
1968
|
-
)
|
|
1969
|
-
used_missing_skill_script_retry = True
|
|
1970
|
-
current_toolsets = updated_toolsets
|
|
1971
|
-
if failing_skill:
|
|
1972
|
-
available_skill_names[:] = [name for name in available_skill_names if name != failing_skill]
|
|
1973
|
-
skills_available = len(available_skill_names) > 0
|
|
1974
|
-
if not skills_available:
|
|
1975
|
-
skills_required = False
|
|
1976
|
-
current_prompt = (
|
|
1977
|
-
user_prompt_payload
|
|
1978
|
-
+ "\n\nSKILL SCRIPT GUARD:\n"
|
|
1979
|
-
+ "- Do not call run_skill_script unless the selected skill explicitly lists scripts.\n"
|
|
1980
|
-
+ "- Use load_skill and read_skill_resource for skills that have no scripts.\n"
|
|
1981
|
-
+ "- Continue with filesystem/LSP tools for repository evidence."
|
|
1982
|
-
)
|
|
1983
|
-
continue
|
|
1984
|
-
|
|
1985
|
-
missing_skill_resource = "resource '" in message and "not found in skill" in message
|
|
1986
|
-
if missing_skill_resource and not used_missing_skill_resource_retry:
|
|
1987
|
-
failing_skill = self._parse_skill_name_from_error(str(exc))
|
|
1988
|
-
updated_toolsets, removed_count = self._drop_skill_from_toolsets(
|
|
1989
|
-
current_toolsets,
|
|
1990
|
-
failing_skill or "",
|
|
1991
|
-
)
|
|
1992
|
-
self.logger.warning(
|
|
1993
|
-
"agentic_missing_skill_resource_retry_degraded_skill",
|
|
1994
|
-
error=str(exc),
|
|
1995
|
-
failing_skill=failing_skill,
|
|
1996
|
-
removed_toolsets=removed_count,
|
|
1997
|
-
)
|
|
1998
|
-
used_missing_skill_resource_retry = True
|
|
1999
|
-
current_toolsets = updated_toolsets
|
|
2000
|
-
if failing_skill:
|
|
2001
|
-
available_skill_names[:] = [name for name in available_skill_names if name != failing_skill]
|
|
2002
|
-
skills_available = len(available_skill_names) > 0
|
|
2003
|
-
if not available_skill_names:
|
|
2004
|
-
skills_required = False
|
|
2005
|
-
current_prompt = (
|
|
2006
|
-
user_prompt_payload
|
|
2007
|
-
+ "\n\nSKILL RESOURCE GUARD:\n"
|
|
2008
|
-
+ "- A referenced skill/resource is missing; skip that skill and continue.\n"
|
|
2009
|
-
+ "- Use filesystem/LSP tools for repository evidence.\n"
|
|
2010
|
-
+ "- Call load_skill first, then call read_skill_resource only for resource_name values listed in load_skill output."
|
|
2011
|
-
)
|
|
2012
|
-
continue
|
|
2013
|
-
|
|
2014
|
-
missing_skill_name = "skill '" in message and "not found. available:" in message
|
|
2015
|
-
if missing_skill_name and not used_missing_skill_name_retry:
|
|
2016
|
-
failing_skill = self._parse_skill_name_from_error(str(exc))
|
|
2017
|
-
updated_toolsets, removed_count = self._drop_skill_from_toolsets(
|
|
2018
|
-
current_toolsets,
|
|
2019
|
-
failing_skill or "",
|
|
2020
|
-
)
|
|
2021
|
-
self.logger.warning(
|
|
2022
|
-
"agentic_missing_skill_name_retry_degraded_skill",
|
|
2023
|
-
error=str(exc),
|
|
2024
|
-
failing_skill=failing_skill,
|
|
2025
|
-
removed_toolsets=removed_count,
|
|
2026
|
-
)
|
|
2027
|
-
used_missing_skill_name_retry = True
|
|
2028
|
-
current_toolsets = updated_toolsets
|
|
2029
|
-
if failing_skill:
|
|
2030
|
-
available_skill_names[:] = [name for name in available_skill_names if name != failing_skill]
|
|
2031
|
-
skills_available = len(available_skill_names) > 0
|
|
2032
|
-
if not available_skill_names:
|
|
2033
|
-
skills_required = False
|
|
2034
|
-
current_prompt = (
|
|
2035
|
-
user_prompt_payload
|
|
2036
|
-
+ "\n\nSKILL AVAILABILITY GUARD:\n"
|
|
2037
|
-
+ f"- Available skills now: {', '.join(available_skill_names) if available_skill_names else 'none'}.\n"
|
|
2038
|
-
+ "- Do not call load_skill for skills outside this list.\n"
|
|
2039
|
-
+ "- Continue with filesystem/LSP tools if a skill is unavailable."
|
|
2040
|
-
)
|
|
2041
|
-
continue
|
|
2042
|
-
|
|
2043
|
-
stall_after_tools = "stalled after tool activity" in message
|
|
2044
|
-
if stall_after_tools and not used_stall_synthesis_retry:
|
|
2045
|
-
self.logger.warning(
|
|
2046
|
-
"agentic_stall_synthesis_retry",
|
|
2047
|
-
error=str(exc),
|
|
2048
|
-
max_turns=current_turns,
|
|
2049
|
-
max_tool_calls=current_tool_calls,
|
|
2050
|
-
observed_tool_names=(
|
|
2051
|
-
aggregate_retry_telemetry.get("event_tool_names")
|
|
2052
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2053
|
-
else None
|
|
2054
|
-
),
|
|
2055
|
-
)
|
|
2056
|
-
used_stall_synthesis_retry = True
|
|
2057
|
-
current_prompt = (
|
|
2058
|
-
user_prompt_payload
|
|
2059
|
-
+ "\n\nSTALL RECOVERY - FINAL SYNTHESIS MODE:\n"
|
|
2060
|
-
+ "- STOP calling tools.\n"
|
|
2061
|
-
+ "- Use at most 1-2 focused read/list calls if essential, then finalize.\n"
|
|
2062
|
-
+ "- Do not run broad grep/list loops.\n"
|
|
2063
|
-
+ "- Return final CodeFindings JSON now."
|
|
2064
|
-
)
|
|
2065
|
-
current_toolsets = _to_synthesis_toolset(current_toolsets)
|
|
2066
|
-
synthesis_turns, synthesis_tools = _synthesis_retry_caps(bool(current_toolsets))
|
|
2067
|
-
current_tool_calls = synthesis_tools
|
|
2068
|
-
current_turns = min(current_turns, synthesis_turns)
|
|
2069
|
-
continue
|
|
2070
|
-
|
|
2071
|
-
if self._is_output_validation_retry_error(exc) and not used_output_validation_synthesis_retry:
|
|
2072
|
-
self.logger.warning(
|
|
2073
|
-
"agentic_output_validation_hard_synthesis_retry",
|
|
2074
|
-
error=str(exc),
|
|
2075
|
-
max_turns=current_turns,
|
|
2076
|
-
max_tool_calls=current_tool_calls,
|
|
2077
|
-
)
|
|
2078
|
-
used_output_validation_synthesis_retry = True
|
|
2079
|
-
current_prompt = (
|
|
2080
|
-
user_prompt_payload
|
|
2081
|
-
+ "\n\nOUTPUT VALIDATION RECOVERY - HARD SYNTHESIS MODE:\n"
|
|
2082
|
-
+ "- DO NOT call tools.\n"
|
|
2083
|
-
+ "- Return only final CodeFindings JSON matching the schema.\n"
|
|
2084
|
-
+ "- Use evidence already collected in prior turns.\n"
|
|
2085
|
-
)
|
|
2086
|
-
current_toolsets = []
|
|
2087
|
-
# Keep a tiny allowance to avoid tool_calls_limit=0 deadlocks
|
|
2088
|
-
# when providers emit one residual internal tool/final_result call.
|
|
2089
|
-
current_tool_calls = max(1, local_openai_hard_synthesis_max_tool_calls)
|
|
2090
|
-
current_turns = min(current_turns, max(2, local_openai_hard_synthesis_max_turns))
|
|
2091
|
-
continue
|
|
2092
|
-
|
|
2093
|
-
if not self._is_usage_limit_error(exc):
|
|
2094
|
-
raise
|
|
2095
|
-
|
|
2096
|
-
telemetry_loop = (
|
|
2097
|
-
latest_telemetry
|
|
2098
|
-
if isinstance(latest_telemetry, dict) and latest_telemetry
|
|
2099
|
-
else (
|
|
2100
|
-
aggregate_retry_telemetry
|
|
2101
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2102
|
-
else None
|
|
2103
|
-
)
|
|
2104
|
-
)
|
|
2105
|
-
if "tool_calls_limit" in message and self._is_list_directory_churn(telemetry_loop):
|
|
2106
|
-
tool_count_by_name = (
|
|
2107
|
-
telemetry_loop.get("event_tool_count_by_name") if isinstance(telemetry_loop, dict) else {}
|
|
2108
|
-
)
|
|
2109
|
-
list_directory_calls = (
|
|
2110
|
-
int(tool_count_by_name.get("list_directory", 0) or 0)
|
|
2111
|
-
if isinstance(tool_count_by_name, dict)
|
|
2112
|
-
else 0
|
|
2113
|
-
)
|
|
2114
|
-
self.logger.warning(
|
|
2115
|
-
"agentic_list_directory_loop_detected",
|
|
2116
|
-
error=str(exc),
|
|
2117
|
-
list_directory_calls=list_directory_calls,
|
|
2118
|
-
tool_calls=current_tool_calls,
|
|
2119
|
-
)
|
|
2120
|
-
if not used_list_directory_synthesis_retry:
|
|
2121
|
-
used_list_directory_synthesis_retry = True
|
|
2122
|
-
current_prompt = (
|
|
2123
|
-
user_prompt_payload
|
|
2124
|
-
+ "\n\nLIST-DIRECTORY CHURN GUARD - FINAL SYNTHESIS MODE:\n"
|
|
2125
|
-
+ "- STOP broad list_directory exploration.\n"
|
|
2126
|
-
+ "- Use at most one targeted read_file/search call if essential.\n"
|
|
2127
|
-
+ "- Prefer synthesizing from already collected evidence.\n"
|
|
2128
|
-
+ "- Return final CodeFindings JSON now."
|
|
2129
|
-
)
|
|
2130
|
-
current_toolsets = _to_synthesis_toolset(current_toolsets)
|
|
2131
|
-
synthesis_turns, synthesis_tools = _synthesis_retry_caps(bool(current_toolsets))
|
|
2132
|
-
current_tool_calls = synthesis_tools
|
|
2133
|
-
current_turns = min(current_turns, synthesis_turns)
|
|
2134
|
-
continue
|
|
2135
|
-
raise RuntimeError(
|
|
2136
|
-
"agentic list_directory churn detected: aborting before tool_calls_limit repeats"
|
|
2137
|
-
) from exc
|
|
2138
|
-
|
|
2139
|
-
if self._is_repetitive_non_progress_tool_usage(
|
|
2140
|
-
aggregate_retry_telemetry if isinstance(aggregate_retry_telemetry, dict) else None,
|
|
2141
|
-
cadence_policy=cadence_policy,
|
|
2142
|
-
):
|
|
2143
|
-
if not used_request_limit_synthesis_retry and budget_retry_attempts == 0:
|
|
2144
|
-
if not _consume_corrective_budget(
|
|
2145
|
-
guard_class="non_progress",
|
|
2146
|
-
reason="request_limit_synthesis_retry",
|
|
2147
|
-
):
|
|
2148
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2149
|
-
guard_class="non_progress",
|
|
2150
|
-
reason="request_limit_synthesis_retry_budget_exhausted",
|
|
2151
|
-
output_hint=None,
|
|
2152
|
-
telemetry_hint=(
|
|
2153
|
-
aggregate_retry_telemetry
|
|
2154
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2155
|
-
else None
|
|
2156
|
-
),
|
|
2157
|
-
)
|
|
2158
|
-
self.logger.warning(
|
|
2159
|
-
"agentic_request_limit_synthesis_retry",
|
|
2160
|
-
error=str(exc),
|
|
2161
|
-
max_turns=current_turns,
|
|
2162
|
-
max_tool_calls=current_tool_calls,
|
|
2163
|
-
observed_tool_names=(
|
|
2164
|
-
aggregate_retry_telemetry.get("event_tool_names")
|
|
2165
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2166
|
-
else None
|
|
2167
|
-
),
|
|
2168
|
-
)
|
|
2169
|
-
used_request_limit_synthesis_retry = True
|
|
2170
|
-
current_prompt = (
|
|
2171
|
-
user_prompt_payload
|
|
2172
|
-
+ "\n\nFINAL SYNTHESIS MODE:\n"
|
|
2173
|
-
+ "- STOP calling tools.\n"
|
|
2174
|
-
+ "- Use at most 1-2 focused read/list calls if essential, then finalize.\n"
|
|
2175
|
-
+ "- Do not run broad grep/list loops.\n"
|
|
2176
|
-
+ "- Return the final CodeFindings JSON now."
|
|
2177
|
-
)
|
|
2178
|
-
current_toolsets = _to_synthesis_toolset(current_toolsets)
|
|
2179
|
-
synthesis_turns, synthesis_tools = _synthesis_retry_caps(bool(current_toolsets))
|
|
2180
|
-
current_tool_calls = synthesis_tools
|
|
2181
|
-
current_turns = min(current_turns, synthesis_turns)
|
|
2182
|
-
continue
|
|
2183
|
-
self.logger.warning(
|
|
2184
|
-
"agentic_request_limit_non_progress_abort",
|
|
2185
|
-
error=str(exc),
|
|
2186
|
-
max_turns=current_turns,
|
|
2187
|
-
max_tool_calls=current_tool_calls,
|
|
2188
|
-
observed_tool_names=(
|
|
2189
|
-
aggregate_retry_telemetry.get("event_tool_names")
|
|
2190
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2191
|
-
else None
|
|
2192
|
-
),
|
|
2193
|
-
)
|
|
2194
|
-
if not used_non_progress_final_retry:
|
|
2195
|
-
if not _consume_corrective_budget(
|
|
2196
|
-
guard_class="non_progress",
|
|
2197
|
-
reason="request_limit_non_progress_final_retry",
|
|
2198
|
-
):
|
|
2199
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2200
|
-
guard_class="non_progress",
|
|
2201
|
-
reason="request_limit_non_progress_final_retry_budget_exhausted",
|
|
2202
|
-
output_hint=None,
|
|
2203
|
-
telemetry_hint=(
|
|
2204
|
-
aggregate_retry_telemetry
|
|
2205
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2206
|
-
else None
|
|
2207
|
-
),
|
|
2208
|
-
)
|
|
2209
|
-
used_non_progress_final_retry = True
|
|
2210
|
-
current_prompt = (
|
|
2211
|
-
user_prompt_payload
|
|
2212
|
-
+ "\n\nNON-PROGRESS EXIT GUARD - FINAL ANSWER MODE:\n"
|
|
2213
|
-
+ "- STOP calling tools immediately.\n"
|
|
2214
|
-
+ "- Synthesize from already collected evidence only.\n"
|
|
2215
|
-
+ "- Return final CodeFindings JSON now."
|
|
2216
|
-
)
|
|
2217
|
-
current_toolsets = _to_synthesis_toolset(current_toolsets)
|
|
2218
|
-
# Keep a tiny read-only budget to avoid tool_calls_limit=0 deadlocks
|
|
2219
|
-
# when providers emit one residual tool call before final synthesis.
|
|
2220
|
-
synthesis_turns, synthesis_tools = _synthesis_retry_caps(bool(current_toolsets))
|
|
2221
|
-
current_tool_calls = synthesis_tools
|
|
2222
|
-
current_turns = min(current_turns, synthesis_turns)
|
|
2223
|
-
continue
|
|
2224
|
-
if strict_skip_post_guard_retries:
|
|
2225
|
-
tool_count_by_name = (
|
|
2226
|
-
aggregate_retry_telemetry.get("event_tool_count_by_name")
|
|
2227
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2228
|
-
else {}
|
|
2229
|
-
)
|
|
2230
|
-
read_file_calls = (
|
|
2231
|
-
int(tool_count_by_name.get("read_file", 0) or 0)
|
|
2232
|
-
if isinstance(tool_count_by_name, dict)
|
|
2233
|
-
else 0
|
|
2234
|
-
)
|
|
2235
|
-
observed_tool_names = (
|
|
2236
|
-
aggregate_retry_telemetry.get("event_tool_names")
|
|
2237
|
-
if isinstance(aggregate_retry_telemetry, dict)
|
|
2238
|
-
else []
|
|
2239
|
-
)
|
|
2240
|
-
self.logger.warning(
|
|
2241
|
-
"agentic_request_limit_non_progress_degraded_skip_retry",
|
|
2242
|
-
error=str(exc),
|
|
2243
|
-
max_turns=current_turns,
|
|
2244
|
-
max_tool_calls=current_tool_calls,
|
|
2245
|
-
observed_tool_names=observed_tool_names,
|
|
2246
|
-
observed_read_file_calls=read_file_calls,
|
|
2247
|
-
strict_no_fallback=strict_no_fallback,
|
|
2248
|
-
)
|
|
2249
|
-
return CodeFindings(
|
|
2250
|
-
score=0.0,
|
|
2251
|
-
confidence=0.4,
|
|
2252
|
-
issues=[],
|
|
2253
|
-
patterns=[],
|
|
2254
|
-
reasoning=(
|
|
2255
|
-
"Degraded finalize: strict non-progress/request-limit guard triggered; "
|
|
2256
|
-
"returning bounded partial synthesis without additional retries."
|
|
2257
|
-
),
|
|
2258
|
-
files_analyzed=max(0, read_file_calls),
|
|
2259
|
-
tech_stack=[],
|
|
2260
|
-
)
|
|
2261
|
-
if corrective_budget_remaining <= 0:
|
|
2262
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2263
|
-
guard_class="non_progress",
|
|
2264
|
-
reason="request_limit_non_progress_abort_budget_exhausted",
|
|
2265
|
-
output_hint=None,
|
|
2266
|
-
telemetry_hint=(
|
|
2267
|
-
aggregate_retry_telemetry if isinstance(aggregate_retry_telemetry, dict) else None
|
|
2268
|
-
),
|
|
2269
|
-
)
|
|
2270
|
-
raise RuntimeError(
|
|
2271
|
-
"agentic non-progress detected before request-limit retry: repetitive tool usage"
|
|
2272
|
-
) from exc
|
|
2273
|
-
|
|
2274
|
-
if strict_no_fallback and local_openai_protocol and not used_strict_budget_synthesis_retry:
|
|
2275
|
-
self.logger.warning(
|
|
2276
|
-
"agentic_strict_budget_synthesis_retry",
|
|
2277
|
-
error=str(exc),
|
|
2278
|
-
max_turns=current_turns,
|
|
2279
|
-
max_tool_calls=current_tool_calls,
|
|
2280
|
-
)
|
|
2281
|
-
used_strict_budget_synthesis_retry = True
|
|
2282
|
-
current_prompt = (
|
|
2283
|
-
user_prompt_payload
|
|
2284
|
-
+ "\n\nSTRICT BUDGET EXHAUSTED - FINAL SYNTHESIS MODE:\n"
|
|
2285
|
-
+ "- STOP calling tools.\n"
|
|
2286
|
-
+ "- Use at most 1-2 focused read/list calls if essential, then finalize.\n"
|
|
2287
|
-
+ "- Do not run broad grep/list loops.\n"
|
|
2288
|
-
+ "- Return final CodeFindings JSON now."
|
|
2289
|
-
)
|
|
2290
|
-
current_toolsets = _to_synthesis_toolset(current_toolsets)
|
|
2291
|
-
synthesis_turns, synthesis_tools = _synthesis_retry_caps(bool(current_toolsets))
|
|
2292
|
-
current_tool_calls = synthesis_tools
|
|
2293
|
-
current_turns = min(current_turns, synthesis_turns)
|
|
2294
|
-
continue
|
|
2295
|
-
|
|
2296
|
-
if strict_no_fallback:
|
|
2297
|
-
if local_openai_protocol:
|
|
2298
|
-
# Local OpenAI providers can keep issuing repetitive tool calls even
|
|
2299
|
-
# after synthesis mode prompts. Avoid expanding budgets; force one
|
|
2300
|
-
# hard synthesis retry with tools disabled, then fail fast.
|
|
2301
|
-
if not used_non_progress_final_retry:
|
|
2302
|
-
used_non_progress_final_retry = True
|
|
2303
|
-
local_openai_hard_synthesis_used = True
|
|
2304
|
-
strict_budget_hard_synthesis_used = True
|
|
2305
|
-
self.logger.warning(
|
|
2306
|
-
"agentic_local_openai_hard_synthesis_retry",
|
|
2307
|
-
error=str(exc),
|
|
2308
|
-
max_turns=current_turns,
|
|
2309
|
-
max_tool_calls=current_tool_calls,
|
|
2310
|
-
)
|
|
2311
|
-
current_prompt = (
|
|
2312
|
-
user_prompt_payload
|
|
2313
|
-
+ "\n\nLOCAL OPENAI HARD SYNTHESIS MODE:\n"
|
|
2314
|
-
+ "- DO NOT call any tools.\n"
|
|
2315
|
-
+ "- Synthesize strictly from prior tool outputs.\n"
|
|
2316
|
-
+ "- Return final CodeFindings JSON now.\n"
|
|
2317
|
-
)
|
|
2318
|
-
current_toolsets = []
|
|
2319
|
-
current_tool_calls = max(1, local_openai_hard_synthesis_max_tool_calls)
|
|
2320
|
-
current_turns = min(current_turns, max(1, local_openai_hard_synthesis_max_turns))
|
|
2321
|
-
continue
|
|
2322
|
-
self.logger.warning(
|
|
2323
|
-
"agentic_local_openai_budget_retry_disabled_fail_fast",
|
|
2324
|
-
error=str(exc),
|
|
2325
|
-
max_turns=current_turns,
|
|
2326
|
-
max_tool_calls=current_tool_calls,
|
|
2327
|
-
)
|
|
2328
|
-
raise
|
|
2329
|
-
# Non-local strict mode: avoid budget re-expansion after synthesis.
|
|
2330
|
-
# Force one hard synthesis retry with no tools, then fail fast.
|
|
2331
|
-
if not used_strict_budget_hard_synthesis_retry:
|
|
2332
|
-
used_strict_budget_hard_synthesis_retry = True
|
|
2333
|
-
strict_budget_hard_synthesis_used = True
|
|
2334
|
-
self.logger.warning(
|
|
2335
|
-
"agentic_strict_budget_hard_synthesis_retry",
|
|
2336
|
-
error=str(exc),
|
|
2337
|
-
max_turns=current_turns,
|
|
2338
|
-
max_tool_calls=current_tool_calls,
|
|
2339
|
-
)
|
|
2340
|
-
current_prompt = (
|
|
2341
|
-
user_prompt_payload
|
|
2342
|
-
+ "\n\nSTRICT BUDGET EXHAUSTED - HARD SYNTHESIS MODE:\n"
|
|
2343
|
-
+ "- DO NOT call tools.\n"
|
|
2344
|
-
+ "- Synthesize strictly from prior tool outputs.\n"
|
|
2345
|
-
+ "- Return final CodeFindings JSON now.\n"
|
|
2346
|
-
)
|
|
2347
|
-
current_toolsets = []
|
|
2348
|
-
# Keep a tiny allowance to avoid tool_calls_limit=0 deadlocks
|
|
2349
|
-
# when providers emit one residual internal tool/final_result call.
|
|
2350
|
-
current_tool_calls = max(1, local_openai_hard_synthesis_max_tool_calls)
|
|
2351
|
-
current_turns = min(current_turns, max(1, local_openai_hard_synthesis_max_turns))
|
|
2352
|
-
continue
|
|
2353
|
-
self.logger.warning(
|
|
2354
|
-
"agentic_budget_retry_disabled_fail_fast",
|
|
2355
|
-
error=str(exc),
|
|
2356
|
-
max_turns=current_turns,
|
|
2357
|
-
max_tool_calls=current_tool_calls,
|
|
2358
|
-
)
|
|
2359
|
-
raise
|
|
2360
|
-
|
|
2361
|
-
if budget_retry_attempts >= max_budget_retry_attempts:
|
|
2362
|
-
self.logger.warning(
|
|
2363
|
-
"agentic_budget_retry_exhausted",
|
|
2364
|
-
error=str(exc),
|
|
2365
|
-
max_turns=current_turns,
|
|
2366
|
-
max_tool_calls=current_tool_calls,
|
|
2367
|
-
retry_attempts=budget_retry_attempts,
|
|
2368
|
-
)
|
|
2369
|
-
raise
|
|
2370
|
-
|
|
2371
|
-
retry_turns = min(current_turns + 2, retry_turn_cap)
|
|
2372
|
-
retry_tool_calls = min(current_tool_calls + 6, retry_tool_call_cap)
|
|
2373
|
-
if retry_turns <= current_turns and retry_tool_calls <= current_tool_calls:
|
|
2374
|
-
raise
|
|
2375
|
-
self.logger.warning(
|
|
2376
|
-
"agentic_budget_retry",
|
|
2377
|
-
error=str(exc),
|
|
2378
|
-
original_max_turns=current_turns,
|
|
2379
|
-
original_max_tool_calls=current_tool_calls,
|
|
2380
|
-
retry_max_turns=retry_turns,
|
|
2381
|
-
retry_max_tool_calls=retry_tool_calls,
|
|
2382
|
-
)
|
|
2383
|
-
budget_retry_attempts += 1
|
|
2384
|
-
current_turns = retry_turns
|
|
2385
|
-
current_tool_calls = retry_tool_calls
|
|
2386
|
-
|
|
2387
|
-
output = await _invoke_agentic(
|
|
2388
|
-
user_prompt,
|
|
2389
|
-
max_turns,
|
|
2390
|
-
max_tool_calls,
|
|
2391
|
-
active_toolsets=toolsets,
|
|
2392
|
-
)
|
|
2393
|
-
if (not str(getattr(output, "reasoning", "") or "").strip()) and getattr(output, "issues", None):
|
|
2394
|
-
synthesized_reasoning = self._build_issue_grounded_reasoning(output)
|
|
2395
|
-
if synthesized_reasoning:
|
|
2396
|
-
output.reasoning = synthesized_reasoning
|
|
2397
|
-
self.logger.info(
|
|
2398
|
-
"agentic_reasoning_autofill_from_issues",
|
|
2399
|
-
issues_count=len(getattr(output, "issues", []) or []),
|
|
2400
|
-
reasoning_chars=len(synthesized_reasoning),
|
|
2401
|
-
)
|
|
2402
|
-
telemetry = (
|
|
2403
|
-
aggregate_retry_telemetry
|
|
2404
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2405
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2406
|
-
)
|
|
2407
|
-
telemetry_available = isinstance(telemetry, dict) and (
|
|
2408
|
-
"usage" in telemetry
|
|
2409
|
-
or "event_tool_calls" in telemetry
|
|
2410
|
-
or "event_tool_calls_started" in telemetry
|
|
2411
|
-
or "event_tool_calls_completed" in telemetry
|
|
2412
|
-
)
|
|
2413
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry if telemetry_available else None)
|
|
2414
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry if telemetry_available else None)
|
|
2415
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry if telemetry_available else None)
|
|
2416
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry if telemetry_available else None)
|
|
2417
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(
|
|
2418
|
-
telemetry if telemetry_available else None
|
|
2419
|
-
)
|
|
2420
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry if telemetry_available else None)
|
|
2421
|
-
quality_summary = self._build_response_quality_summary(output, telemetry if telemetry_available else None)
|
|
2422
|
-
quality_flags = (
|
|
2423
|
-
{str(flag) for flag in quality_summary.get("quality_flags", [])}
|
|
2424
|
-
if isinstance(quality_summary, dict)
|
|
2425
|
-
else set()
|
|
2426
|
-
)
|
|
2427
|
-
terminal_quality_flags = set(quality_flags)
|
|
2428
|
-
reasoning_text = str(getattr(output, "reasoning", "") or "")
|
|
2429
|
-
reasoning_has_evidence_refs = self._has_concrete_reasoning_evidence_refs(reasoning_text)
|
|
2430
|
-
grounded_issue_paths = self._has_grounded_issue_paths(output, repo_path)
|
|
2431
|
-
if (not reasoning_has_evidence_refs) and (not grounded_issue_paths):
|
|
2432
|
-
terminal_quality_flags.add("reasoning_missing_evidence_refs")
|
|
2433
|
-
terminal_quality_failure_reason = (
|
|
2434
|
-
"reasoning_too_short"
|
|
2435
|
-
if "reasoning_too_short" in terminal_quality_flags
|
|
2436
|
-
else "reasoning_missing_evidence_refs"
|
|
2437
|
-
)
|
|
2438
|
-
if (
|
|
2439
|
-
strict_no_fallback
|
|
2440
|
-
and strict_budget_hard_synthesis_used
|
|
2441
|
-
and bool({"reasoning_too_short", "reasoning_missing_evidence_refs"} & terminal_quality_flags)
|
|
2442
|
-
):
|
|
2443
|
-
if strict_skip_post_guard_retries:
|
|
2444
|
-
self.logger.warning(
|
|
2445
|
-
"agentic_strict_budget_hard_synthesis_quality_degraded_skip_retry",
|
|
2446
|
-
quality_flags=sorted(terminal_quality_flags),
|
|
2447
|
-
reasoning_chars=quality_summary.get("reasoning_chars"),
|
|
2448
|
-
observed_tool_counts=(
|
|
2449
|
-
telemetry.get("event_tool_count_by_name") if isinstance(telemetry, dict) else None
|
|
2450
|
-
),
|
|
2451
|
-
)
|
|
2452
|
-
elif hard_synthesis_quality_retry_used:
|
|
2453
|
-
self.logger.warning(
|
|
2454
|
-
"agentic_strict_budget_hard_synthesis_quality_unsatisfied",
|
|
2455
|
-
quality_flags=sorted(terminal_quality_flags),
|
|
2456
|
-
reasoning_chars=quality_summary.get("reasoning_chars"),
|
|
2457
|
-
observed_tool_counts=(
|
|
2458
|
-
telemetry.get("event_tool_count_by_name") if isinstance(telemetry, dict) else None
|
|
2459
|
-
),
|
|
2460
|
-
)
|
|
2461
|
-
raise RuntimeError(
|
|
2462
|
-
f"agentic hard-synthesis quality guard unsatisfied: {terminal_quality_failure_reason} after terminal retry"
|
|
2463
|
-
)
|
|
2464
|
-
else:
|
|
2465
|
-
hard_synthesis_quality_retry_used = True
|
|
2466
|
-
self.logger.warning(
|
|
2467
|
-
"agentic_strict_budget_hard_synthesis_quality_retry",
|
|
2468
|
-
quality_flags=sorted(terminal_quality_flags),
|
|
2469
|
-
reasoning_chars=quality_summary.get("reasoning_chars"),
|
|
2470
|
-
observed_tool_counts=(
|
|
2471
|
-
telemetry.get("event_tool_count_by_name") if isinstance(telemetry, dict) else None
|
|
2472
|
-
),
|
|
2473
|
-
)
|
|
2474
|
-
quality_guard_prompt = (
|
|
2475
|
-
user_prompt
|
|
2476
|
-
+ "\n\nSTRICT HARD-SYNTHESIS QUALITY GUARD:\n"
|
|
2477
|
-
+ "- DO NOT call tools.\n"
|
|
2478
|
-
+ "- Return only final CodeFindings JSON.\n"
|
|
2479
|
-
+ "- In reasoning, provide 4-6 sentences grounded in already collected evidence.\n"
|
|
2480
|
-
+ "- Include at least two concrete evidence references (file path + line like src/app.py:123, or explicit document title in quotes).\n"
|
|
2481
|
-
+ "- State key risk and one residual uncertainty explicitly.\n"
|
|
2482
|
-
)
|
|
2483
|
-
output = await _invoke_agentic(
|
|
2484
|
-
quality_guard_prompt,
|
|
2485
|
-
max(1, local_openai_hard_synthesis_max_turns),
|
|
2486
|
-
max(1, local_openai_hard_synthesis_max_tool_calls),
|
|
2487
|
-
active_toolsets=[],
|
|
2488
|
-
)
|
|
2489
|
-
if (not str(getattr(output, "reasoning", "") or "").strip()) and getattr(output, "issues", None):
|
|
2490
|
-
synthesized_reasoning = self._build_issue_grounded_reasoning(output)
|
|
2491
|
-
if synthesized_reasoning:
|
|
2492
|
-
output.reasoning = synthesized_reasoning
|
|
2493
|
-
self.logger.info(
|
|
2494
|
-
"agentic_reasoning_autofill_from_issues",
|
|
2495
|
-
issues_count=len(getattr(output, "issues", []) or []),
|
|
2496
|
-
reasoning_chars=len(synthesized_reasoning),
|
|
2497
|
-
)
|
|
2498
|
-
telemetry = (
|
|
2499
|
-
aggregate_retry_telemetry
|
|
2500
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2501
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2502
|
-
)
|
|
2503
|
-
telemetry_available = isinstance(telemetry, dict) and (
|
|
2504
|
-
"usage" in telemetry
|
|
2505
|
-
or "event_tool_calls" in telemetry
|
|
2506
|
-
or "event_tool_calls_started" in telemetry
|
|
2507
|
-
or "event_tool_calls_completed" in telemetry
|
|
2508
|
-
)
|
|
2509
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(
|
|
2510
|
-
telemetry if telemetry_available else None
|
|
2511
|
-
)
|
|
2512
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(
|
|
2513
|
-
telemetry if telemetry_available else None
|
|
2514
|
-
)
|
|
2515
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry if telemetry_available else None)
|
|
2516
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry if telemetry_available else None)
|
|
2517
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(
|
|
2518
|
-
telemetry if telemetry_available else None
|
|
2519
|
-
)
|
|
2520
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry if telemetry_available else None)
|
|
2521
|
-
quality_summary = self._build_response_quality_summary(output, telemetry if telemetry_available else None)
|
|
2522
|
-
quality_flags = (
|
|
2523
|
-
{str(flag) for flag in quality_summary.get("quality_flags", [])}
|
|
2524
|
-
if isinstance(quality_summary, dict)
|
|
2525
|
-
else set()
|
|
2526
|
-
)
|
|
2527
|
-
terminal_quality_flags = set(quality_flags)
|
|
2528
|
-
reasoning_text = str(getattr(output, "reasoning", "") or "")
|
|
2529
|
-
reasoning_has_evidence_refs = self._has_concrete_reasoning_evidence_refs(reasoning_text)
|
|
2530
|
-
grounded_issue_paths = self._has_grounded_issue_paths(output, repo_path)
|
|
2531
|
-
if (not reasoning_has_evidence_refs) and (not grounded_issue_paths):
|
|
2532
|
-
terminal_quality_flags.add("reasoning_missing_evidence_refs")
|
|
2533
|
-
terminal_quality_failure_reason = (
|
|
2534
|
-
"reasoning_too_short"
|
|
2535
|
-
if "reasoning_too_short" in terminal_quality_flags
|
|
2536
|
-
else "reasoning_missing_evidence_refs"
|
|
2537
|
-
)
|
|
2538
|
-
if bool({"reasoning_too_short", "reasoning_missing_evidence_refs"} & terminal_quality_flags):
|
|
2539
|
-
self.logger.warning(
|
|
2540
|
-
"agentic_strict_budget_hard_synthesis_quality_unsatisfied",
|
|
2541
|
-
quality_flags=sorted(terminal_quality_flags),
|
|
2542
|
-
reasoning_chars=quality_summary.get("reasoning_chars"),
|
|
2543
|
-
observed_tool_counts=(
|
|
2544
|
-
telemetry.get("event_tool_count_by_name") if isinstance(telemetry, dict) else None
|
|
2545
|
-
),
|
|
2546
|
-
)
|
|
2547
|
-
raise RuntimeError(
|
|
2548
|
-
f"agentic hard-synthesis quality guard unsatisfied: {terminal_quality_failure_reason} after terminal retry"
|
|
2549
|
-
)
|
|
2550
|
-
|
|
2551
|
-
if telemetry_available and strict_no_fallback:
|
|
2552
|
-
if self._is_repetitive_non_progress_tool_usage(telemetry, cadence_policy=cadence_policy):
|
|
2553
|
-
strict_efficiency_summary = self._build_tool_efficiency_summary(
|
|
2554
|
-
telemetry if isinstance(telemetry, dict) else None
|
|
2555
|
-
)
|
|
2556
|
-
productive_output = self._has_productive_agentic_output(output, strict_efficiency_summary)
|
|
2557
|
-
log_fn = self.logger.info if productive_output else self.logger.warning
|
|
2558
|
-
log_event = (
|
|
2559
|
-
"agentic_non_progress_guard_degraded_productive"
|
|
2560
|
-
if productive_output
|
|
2561
|
-
else "agentic_non_progress_guard_unsatisfied"
|
|
2562
|
-
)
|
|
2563
|
-
log_fn(
|
|
2564
|
-
log_event,
|
|
2565
|
-
observed_tool_calls=tool_calls_observed,
|
|
2566
|
-
observed_skill_calls=skill_calls_observed,
|
|
2567
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
2568
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2569
|
-
productive_output=productive_output,
|
|
2570
|
-
strict_no_fallback=strict_no_fallback,
|
|
2571
|
-
)
|
|
2572
|
-
if strict_no_fallback and not productive_output:
|
|
2573
|
-
if strict_skip_post_guard_retries:
|
|
2574
|
-
self.logger.warning(
|
|
2575
|
-
"agentic_non_progress_guard_degraded_skip_retry",
|
|
2576
|
-
observed_tool_calls=tool_calls_observed,
|
|
2577
|
-
observed_skill_calls=skill_calls_observed,
|
|
2578
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2579
|
-
)
|
|
2580
|
-
else:
|
|
2581
|
-
raise RuntimeError(
|
|
2582
|
-
"agentic non-progress guard unsatisfied: repetitive tool usage without progress"
|
|
2583
|
-
)
|
|
2584
|
-
|
|
2585
|
-
tool_count_by_name = telemetry.get("event_tool_count_by_name")
|
|
2586
|
-
has_detailed_tool_telemetry = isinstance(tool_count_by_name, dict) and any(
|
|
2587
|
-
str(name) != "final_result" and int(count or 0) > 0 for name, count in tool_count_by_name.items()
|
|
2588
|
-
)
|
|
2589
|
-
strict_code_read_required = has_detailed_tool_telemetry
|
|
2590
|
-
if vector_docs_required and vector_docs_tool_calls_observed < 1:
|
|
2591
|
-
self.logger.warning(
|
|
2592
|
-
"agentic_vector_docs_usage_guard_retry_strict",
|
|
2593
|
-
observed_tool_calls=tool_calls_observed,
|
|
2594
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
2595
|
-
vector_docs_required=vector_docs_required,
|
|
2596
|
-
)
|
|
2597
|
-
if not _consume_corrective_budget(
|
|
2598
|
-
guard_class="vector",
|
|
2599
|
-
reason="strict_vector_docs_usage_guard_retry",
|
|
2600
|
-
):
|
|
2601
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2602
|
-
guard_class="vector",
|
|
2603
|
-
reason="strict_vector_docs_usage_guard_retry_budget_exhausted",
|
|
2604
|
-
output_hint=output,
|
|
2605
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2606
|
-
)
|
|
2607
|
-
strict_vector_prompt = (
|
|
2608
|
-
user_prompt
|
|
2609
|
-
+ "\n\nSTRICT MANDATORY VECTOR DOCS RETRIEVAL:\n"
|
|
2610
|
-
+ "- Call search_evidence_vector (docs) or search_code_vector (code) with requirement-specific keywords.\n"
|
|
2611
|
-
+ "- Use vector_retrieval_status only as readiness check, not as primary evidence.\n"
|
|
2612
|
-
+ "- Read at least one concrete source after vector retrieval before finalizing."
|
|
2613
|
-
)
|
|
2614
|
-
output = await _invoke_agentic(
|
|
2615
|
-
strict_vector_prompt,
|
|
2616
|
-
min(max_turns + 2, retry_turn_cap),
|
|
2617
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
2618
|
-
active_toolsets=toolsets,
|
|
2619
|
-
)
|
|
2620
|
-
telemetry = (
|
|
2621
|
-
aggregate_retry_telemetry
|
|
2622
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2623
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2624
|
-
)
|
|
2625
|
-
telemetry_available = isinstance(telemetry, dict) and (
|
|
2626
|
-
"usage" in telemetry
|
|
2627
|
-
or "event_tool_calls" in telemetry
|
|
2628
|
-
or "event_tool_calls_started" in telemetry
|
|
2629
|
-
or "event_tool_calls_completed" in telemetry
|
|
2630
|
-
)
|
|
2631
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(
|
|
2632
|
-
telemetry if telemetry_available else None
|
|
2633
|
-
)
|
|
2634
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(
|
|
2635
|
-
telemetry if telemetry_available else None
|
|
2636
|
-
)
|
|
2637
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry if telemetry_available else None)
|
|
2638
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(
|
|
2639
|
-
telemetry if telemetry_available else None
|
|
2640
|
-
)
|
|
2641
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(
|
|
2642
|
-
telemetry if telemetry_available else None
|
|
2643
|
-
)
|
|
2644
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(
|
|
2645
|
-
telemetry if telemetry_available else None
|
|
2646
|
-
)
|
|
2647
|
-
# Strict mode requires an explicit, effective skill tool call
|
|
2648
|
-
# only for rows classified as skill-required.
|
|
2649
|
-
skills_requirement_satisfied = (not skills_required) or (skill_effective_calls_observed >= 1)
|
|
2650
|
-
if (
|
|
2651
|
-
not skills_requirement_satisfied
|
|
2652
|
-
and tool_calls_observed >= 1
|
|
2653
|
-
and (not strict_code_read_required or code_read_calls_observed >= 1)
|
|
2654
|
-
and (not docs_required or docs_read_calls_observed >= 1 or vector_docs_tool_calls_observed >= 1)
|
|
2655
|
-
and (not vector_docs_required or vector_docs_tool_calls_observed >= 1)
|
|
2656
|
-
and (vector_docs_tool_calls_observed < 1 or (docs_read_calls_observed + code_read_calls_observed) >= 1)
|
|
2657
|
-
):
|
|
2658
|
-
self.logger.warning(
|
|
2659
|
-
"agentic_skill_usage_guard_retry_strict",
|
|
2660
|
-
observed_tool_calls=tool_calls_observed,
|
|
2661
|
-
observed_skill_calls=skill_calls_observed,
|
|
2662
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
2663
|
-
)
|
|
2664
|
-
if not _consume_corrective_budget(
|
|
2665
|
-
guard_class="skill",
|
|
2666
|
-
reason="strict_skill_usage_guard_retry",
|
|
2667
|
-
):
|
|
2668
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2669
|
-
guard_class="skill",
|
|
2670
|
-
reason="strict_skill_usage_guard_retry_budget_exhausted",
|
|
2671
|
-
output_hint=output,
|
|
2672
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2673
|
-
)
|
|
2674
|
-
strict_skill_prompt = (
|
|
2675
|
-
user_prompt
|
|
2676
|
-
+ "\n\nSTRICT MANDATORY SKILL USAGE:\n"
|
|
2677
|
-
+ '- Call load_skill(name="<listed-skill>") for one relevant available skill.\n'
|
|
2678
|
-
+ '- Then call read_skill_resource(name="<listed-skill>", resource_path="<resource-from-load-skill>") once.\n'
|
|
2679
|
-
+ "- Do not call list_skills in this retry; available skills are already listed.\n"
|
|
2680
|
-
+ "- Use skill tools only in this retry to complete one effective skill sequence quickly.\n"
|
|
2681
|
-
+ "- Keep filesystem evidence already collected; do not restart broad discovery.\n"
|
|
2682
|
-
+ "- Return final output only after one effective skill tool call."
|
|
2683
|
-
)
|
|
2684
|
-
strict_skill_tool_allowlist = [
|
|
2685
|
-
"load_skill",
|
|
2686
|
-
"read_skill_resource",
|
|
2687
|
-
"run_skill_script",
|
|
2688
|
-
]
|
|
2689
|
-
strict_skill_toolsets = self._apply_tool_allowlist(list(toolsets), strict_skill_tool_allowlist)
|
|
2690
|
-
if not strict_skill_toolsets:
|
|
2691
|
-
self.logger.warning(
|
|
2692
|
-
"agentic_skill_usage_guard_retry_toolset_unavailable",
|
|
2693
|
-
allowlist=strict_skill_tool_allowlist,
|
|
2694
|
-
)
|
|
2695
|
-
strict_skill_toolsets = list(toolsets)
|
|
2696
|
-
strict_skill_retry_turns = max(2, min(max_turns, 4))
|
|
2697
|
-
strict_skill_retry_tool_calls = max(4, min(max_tool_calls, 8))
|
|
2698
|
-
output = await _invoke_agentic(
|
|
2699
|
-
strict_skill_prompt,
|
|
2700
|
-
strict_skill_retry_turns,
|
|
2701
|
-
strict_skill_retry_tool_calls,
|
|
2702
|
-
active_toolsets=strict_skill_toolsets,
|
|
2703
|
-
)
|
|
2704
|
-
telemetry = (
|
|
2705
|
-
aggregate_retry_telemetry
|
|
2706
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2707
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2708
|
-
)
|
|
2709
|
-
telemetry_available = isinstance(telemetry, dict) and (
|
|
2710
|
-
"usage" in telemetry
|
|
2711
|
-
or "event_tool_calls" in telemetry
|
|
2712
|
-
or "event_tool_calls_started" in telemetry
|
|
2713
|
-
or "event_tool_calls_completed" in telemetry
|
|
2714
|
-
)
|
|
2715
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(
|
|
2716
|
-
telemetry if telemetry_available else None
|
|
2717
|
-
)
|
|
2718
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(
|
|
2719
|
-
telemetry if telemetry_available else None
|
|
2720
|
-
)
|
|
2721
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry if telemetry_available else None)
|
|
2722
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(
|
|
2723
|
-
telemetry if telemetry_available else None
|
|
2724
|
-
)
|
|
2725
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(
|
|
2726
|
-
telemetry if telemetry_available else None
|
|
2727
|
-
)
|
|
2728
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(
|
|
2729
|
-
telemetry if telemetry_available else None
|
|
2730
|
-
)
|
|
2731
|
-
skills_requirement_satisfied = (not skills_required) or (skill_effective_calls_observed >= 1)
|
|
2732
|
-
if (
|
|
2733
|
-
tool_calls_observed < 1
|
|
2734
|
-
or (strict_code_read_required and code_read_calls_observed < 1)
|
|
2735
|
-
or (not skills_requirement_satisfied)
|
|
2736
|
-
or (docs_required and docs_read_calls_observed < 1 and vector_docs_tool_calls_observed < 1)
|
|
2737
|
-
or (vector_docs_required and vector_docs_tool_calls_observed < 1)
|
|
2738
|
-
or (vector_docs_tool_calls_observed >= 1 and (docs_read_calls_observed + code_read_calls_observed) < 1)
|
|
2739
|
-
):
|
|
2740
|
-
if (
|
|
2741
|
-
strict_no_fallback
|
|
2742
|
-
and local_openai_protocol
|
|
2743
|
-
and local_openai_hard_synthesis_used
|
|
2744
|
-
and not has_detailed_tool_telemetry
|
|
2745
|
-
):
|
|
2746
|
-
self.logger.warning(
|
|
2747
|
-
"agentic_usage_guard_degraded_missing_detailed_telemetry",
|
|
2748
|
-
observed_tool_calls=tool_calls_observed,
|
|
2749
|
-
observed_skill_calls=skill_calls_observed,
|
|
2750
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
2751
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2752
|
-
strict_no_fallback=True,
|
|
2753
|
-
)
|
|
2754
|
-
else:
|
|
2755
|
-
self.logger.warning(
|
|
2756
|
-
"agentic_usage_guard_unsatisfied",
|
|
2757
|
-
observed_tool_calls=tool_calls_observed,
|
|
2758
|
-
observed_skill_calls=skill_calls_observed,
|
|
2759
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
2760
|
-
skills_available=skills_available,
|
|
2761
|
-
skills_required=skills_required,
|
|
2762
|
-
preloaded_skill_context_used=bool(preloaded_skill_names),
|
|
2763
|
-
preloaded_skill_names=preloaded_skill_names,
|
|
2764
|
-
strict_code_read_required=strict_code_read_required,
|
|
2765
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
2766
|
-
observed_docs_tool_calls=docs_tool_calls_observed,
|
|
2767
|
-
observed_docs_read_tool_calls=docs_read_calls_observed,
|
|
2768
|
-
docs_required=docs_required,
|
|
2769
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
2770
|
-
vector_docs_required=vector_docs_required,
|
|
2771
|
-
strict_no_fallback=True,
|
|
2772
|
-
)
|
|
2773
|
-
if strict_skip_post_guard_retries:
|
|
2774
|
-
self.logger.warning(
|
|
2775
|
-
"agentic_usage_guard_degraded_skip_retry",
|
|
2776
|
-
strict_no_fallback=True,
|
|
2777
|
-
observed_tool_calls=tool_calls_observed,
|
|
2778
|
-
observed_skill_calls=skill_calls_observed,
|
|
2779
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
2780
|
-
)
|
|
2781
|
-
else:
|
|
2782
|
-
raise RuntimeError(
|
|
2783
|
-
"agentic usage guard unsatisfied: expected tool/docs/skill calls were not observed"
|
|
2784
|
-
)
|
|
2785
|
-
elif telemetry_available:
|
|
2786
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
2787
|
-
telemetry, cadence_policy=cadence_policy
|
|
2788
|
-
)
|
|
2789
|
-
tool_count_by_name = telemetry.get("event_tool_count_by_name") if isinstance(telemetry, dict) else None
|
|
2790
|
-
has_detailed_tool_telemetry = isinstance(tool_count_by_name, dict) and any(
|
|
2791
|
-
str(name) != "final_result" and int(count or 0) > 0 for name, count in tool_count_by_name.items()
|
|
2792
|
-
)
|
|
2793
|
-
require_code_read_in_relaxed_mode = (
|
|
2794
|
-
has_detailed_tool_telemetry and not docs_required and not vector_docs_required
|
|
2795
|
-
)
|
|
2796
|
-
if tool_calls_observed < 1:
|
|
2797
|
-
if non_progress_detected:
|
|
2798
|
-
self.logger.warning(
|
|
2799
|
-
"agentic_tool_usage_guard_retry_skipped_non_progress",
|
|
2800
|
-
observed_tool_calls=tool_calls_observed,
|
|
2801
|
-
observed_skill_calls=skill_calls_observed,
|
|
2802
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2803
|
-
)
|
|
2804
|
-
else:
|
|
2805
|
-
self.logger.warning(
|
|
2806
|
-
"agentic_tool_usage_guard_retry",
|
|
2807
|
-
observed_tool_calls=tool_calls_observed,
|
|
2808
|
-
observed_skill_calls=skill_calls_observed,
|
|
2809
|
-
skills_available=skills_available,
|
|
2810
|
-
)
|
|
2811
|
-
if not _consume_corrective_budget(
|
|
2812
|
-
guard_class="usage",
|
|
2813
|
-
reason="tool_usage_guard_retry",
|
|
2814
|
-
):
|
|
2815
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2816
|
-
guard_class="usage",
|
|
2817
|
-
reason="tool_usage_guard_retry_budget_exhausted",
|
|
2818
|
-
output_hint=output,
|
|
2819
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2820
|
-
)
|
|
2821
|
-
guarded_prompt = (
|
|
2822
|
-
user_prompt
|
|
2823
|
-
+ "\n\nMANDATORY TOOL USAGE:\n"
|
|
2824
|
-
+ "- Before final output, perform one repository discovery call (grep_search preferred; list_directory only if needed).\n"
|
|
2825
|
-
+ "- Then call read_file on at least one concrete file path returned by discovery.\n"
|
|
2826
|
-
+ "- Do not repeat identical list_directory calls on the same path.\n"
|
|
2827
|
-
+ "- Do not return a final answer without tool evidence."
|
|
2828
|
-
)
|
|
2829
|
-
output = await _invoke_agentic(
|
|
2830
|
-
guarded_prompt,
|
|
2831
|
-
min(max_turns + 2, retry_turn_cap),
|
|
2832
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
2833
|
-
active_toolsets=toolsets,
|
|
2834
|
-
)
|
|
2835
|
-
telemetry = (
|
|
2836
|
-
aggregate_retry_telemetry
|
|
2837
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2838
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2839
|
-
)
|
|
2840
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
2841
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
2842
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
2843
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
2844
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
2845
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
2846
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
2847
|
-
telemetry, cadence_policy=cadence_policy
|
|
2848
|
-
)
|
|
2849
|
-
|
|
2850
|
-
if require_code_read_in_relaxed_mode and code_read_calls_observed < 1:
|
|
2851
|
-
if non_progress_detected:
|
|
2852
|
-
self.logger.warning(
|
|
2853
|
-
"agentic_code_read_guard_retry_skipped_non_progress",
|
|
2854
|
-
observed_tool_calls=tool_calls_observed,
|
|
2855
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
2856
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2857
|
-
)
|
|
2858
|
-
else:
|
|
2859
|
-
self.logger.warning(
|
|
2860
|
-
"agentic_code_read_guard_retry",
|
|
2861
|
-
observed_tool_calls=tool_calls_observed,
|
|
2862
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
2863
|
-
)
|
|
2864
|
-
if not _consume_corrective_budget(
|
|
2865
|
-
guard_class="usage",
|
|
2866
|
-
reason="code_read_guard_retry",
|
|
2867
|
-
):
|
|
2868
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2869
|
-
guard_class="usage",
|
|
2870
|
-
reason="code_read_guard_retry_budget_exhausted",
|
|
2871
|
-
output_hint=output,
|
|
2872
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2873
|
-
)
|
|
2874
|
-
code_read_guarded_prompt = (
|
|
2875
|
-
user_prompt
|
|
2876
|
-
+ "\n\nMANDATORY CODE READ:\n"
|
|
2877
|
-
+ "- Perform one focused discovery call (grep_search preferred).\n"
|
|
2878
|
-
+ "- Immediately read_file (or get_definition/find_references) on a concrete file hit.\n"
|
|
2879
|
-
+ "- Do not conclude without at least one concrete code read/navigation result."
|
|
2880
|
-
)
|
|
2881
|
-
output = await _invoke_agentic(
|
|
2882
|
-
code_read_guarded_prompt,
|
|
2883
|
-
min(max_turns + 2, retry_turn_cap),
|
|
2884
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
2885
|
-
active_toolsets=toolsets,
|
|
2886
|
-
)
|
|
2887
|
-
telemetry = (
|
|
2888
|
-
aggregate_retry_telemetry
|
|
2889
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2890
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2891
|
-
)
|
|
2892
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
2893
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
2894
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
2895
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
2896
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
2897
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
2898
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
2899
|
-
telemetry, cadence_policy=cadence_policy
|
|
2900
|
-
)
|
|
2901
|
-
|
|
2902
|
-
if docs_required and docs_read_calls_observed < 1 and vector_docs_tool_calls_observed < 1:
|
|
2903
|
-
if non_progress_detected:
|
|
2904
|
-
self.logger.warning(
|
|
2905
|
-
"agentic_docs_usage_guard_retry_skipped_non_progress",
|
|
2906
|
-
observed_tool_calls=tool_calls_observed,
|
|
2907
|
-
observed_docs_tool_calls=docs_tool_calls_observed,
|
|
2908
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2909
|
-
docs_required=docs_required,
|
|
2910
|
-
)
|
|
2911
|
-
else:
|
|
2912
|
-
self.logger.warning(
|
|
2913
|
-
"agentic_docs_usage_guard_retry",
|
|
2914
|
-
observed_tool_calls=tool_calls_observed,
|
|
2915
|
-
observed_docs_tool_calls=docs_tool_calls_observed,
|
|
2916
|
-
docs_required=docs_required,
|
|
2917
|
-
)
|
|
2918
|
-
if not _consume_corrective_budget(
|
|
2919
|
-
guard_class="docs",
|
|
2920
|
-
reason="docs_usage_guard_retry",
|
|
2921
|
-
):
|
|
2922
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2923
|
-
guard_class="docs",
|
|
2924
|
-
reason="docs_usage_guard_retry_budget_exhausted",
|
|
2925
|
-
output_hint=output,
|
|
2926
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2927
|
-
)
|
|
2928
|
-
docs_guarded_prompt = (
|
|
2929
|
-
user_prompt
|
|
2930
|
-
+ "\n\nMANDATORY DOCS RETRIEVAL:\n"
|
|
2931
|
-
+ "- Call list_evidence_documents or search_evidence using architecture/security requirement keywords.\n"
|
|
2932
|
-
+ "- Then call read_evidence_document on at least one relevant result.\n"
|
|
2933
|
-
+ "- Correlate code findings with docs findings before final output."
|
|
2934
|
-
)
|
|
2935
|
-
output = await _invoke_agentic(
|
|
2936
|
-
docs_guarded_prompt,
|
|
2937
|
-
min(max_turns + 2, retry_turn_cap),
|
|
2938
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
2939
|
-
active_toolsets=toolsets,
|
|
2940
|
-
)
|
|
2941
|
-
telemetry = (
|
|
2942
|
-
aggregate_retry_telemetry
|
|
2943
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2944
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2945
|
-
)
|
|
2946
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
2947
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
2948
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
2949
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
2950
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
2951
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
2952
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
2953
|
-
telemetry, cadence_policy=cadence_policy
|
|
2954
|
-
)
|
|
2955
|
-
|
|
2956
|
-
if vector_docs_required and vector_docs_tool_calls_observed < 1:
|
|
2957
|
-
if non_progress_detected:
|
|
2958
|
-
self.logger.warning(
|
|
2959
|
-
"agentic_vector_docs_usage_guard_skipped_non_progress",
|
|
2960
|
-
observed_tool_calls=tool_calls_observed,
|
|
2961
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
2962
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
2963
|
-
vector_docs_required=vector_docs_required,
|
|
2964
|
-
)
|
|
2965
|
-
else:
|
|
2966
|
-
self.logger.warning(
|
|
2967
|
-
"agentic_vector_docs_usage_guard_retry",
|
|
2968
|
-
observed_tool_calls=tool_calls_observed,
|
|
2969
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
2970
|
-
vector_docs_required=vector_docs_required,
|
|
2971
|
-
)
|
|
2972
|
-
if not _consume_corrective_budget(
|
|
2973
|
-
guard_class="vector",
|
|
2974
|
-
reason="vector_docs_usage_guard_retry",
|
|
2975
|
-
):
|
|
2976
|
-
return _degraded_finalize_for_corrective_budget(
|
|
2977
|
-
guard_class="vector",
|
|
2978
|
-
reason="vector_docs_usage_guard_retry_budget_exhausted",
|
|
2979
|
-
output_hint=output,
|
|
2980
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
2981
|
-
)
|
|
2982
|
-
vector_guarded_prompt = (
|
|
2983
|
-
user_prompt
|
|
2984
|
-
+ "\n\nMANDATORY VECTOR DOCS RETRIEVAL:\n"
|
|
2985
|
-
+ "- Call search_evidence_vector (docs) or search_code_vector (code) with architecture/security requirement keywords.\n"
|
|
2986
|
-
+ "- Use vector_retrieval_status only as readiness check, not as primary evidence.\n"
|
|
2987
|
-
+ "- Correlate vector evidence chunks with repository findings before final output."
|
|
2988
|
-
)
|
|
2989
|
-
output = await _invoke_agentic(
|
|
2990
|
-
vector_guarded_prompt,
|
|
2991
|
-
min(max_turns + 2, retry_turn_cap),
|
|
2992
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
2993
|
-
active_toolsets=toolsets,
|
|
2994
|
-
)
|
|
2995
|
-
telemetry = (
|
|
2996
|
-
aggregate_retry_telemetry
|
|
2997
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
2998
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
2999
|
-
)
|
|
3000
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
3001
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
3002
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
3003
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
3004
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
3005
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
3006
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
3007
|
-
telemetry, cadence_policy=cadence_policy
|
|
3008
|
-
)
|
|
3009
|
-
|
|
3010
|
-
if vector_docs_tool_calls_observed >= 1 and (docs_read_calls_observed + code_read_calls_observed) < 1:
|
|
3011
|
-
if non_progress_detected:
|
|
3012
|
-
self.logger.warning(
|
|
3013
|
-
"agentic_vector_readback_guard_skipped_non_progress",
|
|
3014
|
-
observed_tool_calls=tool_calls_observed,
|
|
3015
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
3016
|
-
observed_docs_read_tool_calls=docs_read_calls_observed,
|
|
3017
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
3018
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
3019
|
-
)
|
|
3020
|
-
else:
|
|
3021
|
-
self.logger.warning(
|
|
3022
|
-
"agentic_vector_readback_guard_retry",
|
|
3023
|
-
observed_tool_calls=tool_calls_observed,
|
|
3024
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
3025
|
-
observed_docs_read_tool_calls=docs_read_calls_observed,
|
|
3026
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
3027
|
-
)
|
|
3028
|
-
if not _consume_corrective_budget(
|
|
3029
|
-
guard_class="vector",
|
|
3030
|
-
reason="vector_readback_guard_retry",
|
|
3031
|
-
):
|
|
3032
|
-
return _degraded_finalize_for_corrective_budget(
|
|
3033
|
-
guard_class="vector",
|
|
3034
|
-
reason="vector_readback_guard_retry_budget_exhausted",
|
|
3035
|
-
output_hint=output,
|
|
3036
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
3037
|
-
)
|
|
3038
|
-
vector_readback_prompt = (
|
|
3039
|
-
user_prompt
|
|
3040
|
-
+ "\n\nMANDATORY VECTOR READ-BACK:\n"
|
|
3041
|
-
+ "- After vector retrieval, read at least one concrete source before finalizing.\n"
|
|
3042
|
-
+ "- Use read_evidence_document for docs vectors or read_file/get_definition/find_references for code vectors.\n"
|
|
3043
|
-
+ "- Ground findings in the concrete read output, not vector summaries alone."
|
|
3044
|
-
)
|
|
3045
|
-
output = await _invoke_agentic(
|
|
3046
|
-
vector_readback_prompt,
|
|
3047
|
-
min(max_turns + 2, retry_turn_cap),
|
|
3048
|
-
min(max_tool_calls + 8, retry_tool_call_cap),
|
|
3049
|
-
active_toolsets=toolsets,
|
|
3050
|
-
)
|
|
3051
|
-
telemetry = (
|
|
3052
|
-
aggregate_retry_telemetry
|
|
3053
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
3054
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
3055
|
-
)
|
|
3056
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
3057
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
3058
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
3059
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
3060
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
3061
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
3062
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
3063
|
-
telemetry, cadence_policy=cadence_policy
|
|
3064
|
-
)
|
|
3065
|
-
|
|
3066
|
-
if skills_required and skill_effective_calls_observed < 1:
|
|
3067
|
-
if non_progress_detected:
|
|
3068
|
-
self.logger.warning(
|
|
3069
|
-
"agentic_skill_usage_guard_retry_skipped_non_progress",
|
|
3070
|
-
observed_tool_calls=tool_calls_observed,
|
|
3071
|
-
observed_skill_calls=skill_calls_observed,
|
|
3072
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
3073
|
-
)
|
|
3074
|
-
else:
|
|
3075
|
-
self.logger.warning(
|
|
3076
|
-
"agentic_skill_usage_guard_retry",
|
|
3077
|
-
observed_tool_calls=tool_calls_observed,
|
|
3078
|
-
observed_skill_calls=skill_calls_observed,
|
|
3079
|
-
)
|
|
3080
|
-
if not _consume_corrective_budget(
|
|
3081
|
-
guard_class="skill",
|
|
3082
|
-
reason="skill_usage_guard_retry",
|
|
3083
|
-
):
|
|
3084
|
-
return _degraded_finalize_for_corrective_budget(
|
|
3085
|
-
guard_class="skill",
|
|
3086
|
-
reason="skill_usage_guard_retry_budget_exhausted",
|
|
3087
|
-
output_hint=output,
|
|
3088
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
3089
|
-
)
|
|
3090
|
-
skill_guarded_prompt = (
|
|
3091
|
-
user_prompt
|
|
3092
|
-
+ "\n\nMANDATORY SKILL USAGE:\n"
|
|
3093
|
-
+ "- Do not call list_skills unless the available skill list is missing.\n"
|
|
3094
|
-
+ '- Call load_skill(name="<listed-skill>") once for one relevant skill.\n'
|
|
3095
|
-
+ '- Then call read_skill_resource(name="<listed-skill>", resource_path="<resource-from-load-skill>") '
|
|
3096
|
-
+ "or run_skill_script only when explicitly available.\n"
|
|
3097
|
-
+ "- Do not return a final answer without at least one effective skill tool call."
|
|
3098
|
-
)
|
|
3099
|
-
output = await _invoke_agentic(
|
|
3100
|
-
skill_guarded_prompt,
|
|
3101
|
-
min(max_turns + 4, retry_turn_cap),
|
|
3102
|
-
min(max_tool_calls + 12, retry_tool_call_cap),
|
|
3103
|
-
active_toolsets=toolsets,
|
|
3104
|
-
)
|
|
3105
|
-
telemetry = (
|
|
3106
|
-
aggregate_retry_telemetry
|
|
3107
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
3108
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
3109
|
-
)
|
|
3110
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
3111
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
3112
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
3113
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
3114
|
-
telemetry, cadence_policy=cadence_policy
|
|
3115
|
-
)
|
|
3116
|
-
|
|
3117
|
-
if non_progress_detected:
|
|
3118
|
-
self.logger.warning(
|
|
3119
|
-
"agentic_non_progress_guard_retry",
|
|
3120
|
-
observed_tool_calls=tool_calls_observed,
|
|
3121
|
-
observed_skill_calls=skill_calls_observed,
|
|
3122
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
3123
|
-
)
|
|
3124
|
-
non_progress_guarded_prompt = (
|
|
3125
|
-
user_prompt
|
|
3126
|
-
+ "\n\nNON-PROGRESS LOOP GUARD:\n"
|
|
3127
|
-
+ "- Avoid repeating the same tool call pattern.\n"
|
|
3128
|
-
+ "- Pivot to a different tool or file target when prior calls yield no new evidence.\n"
|
|
3129
|
-
+ "- Do not call list_directory more than once per distinct path.\n"
|
|
3130
|
-
+ "- Do not call search_evidence more than twice for the same requirement.\n"
|
|
3131
|
-
+ "- Do not call list_skills unless you will immediately use a loaded skill in analysis.\n"
|
|
3132
|
-
+ "- Produce findings only after acquiring fresh tool evidence."
|
|
3133
|
-
)
|
|
3134
|
-
if not _consume_corrective_budget(
|
|
3135
|
-
guard_class="non_progress",
|
|
3136
|
-
reason="non_progress_guard_retry",
|
|
3137
|
-
):
|
|
3138
|
-
return _degraded_finalize_for_corrective_budget(
|
|
3139
|
-
guard_class="non_progress",
|
|
3140
|
-
reason="non_progress_guard_retry_budget_exhausted",
|
|
3141
|
-
output_hint=output,
|
|
3142
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
3143
|
-
)
|
|
3144
|
-
output = await _invoke_agentic(
|
|
3145
|
-
non_progress_guarded_prompt,
|
|
3146
|
-
min(max_turns, retry_turn_cap),
|
|
3147
|
-
min(max_tool_calls, 12),
|
|
3148
|
-
active_toolsets=toolsets,
|
|
3149
|
-
)
|
|
3150
|
-
telemetry = (
|
|
3151
|
-
aggregate_retry_telemetry
|
|
3152
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
3153
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
3154
|
-
)
|
|
3155
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
3156
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
3157
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
3158
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
3159
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
3160
|
-
code_read_calls_observed = self._extract_code_read_tool_usage(telemetry)
|
|
3161
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
3162
|
-
telemetry, cadence_policy=cadence_policy
|
|
3163
|
-
)
|
|
3164
|
-
|
|
3165
|
-
if non_progress_detected:
|
|
3166
|
-
self.logger.warning(
|
|
3167
|
-
"agentic_non_progress_guard_unsatisfied",
|
|
3168
|
-
observed_tool_calls=tool_calls_observed,
|
|
3169
|
-
observed_skill_calls=skill_calls_observed,
|
|
3170
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
3171
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
3172
|
-
)
|
|
3173
|
-
if corrective_budget_remaining <= 0:
|
|
3174
|
-
return _degraded_finalize_for_corrective_budget(
|
|
3175
|
-
guard_class="non_progress",
|
|
3176
|
-
reason="non_progress_guard_unsatisfied_budget_exhausted",
|
|
3177
|
-
output_hint=output,
|
|
3178
|
-
telemetry_hint=telemetry if isinstance(telemetry, dict) else None,
|
|
3179
|
-
)
|
|
3180
|
-
raise RuntimeError("agentic non-progress guard unsatisfied: repetitive tool usage without progress")
|
|
3181
|
-
|
|
3182
|
-
# Strict mode requires an explicit, effective skill tool call
|
|
3183
|
-
# only for rows classified as skill-required.
|
|
3184
|
-
skills_requirement_satisfied = (not skills_required) or (skill_effective_calls_observed >= 1)
|
|
3185
|
-
if (
|
|
3186
|
-
tool_calls_observed < 1
|
|
3187
|
-
or (require_code_read_in_relaxed_mode and code_read_calls_observed < 1)
|
|
3188
|
-
or (not skills_requirement_satisfied)
|
|
3189
|
-
or (docs_required and docs_read_calls_observed < 1 and vector_docs_tool_calls_observed < 1)
|
|
3190
|
-
or (vector_docs_required and vector_docs_tool_calls_observed < 1)
|
|
3191
|
-
):
|
|
3192
|
-
self.logger.warning(
|
|
3193
|
-
"agentic_usage_guard_unsatisfied",
|
|
3194
|
-
observed_tool_calls=tool_calls_observed,
|
|
3195
|
-
observed_skill_calls=skill_calls_observed,
|
|
3196
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
3197
|
-
skills_available=skills_available,
|
|
3198
|
-
skills_required=skills_required,
|
|
3199
|
-
preloaded_skill_context_used=bool(preloaded_skill_names),
|
|
3200
|
-
preloaded_skill_names=preloaded_skill_names,
|
|
3201
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
3202
|
-
observed_docs_tool_calls=docs_tool_calls_observed,
|
|
3203
|
-
docs_required=docs_required,
|
|
3204
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
3205
|
-
vector_docs_required=vector_docs_required,
|
|
3206
|
-
)
|
|
3207
|
-
# Relaxed mode is warning-only for usage guard misses; strict mode hard-fails above.
|
|
3208
|
-
|
|
3209
|
-
efficiency_summary = self._build_tool_efficiency_summary(telemetry if isinstance(telemetry, dict) else None)
|
|
3210
|
-
if self._is_tool_efficiency_kpi_unsatisfied(efficiency_summary, cadence_policy=cadence_policy):
|
|
3211
|
-
non_progress_detected = self._is_repetitive_non_progress_tool_usage(
|
|
3212
|
-
telemetry, cadence_policy=cadence_policy
|
|
3213
|
-
)
|
|
3214
|
-
self.logger.warning(
|
|
3215
|
-
"agentic_tool_efficiency_kpi_failed",
|
|
3216
|
-
tool_efficiency=efficiency_summary,
|
|
3217
|
-
strict_no_fallback=strict_no_fallback,
|
|
3218
|
-
non_progress_detected=non_progress_detected,
|
|
3219
|
-
)
|
|
3220
|
-
if non_progress_detected:
|
|
3221
|
-
self.logger.warning(
|
|
3222
|
-
"agentic_tool_efficiency_kpi_corrective_skipped_non_progress",
|
|
3223
|
-
tool_efficiency=efficiency_summary,
|
|
3224
|
-
)
|
|
3225
|
-
else:
|
|
3226
|
-
corrected_prompt = self._build_tool_efficiency_corrective_prompt(
|
|
3227
|
-
user_prompt, cadence_policy=cadence_policy
|
|
3228
|
-
)
|
|
3229
|
-
output = await _invoke_agentic(
|
|
3230
|
-
corrected_prompt,
|
|
3231
|
-
min(max_turns + 3, retry_turn_cap),
|
|
3232
|
-
min(max_tool_calls + 12, retry_tool_call_cap),
|
|
3233
|
-
active_toolsets=toolsets,
|
|
3234
|
-
)
|
|
3235
|
-
telemetry = (
|
|
3236
|
-
aggregate_retry_telemetry
|
|
3237
|
-
if isinstance(aggregate_retry_telemetry, dict) and aggregate_retry_telemetry
|
|
3238
|
-
else getattr(self, "_last_agent_run_telemetry", {})
|
|
3239
|
-
)
|
|
3240
|
-
tool_calls_observed, skill_calls_observed = self._extract_tool_usage(telemetry)
|
|
3241
|
-
skill_effective_calls_observed = self._extract_skill_effective_usage(telemetry)
|
|
3242
|
-
docs_tool_calls_observed = self._extract_docs_tool_usage(telemetry)
|
|
3243
|
-
docs_read_calls_observed = self._extract_docs_read_tool_usage(telemetry)
|
|
3244
|
-
vector_docs_tool_calls_observed = self._extract_vector_docs_tool_usage(telemetry)
|
|
3245
|
-
efficiency_summary = self._build_tool_efficiency_summary(
|
|
3246
|
-
telemetry if isinstance(telemetry, dict) else None
|
|
3247
|
-
)
|
|
3248
|
-
if self._is_tool_efficiency_kpi_unsatisfied(efficiency_summary, cadence_policy=cadence_policy):
|
|
3249
|
-
self.logger.warning(
|
|
3250
|
-
"agentic_tool_efficiency_kpi_unsatisfied",
|
|
3251
|
-
tool_efficiency=efficiency_summary,
|
|
3252
|
-
strict_no_fallback=strict_no_fallback,
|
|
3253
|
-
)
|
|
3254
|
-
if strict_no_fallback:
|
|
3255
|
-
if strict_skip_post_guard_retries:
|
|
3256
|
-
self.logger.warning(
|
|
3257
|
-
"agentic_tool_efficiency_kpi_degraded_skip_retry",
|
|
3258
|
-
tool_efficiency=efficiency_summary,
|
|
3259
|
-
)
|
|
3260
|
-
else:
|
|
3261
|
-
raise RuntimeError("agentic tool-efficiency KPI unsatisfied after corrective prompt")
|
|
3262
|
-
|
|
3263
|
-
elapsed = time.monotonic() - start_time
|
|
3264
|
-
if isinstance(aggregate_retry_telemetry, dict):
|
|
3265
|
-
_sync_corrective_budget_telemetry(aggregate_retry_telemetry)
|
|
3266
|
-
if isinstance(telemetry, dict) and efficiency_summary:
|
|
3267
|
-
telemetry["tool_efficiency"] = efficiency_summary
|
|
3268
|
-
final_quality_summary = self._build_response_quality_summary(
|
|
3269
|
-
output,
|
|
3270
|
-
telemetry if isinstance(telemetry, dict) else None,
|
|
3271
|
-
)
|
|
3272
|
-
if isinstance(telemetry, dict):
|
|
3273
|
-
telemetry["response_quality"] = final_quality_summary
|
|
3274
|
-
self.logger.info(
|
|
3275
|
-
"agentic_analysis_complete",
|
|
3276
|
-
elapsed_sec=round(elapsed, 2),
|
|
3277
|
-
score=getattr(output, "score", None),
|
|
3278
|
-
confidence=getattr(output, "confidence", None),
|
|
3279
|
-
observed_tool_calls=tool_calls_observed,
|
|
3280
|
-
observed_code_read_tool_calls=code_read_calls_observed,
|
|
3281
|
-
observed_skill_calls=skill_calls_observed,
|
|
3282
|
-
observed_skill_effective_calls=skill_effective_calls_observed,
|
|
3283
|
-
observed_docs_tool_calls=docs_tool_calls_observed,
|
|
3284
|
-
observed_docs_read_tool_calls=docs_read_calls_observed,
|
|
3285
|
-
observed_vector_docs_tool_calls=vector_docs_tool_calls_observed,
|
|
3286
|
-
skills_available=skills_available,
|
|
3287
|
-
available_skill_count=len(available_skill_names),
|
|
3288
|
-
available_skill_names=available_skill_names[:8],
|
|
3289
|
-
preloaded_skill_context_used=bool(preloaded_skill_names),
|
|
3290
|
-
preloaded_skill_names=preloaded_skill_names,
|
|
3291
|
-
skills_needed=skills_needed,
|
|
3292
|
-
skills_needed_reason=skills_needed_reason,
|
|
3293
|
-
skills_required=skills_required,
|
|
3294
|
-
advisory_skill_sequence_skipped=advisory_skill_sequence_skipped,
|
|
3295
|
-
docs_required=docs_required,
|
|
3296
|
-
vector_docs_required=vector_docs_required,
|
|
3297
|
-
)
|
|
3298
|
-
if efficiency_summary:
|
|
3299
|
-
self.logger.info(
|
|
3300
|
-
"agentic_tool_efficiency",
|
|
3301
|
-
**efficiency_summary,
|
|
3302
|
-
)
|
|
3303
|
-
skill_effective_rate = efficiency_summary.get("skill_effective_rate")
|
|
3304
|
-
if isinstance(skill_effective_rate, float) and skill_effective_rate < 0.5:
|
|
3305
|
-
self.logger.warning(
|
|
3306
|
-
"agentic_skill_efficiency_low",
|
|
3307
|
-
skill_effective_rate=skill_effective_rate,
|
|
3308
|
-
skill_calls_total=efficiency_summary.get("skill_calls_total"),
|
|
3309
|
-
skill_calls_effective=efficiency_summary.get("skill_calls_effective"),
|
|
3310
|
-
skill_discovery_ratio=efficiency_summary.get("skill_discovery_ratio"),
|
|
3311
|
-
)
|
|
3312
|
-
repetition_rate = efficiency_summary.get("tool_repetition_rate")
|
|
3313
|
-
tool_calls_completed = int(efficiency_summary.get("tool_calls_completed", 0) or 0)
|
|
3314
|
-
if isinstance(repetition_rate, float) and tool_calls_completed >= 6 and repetition_rate > 0.6:
|
|
3315
|
-
self.logger.warning(
|
|
3316
|
-
"agentic_tool_efficiency_low",
|
|
3317
|
-
tool_repetition_rate=repetition_rate,
|
|
3318
|
-
tool_calls_completed=tool_calls_completed,
|
|
3319
|
-
tool_calls_unique=efficiency_summary.get("tool_calls_unique"),
|
|
3320
|
-
)
|
|
3321
|
-
if isinstance(telemetry, dict):
|
|
3322
|
-
skill_calls = int(telemetry.get("event_skill_tool_calls", 0) or 0)
|
|
3323
|
-
effective_skill_calls = int(
|
|
3324
|
-
telemetry.get(
|
|
3325
|
-
"event_skill_execution_effective_tool_calls",
|
|
3326
|
-
telemetry.get("event_skill_effective_tool_calls", 0),
|
|
3327
|
-
)
|
|
3328
|
-
or 0
|
|
3329
|
-
)
|
|
3330
|
-
if skill_calls > 0 and effective_skill_calls == 0:
|
|
3331
|
-
self.logger.warning(
|
|
3332
|
-
"ineffective_skill_use",
|
|
3333
|
-
observed_skill_calls=skill_calls,
|
|
3334
|
-
observed_skill_effective_calls=effective_skill_calls,
|
|
3335
|
-
observed_tool_names=telemetry.get("event_tool_names"),
|
|
3336
|
-
)
|
|
3337
|
-
if isinstance(telemetry, dict):
|
|
3338
|
-
self._last_agent_run_telemetry = telemetry
|
|
3339
|
-
return output
|
|
3340
|
-
|
|
3341
|
-
async def _run_pydantic_ai_analysis(
|
|
3342
|
-
self,
|
|
3343
|
-
evidence: EvidenceBundle,
|
|
3344
|
-
profile: dict[str, Any] | None = None,
|
|
3345
|
-
) -> CodeFindings | None:
|
|
3346
|
-
"""Run PydanticAI-powered code quality analysis.
|
|
3347
|
-
|
|
3348
|
-
Uses the CodeFindings output model for typed, validated results
|
|
3349
|
-
with automatic confidence-based retry logic.
|
|
3350
|
-
|
|
3351
|
-
Args:
|
|
3352
|
-
evidence: EvidenceBundle with git_evidence to analyze.
|
|
3353
|
-
profile: Optional project profile for context.
|
|
3354
|
-
|
|
3355
|
-
Returns:
|
|
3356
|
-
CodeFindings instance with structured analysis results,
|
|
3357
|
-
or None if analysis fails.
|
|
3358
|
-
"""
|
|
3359
|
-
# Prepare code samples for analysis using CodePackBuilder (TSK-196)
|
|
3360
|
-
repo_path = self._get_repo_path(evidence, profile)
|
|
3361
|
-
code_samples = ""
|
|
3362
|
-
|
|
3363
|
-
if repo_path:
|
|
3364
|
-
try:
|
|
3365
|
-
runtime_config = None
|
|
3366
|
-
runtime_config_getter = getattr(self, "_get_runtime_config", None)
|
|
3367
|
-
if callable(runtime_config_getter):
|
|
3368
|
-
runtime_config = runtime_config_getter()
|
|
3369
|
-
|
|
3370
|
-
max_files = 20
|
|
3371
|
-
max_total_chars: int | None = None
|
|
3372
|
-
if runtime_config is not None and hasattr(runtime_config, "llm"):
|
|
3373
|
-
llm_cfg = runtime_config.llm
|
|
3374
|
-
max_files = int(getattr(llm_cfg, "code_review_max_files", max_files))
|
|
3375
|
-
max_total_chars = int(
|
|
3376
|
-
getattr(llm_cfg, "code_review_max_total_chars", self.MAX_TOTAL_CODE_CONTEXT_CHARS)
|
|
3377
|
-
)
|
|
3378
|
-
|
|
3379
|
-
builder = CodePackBuilder(repo_path)
|
|
3380
|
-
pack = builder.build()
|
|
3381
|
-
selected_files = self._select_files_for_llm(
|
|
3382
|
-
pack,
|
|
3383
|
-
max_files=max_files,
|
|
3384
|
-
max_total_chars=max_total_chars,
|
|
3385
|
-
)
|
|
3386
|
-
code_samples = self._format_code_pack(pack, files=selected_files)
|
|
3387
|
-
self.logger.info("code_pack_used", files=pack.total_files_included, scanned=pack.total_files_scanned)
|
|
3388
|
-
self.logger.info(
|
|
3389
|
-
"code_pack_selected_for_pydantic_analysis",
|
|
3390
|
-
selected=len(selected_files),
|
|
3391
|
-
source_files=sum(1 for file_ev in selected_files if self._is_source_code_file(file_ev.file_path)),
|
|
3392
|
-
)
|
|
3393
|
-
except CODE_PACK_RECOVERABLE_ERRORS as e:
|
|
3394
|
-
self.logger.warning(
|
|
3395
|
-
"code_pack_build_failed",
|
|
3396
|
-
error=str(e),
|
|
3397
|
-
error_type=type(e).__name__,
|
|
3398
|
-
handler="_run_pydantic_code_analysis.code_pack_builder",
|
|
3399
|
-
repo_path=str(repo_path),
|
|
3400
|
-
)
|
|
3401
|
-
# Fallback will happen below if code_samples is empty
|
|
3402
|
-
|
|
3403
|
-
if not code_samples:
|
|
3404
|
-
# Fallback to legacy preparation
|
|
3405
|
-
max_files = 5
|
|
3406
|
-
max_chars_per_file = 3000
|
|
3407
|
-
runtime_config = None
|
|
3408
|
-
runtime_config_getter = getattr(self, "_get_runtime_config", None)
|
|
3409
|
-
if callable(runtime_config_getter):
|
|
3410
|
-
runtime_config = runtime_config_getter()
|
|
3411
|
-
if runtime_config is not None and hasattr(runtime_config, "llm"):
|
|
3412
|
-
llm_cfg = runtime_config.llm
|
|
3413
|
-
max_files = min(max(1, int(getattr(llm_cfg, "code_review_max_files", max_files))), 10)
|
|
3414
|
-
total_chars = int(getattr(llm_cfg, "code_review_max_total_chars", self.MAX_TOTAL_CODE_CONTEXT_CHARS))
|
|
3415
|
-
max_chars_per_file = max(1000, total_chars // max(1, max_files))
|
|
3416
|
-
code_samples = self._prepare_code_samples(
|
|
3417
|
-
evidence,
|
|
3418
|
-
max_files=max_files,
|
|
3419
|
-
max_chars_per_file=max_chars_per_file,
|
|
3420
|
-
)
|
|
3421
|
-
|
|
3422
|
-
if not code_samples:
|
|
3423
|
-
self.logger.info("no_code_samples_available")
|
|
3424
|
-
return None
|
|
3425
|
-
|
|
3426
|
-
# Construct the analysis prompt
|
|
3427
|
-
user_prompt = self._build_analysis_prompt(code_samples, evidence, profile)
|
|
3428
|
-
|
|
3429
|
-
if self.settings.protocol == LLMProtocolType.OPENAI and self._uses_local_openai_protocol():
|
|
3430
|
-
return await self._run_ollama_code_analysis_direct(user_prompt=user_prompt)
|
|
3431
|
-
|
|
3432
|
-
# Build dependencies for PydanticAI agent
|
|
3433
|
-
deps = AuditDeps.from_evidence_bundle(
|
|
3434
|
-
evidence=evidence,
|
|
3435
|
-
profile=profile,
|
|
3436
|
-
settings=self.settings,
|
|
3437
|
-
evidence_corpus=self._evidence_corpus,
|
|
3438
|
-
)
|
|
3439
|
-
|
|
3440
|
-
# Run the PydanticAI agent
|
|
3441
|
-
try:
|
|
3442
|
-
output = await self._run_pydantic_agent(
|
|
3443
|
-
system_prompt=CODE_ANALYSIS_SYSTEM_PROMPT,
|
|
3444
|
-
user_prompt=user_prompt,
|
|
3445
|
-
result_type=CodeFindings,
|
|
3446
|
-
complexity="standard",
|
|
3447
|
-
deps=deps,
|
|
3448
|
-
)
|
|
3449
|
-
return output
|
|
3450
|
-
except Exception as e:
|
|
3451
|
-
self.logger.warning(
|
|
3452
|
-
"pydantic_ai_agent_failed",
|
|
3453
|
-
error=str(e),
|
|
3454
|
-
error_type=type(e).__name__,
|
|
3455
|
-
)
|
|
3456
|
-
raise
|
|
3457
|
-
|
|
3458
|
-
async def _run_ollama_code_analysis_direct(self, *, user_prompt: str) -> CodeFindings:
|
|
3459
|
-
"""Run CodeFindings generation via direct Ollama messages API.
|
|
3460
|
-
|
|
3461
|
-
OLLAMA's OpenAI-compat endpoint can reject certain assistant message shapes
|
|
3462
|
-
emitted by structured-output runtimes. This path uses the native Ollama
|
|
3463
|
-
messages wrapper and validates JSON into CodeFindings.
|
|
3464
|
-
"""
|
|
3465
|
-
client = self.settings.get_client()
|
|
3466
|
-
model_name = self.settings.select_model("standard") if hasattr(self.settings, "select_model") else None
|
|
3467
|
-
selected_model = model_name or self.settings.model_standard
|
|
3468
|
-
options: dict[str, Any] = {}
|
|
3469
|
-
ollama_num_ctx = getattr(self.settings, "ollama_num_ctx", None)
|
|
3470
|
-
if isinstance(ollama_num_ctx, int) and ollama_num_ctx > 0:
|
|
3471
|
-
options["num_ctx"] = ollama_num_ctx
|
|
3472
|
-
|
|
3473
|
-
def _create_message():
|
|
3474
|
-
return client.messages.create(
|
|
3475
|
-
model=selected_model,
|
|
3476
|
-
max_tokens=self.settings.max_tokens_per_request,
|
|
3477
|
-
temperature=0.0,
|
|
3478
|
-
system=CODE_ANALYSIS_SYSTEM_PROMPT,
|
|
3479
|
-
messages=[{"role": "user", "content": user_prompt}],
|
|
3480
|
-
format="json",
|
|
3481
|
-
options=options,
|
|
3482
|
-
)
|
|
3483
|
-
|
|
3484
|
-
message = await asyncio.to_thread(_create_message)
|
|
3485
|
-
content_parts: list[str] = []
|
|
3486
|
-
for block in getattr(message, "content", []) or []:
|
|
3487
|
-
text = getattr(block, "text", None)
|
|
3488
|
-
if text:
|
|
3489
|
-
content_parts.append(text)
|
|
3490
|
-
response_text = "\n".join(content_parts).strip()
|
|
3491
|
-
payload = self._strip_json_fence(response_text)
|
|
3492
|
-
try:
|
|
3493
|
-
return CodeFindings.model_validate_json(payload)
|
|
3494
|
-
except STRUCTURED_OUTPUT_RECOVERABLE_ERRORS as exc:
|
|
3495
|
-
self.logger.debug(
|
|
3496
|
-
"ollama_code_findings_json_parse_retry",
|
|
3497
|
-
error_type=type(exc).__name__,
|
|
3498
|
-
)
|
|
3499
|
-
start = payload.find("{")
|
|
3500
|
-
end = payload.rfind("}")
|
|
3501
|
-
if 0 <= start < end:
|
|
3502
|
-
return CodeFindings.model_validate_json(payload[start : end + 1])
|
|
3503
|
-
raise
|
|
3504
|
-
|
|
3505
|
-
def _format_code_pack(self, pack: Any, files: list[Any] | None = None) -> str:
|
|
3506
|
-
"""Format CodeEvidencePack for prompt.
|
|
3507
|
-
|
|
3508
|
-
Args:
|
|
3509
|
-
pack: CodeEvidencePack instance.
|
|
3510
|
-
|
|
3511
|
-
Returns:
|
|
3512
|
-
Formatted string.
|
|
3513
|
-
"""
|
|
3514
|
-
selected_files = files or pack.files
|
|
3515
|
-
parts = [
|
|
3516
|
-
f"Code Evidence Pack (Selected Files: {len(selected_files)} / {pack.total_files_included})",
|
|
3517
|
-
"Selected file list:",
|
|
3518
|
-
]
|
|
3519
|
-
parts.extend(f"- {file_ev.file_path}" for file_ev in selected_files)
|
|
3520
|
-
parts.append("")
|
|
3521
|
-
|
|
3522
|
-
for file_ev in selected_files:
|
|
3523
|
-
header = f"### File: {file_ev.file_path}"
|
|
3524
|
-
if file_ev.priority <= 2:
|
|
3525
|
-
header += " [HIGH PRIORITY]"
|
|
3526
|
-
if file_ev.truncated:
|
|
3527
|
-
header += " [TRUNCATED]"
|
|
3528
|
-
|
|
3529
|
-
parts.append(f"{header}\n```\n{file_ev.content}\n```\n")
|
|
3530
|
-
|
|
3531
|
-
return "\n".join(parts)
|
|
3532
|
-
|
|
3533
|
-
def _select_files_for_llm(
|
|
3534
|
-
self,
|
|
3535
|
-
code_pack: CodeEvidencePack,
|
|
3536
|
-
max_files: int = 20,
|
|
3537
|
-
max_infra_files: int = 6,
|
|
3538
|
-
min_source_files: int = 12,
|
|
3539
|
-
max_total_chars: int | None = None,
|
|
3540
|
-
) -> list[Any]:
|
|
3541
|
-
"""Select a source-first subset of files for LLM input quality.
|
|
3542
|
-
|
|
3543
|
-
Args:
|
|
3544
|
-
code_pack: Code evidence pack to select from.
|
|
3545
|
-
max_files: Maximum number of files to select.
|
|
3546
|
-
max_infra_files: Maximum infrastructure files (priority <= 5).
|
|
3547
|
-
min_source_files: Minimum source code files to include.
|
|
3548
|
-
max_total_chars: Total content character budget. Defaults to
|
|
3549
|
-
``MAX_TOTAL_CODE_CONTEXT_CHARS`` when *None*.
|
|
3550
|
-
|
|
3551
|
-
Returns:
|
|
3552
|
-
Selected file list, ordered by priority then path, within budget.
|
|
3553
|
-
"""
|
|
3554
|
-
if not code_pack.files:
|
|
3555
|
-
return []
|
|
3556
|
-
|
|
3557
|
-
effective_budget = max_total_chars if max_total_chars is not None else self.MAX_TOTAL_CODE_CONTEXT_CHARS
|
|
3558
|
-
effective_max_infra_files = min(max_infra_files, max(1, max_files // 6))
|
|
3559
|
-
per_file_budget_cap = max(1200, effective_budget // max(1, max_files))
|
|
3560
|
-
infra_file_budget_cap = min(4000, per_file_budget_cap)
|
|
3561
|
-
source_file_budget_cap = max(per_file_budget_cap, min(6000, per_file_budget_cap * 2))
|
|
3562
|
-
|
|
3563
|
-
sorted_files = sorted(code_pack.files, key=lambda file_ev: (file_ev.priority, file_ev.file_path))
|
|
3564
|
-
|
|
3565
|
-
security_path_tokens = (
|
|
3566
|
-
"security",
|
|
3567
|
-
"auth",
|
|
3568
|
-
"token",
|
|
3569
|
-
"credential",
|
|
3570
|
-
"password",
|
|
3571
|
-
"secret",
|
|
3572
|
-
"sql",
|
|
3573
|
-
"query",
|
|
3574
|
-
"db",
|
|
3575
|
-
"store",
|
|
3576
|
-
"state",
|
|
3577
|
-
"agent",
|
|
3578
|
-
"workflow",
|
|
3579
|
-
"llm",
|
|
3580
|
-
"provider",
|
|
3581
|
-
)
|
|
3582
|
-
|
|
3583
|
-
def _source_rank(file_ev: Any) -> tuple[int, int, int, str]:
|
|
3584
|
-
normalized = str(getattr(file_ev, "file_path", "")).replace("\\", "/").lower()
|
|
3585
|
-
security_relevant = 0 if any(token in normalized for token in security_path_tokens) else 1
|
|
3586
|
-
tests_penalty = 1 if normalized.startswith("tests/") or "/tests/" in normalized else 0
|
|
3587
|
-
content_len = len(getattr(file_ev, "content", "") or "")
|
|
3588
|
-
oversized_penalty = 1 if content_len > source_file_budget_cap else 0
|
|
3589
|
-
return (security_relevant, tests_penalty, oversized_penalty, normalized)
|
|
3590
|
-
|
|
3591
|
-
source_files = sorted(
|
|
3592
|
-
[file_ev for file_ev in sorted_files if self._is_source_code_file(file_ev.file_path)],
|
|
3593
|
-
key=_source_rank,
|
|
3594
|
-
)
|
|
3595
|
-
source_files_non_truncated = [
|
|
3596
|
-
file_ev for file_ev in source_files if not bool(getattr(file_ev, "truncated", False))
|
|
3597
|
-
]
|
|
3598
|
-
source_files_truncated = [file_ev for file_ev in source_files if bool(getattr(file_ev, "truncated", False))]
|
|
3599
|
-
source_files = source_files_non_truncated
|
|
3600
|
-
infra_files = [
|
|
3601
|
-
file_ev
|
|
3602
|
-
for file_ev in sorted_files
|
|
3603
|
-
if (
|
|
3604
|
-
file_ev.priority <= 5
|
|
3605
|
-
and not self._is_source_code_file(file_ev.file_path)
|
|
3606
|
-
and Path(str(file_ev.file_path)).name.lower() not in {"readme", "readme.md", "readme.rst", "readme.txt"}
|
|
3607
|
-
)
|
|
3608
|
-
]
|
|
3609
|
-
other_files = [
|
|
3610
|
-
file_ev for file_ev in sorted_files if file_ev not in source_files and file_ev not in infra_files
|
|
3611
|
-
]
|
|
3612
|
-
|
|
3613
|
-
selected: list[Any] = []
|
|
3614
|
-
total_chars = 0
|
|
3615
|
-
|
|
3616
|
-
def _clone_with_budget(file_ev: Any, budget: int) -> Any:
|
|
3617
|
-
content = getattr(file_ev, "content", "") or ""
|
|
3618
|
-
if len(content) <= budget:
|
|
3619
|
-
return file_ev
|
|
3620
|
-
truncated_content = content[: max(0, budget)]
|
|
3621
|
-
if hasattr(file_ev, "model_copy"):
|
|
3622
|
-
return file_ev.model_copy(update={"content": truncated_content, "truncated": True})
|
|
3623
|
-
candidate = file_ev
|
|
3624
|
-
candidate.content = truncated_content
|
|
3625
|
-
candidate.truncated = True
|
|
3626
|
-
return candidate
|
|
3627
|
-
|
|
3628
|
-
def _try_add(file_ev: Any, *, file_budget_cap: int | None = None) -> bool:
|
|
3629
|
-
"""Add file if within char budget. Returns True if added."""
|
|
3630
|
-
nonlocal total_chars
|
|
3631
|
-
content = getattr(file_ev, "content", "") or ""
|
|
3632
|
-
content_len = len(content)
|
|
3633
|
-
remaining = max(0, effective_budget - total_chars)
|
|
3634
|
-
if remaining <= 0:
|
|
3635
|
-
return False
|
|
3636
|
-
|
|
3637
|
-
candidate = file_ev
|
|
3638
|
-
if file_budget_cap is not None and content_len > file_budget_cap:
|
|
3639
|
-
# Prefer complete files; avoid adding partial excerpts unless this is
|
|
3640
|
-
# the first/only candidate we can include.
|
|
3641
|
-
if selected:
|
|
3642
|
-
return False
|
|
3643
|
-
candidate = _clone_with_budget(file_ev, file_budget_cap)
|
|
3644
|
-
content_len = len(getattr(candidate, "content", "") or "")
|
|
3645
|
-
if content_len <= 0:
|
|
3646
|
-
return False
|
|
3647
|
-
|
|
3648
|
-
if content_len > remaining:
|
|
3649
|
-
if selected:
|
|
3650
|
-
return False
|
|
3651
|
-
# Hard-cap the very first file to keep prompt context within budget.
|
|
3652
|
-
candidate = _clone_with_budget(candidate, remaining)
|
|
3653
|
-
content_len = len(getattr(candidate, "content", "") or "")
|
|
3654
|
-
if content_len <= 0:
|
|
3655
|
-
return False
|
|
3656
|
-
|
|
3657
|
-
selected.append(candidate)
|
|
3658
|
-
total_chars += content_len
|
|
3659
|
-
return True
|
|
3660
|
-
|
|
3661
|
-
# Keep core infra context but cap it to avoid drowning source implementation.
|
|
3662
|
-
for f in infra_files[:effective_max_infra_files]:
|
|
3663
|
-
if len(selected) >= max_files:
|
|
3664
|
-
break
|
|
3665
|
-
if not _try_add(f, file_budget_cap=infra_file_budget_cap):
|
|
3666
|
-
continue
|
|
3667
|
-
|
|
3668
|
-
source_slots = max(0, max_files - len(selected))
|
|
3669
|
-
target_source = min(
|
|
3670
|
-
len(source_files_non_truncated),
|
|
3671
|
-
source_slots,
|
|
3672
|
-
)
|
|
3673
|
-
for f in source_files_non_truncated[:target_source]:
|
|
3674
|
-
if len(selected) >= max_files:
|
|
3675
|
-
break
|
|
3676
|
-
if not _try_add(f, file_budget_cap=source_file_budget_cap):
|
|
3677
|
-
continue
|
|
3678
|
-
|
|
3679
|
-
selected_source_count = sum(1 for f in selected if self._is_source_code_file(getattr(f, "file_path", "")))
|
|
3680
|
-
if selected_source_count < min_source_files:
|
|
3681
|
-
needed_source = min_source_files - selected_source_count
|
|
3682
|
-
for f in source_files_truncated:
|
|
3683
|
-
if needed_source <= 0 or len(selected) >= max_files:
|
|
3684
|
-
break
|
|
3685
|
-
if not _try_add(f, file_budget_cap=source_file_budget_cap):
|
|
3686
|
-
continue
|
|
3687
|
-
needed_source -= 1
|
|
3688
|
-
|
|
3689
|
-
for file_ev in source_files_non_truncated[target_source:] + source_files_truncated + other_files:
|
|
3690
|
-
if len(selected) >= max_files:
|
|
3691
|
-
break
|
|
3692
|
-
per_file_cap = (
|
|
3693
|
-
source_file_budget_cap if self._is_source_code_file(file_ev.file_path) else infra_file_budget_cap
|
|
3694
|
-
)
|
|
3695
|
-
if not _try_add(file_ev, file_budget_cap=per_file_cap):
|
|
3696
|
-
continue
|
|
3697
|
-
|
|
3698
|
-
# Guarantee at least one source file in selection when available; this avoids
|
|
3699
|
-
# infra-only contexts on tight budgets (e.g., large README consuming all chars).
|
|
3700
|
-
selected_has_source = any(self._is_source_code_file(f.file_path) for f in selected)
|
|
3701
|
-
if source_files and not selected_has_source:
|
|
3702
|
-
source_budget = max(1000, effective_budget // 2)
|
|
3703
|
-
source_candidate = _clone_with_budget(source_files[0], source_budget)
|
|
3704
|
-
source_len = len(getattr(source_candidate, "content", "") or "")
|
|
3705
|
-
if source_len > 0:
|
|
3706
|
-
while selected and (total_chars + source_len > effective_budget):
|
|
3707
|
-
removed = selected.pop()
|
|
3708
|
-
total_chars = max(0, total_chars - len(getattr(removed, "content", "") or ""))
|
|
3709
|
-
if total_chars + source_len <= effective_budget:
|
|
3710
|
-
selected.append(source_candidate)
|
|
3711
|
-
total_chars += source_len
|
|
3712
|
-
|
|
3713
|
-
# Deduplicate while preserving order
|
|
3714
|
-
deduped: list[Any] = []
|
|
3715
|
-
seen: set[str] = set()
|
|
3716
|
-
for file_ev in selected:
|
|
3717
|
-
if file_ev.file_path in seen:
|
|
3718
|
-
continue
|
|
3719
|
-
seen.add(file_ev.file_path)
|
|
3720
|
-
deduped.append(file_ev)
|
|
3721
|
-
|
|
3722
|
-
dropped = len(code_pack.files) - len(deduped)
|
|
3723
|
-
if dropped > 0:
|
|
3724
|
-
self.logger.info(
|
|
3725
|
-
"llm_file_selection_budget_applied",
|
|
3726
|
-
selected=len(deduped),
|
|
3727
|
-
dropped=dropped,
|
|
3728
|
-
total_chars=total_chars,
|
|
3729
|
-
budget=effective_budget,
|
|
3730
|
-
max_files=max_files,
|
|
3731
|
-
)
|
|
3732
|
-
|
|
3733
|
-
return deduped[:max_files]
|
|
3734
|
-
|
|
3735
|
-
def _is_source_code_file(self, file_path: str) -> bool:
|
|
3736
|
-
normalized = file_path.replace("\\", "/").lower()
|
|
3737
|
-
if normalized.startswith("src/") or "/src/" in normalized:
|
|
3738
|
-
return True
|
|
3739
|
-
return normalized.endswith((".py", ".java", ".kt", ".kts", ".js", ".ts", ".tsx", ".go", ".rb", ".php"))
|
|
3740
|
-
|
|
3741
|
-
def _build_analysis_prompt(
|
|
3742
|
-
self,
|
|
3743
|
-
code_samples: str,
|
|
3744
|
-
evidence: EvidenceBundle,
|
|
3745
|
-
profile: dict[str, Any] | None = None,
|
|
3746
|
-
) -> str:
|
|
3747
|
-
"""Build the analysis prompt for the PydanticAI agent.
|
|
3748
|
-
|
|
3749
|
-
Args:
|
|
3750
|
-
code_samples: Formatted code samples string.
|
|
3751
|
-
evidence: EvidenceBundle for context.
|
|
3752
|
-
profile: Optional project profile.
|
|
3753
|
-
|
|
3754
|
-
Returns:
|
|
3755
|
-
Formatted user prompt string.
|
|
3756
|
-
"""
|
|
3757
|
-
context_parts = []
|
|
3758
|
-
|
|
3759
|
-
if profile:
|
|
3760
|
-
domain = profile.get("domain", "unknown")
|
|
3761
|
-
criticality = profile.get("criticality", "unknown")
|
|
3762
|
-
context_parts.append(f"Project Context: Domain={domain}, Criticality={criticality}")
|
|
3763
|
-
|
|
3764
|
-
if evidence.repository:
|
|
3765
|
-
context_parts.append(f"Repository: {evidence.repository}")
|
|
3766
|
-
|
|
3767
|
-
file_count = len(evidence.git_evidence)
|
|
3768
|
-
context_parts.append(f"Total files in evidence: {file_count}")
|
|
3769
|
-
|
|
3770
|
-
context = "\n".join(context_parts) if context_parts else "No additional context"
|
|
3771
|
-
evidence_context = ""
|
|
3772
|
-
if self._evidence_corpus:
|
|
3773
|
-
evidence_context = "\n\n" + self._evidence_corpus.get_context_summary(max_chars=2500)
|
|
3774
|
-
|
|
3775
|
-
return f"""Analyze the following code files for quality, security, and maintainability issues.
|
|
3776
|
-
|
|
3777
|
-
## Context
|
|
3778
|
-
{context}
|
|
3779
|
-
{evidence_context}
|
|
3780
|
-
|
|
3781
|
-
## Code Files
|
|
3782
|
-
{code_samples}
|
|
3783
|
-
|
|
3784
|
-
Provide a comprehensive analysis with:
|
|
3785
|
-
1. Overall quality score (0-10)
|
|
3786
|
-
2. Specific issues found (with file paths and recommendations)
|
|
3787
|
-
3. Detected patterns (positive practices and anti-patterns)
|
|
3788
|
-
4. Your confidence level in the analysis
|
|
3789
|
-
5. Clear reasoning for your assessment"""
|
|
3790
|
-
|
|
3791
|
-
def _build_agentic_investigation_prompt(
|
|
3792
|
-
self,
|
|
3793
|
-
*,
|
|
3794
|
-
evidence: EvidenceBundle,
|
|
3795
|
-
profile: dict[str, Any] | None,
|
|
3796
|
-
repo_path: Path,
|
|
3797
|
-
evidence_corpus: EvidenceCorpus | None,
|
|
3798
|
-
skills_available: bool,
|
|
3799
|
-
available_skill_names: list[str] | None = None,
|
|
3800
|
-
vector_docs_required: bool = False,
|
|
3801
|
-
preloaded_skill_context: str = "",
|
|
3802
|
-
postgres_evidence_ready: bool = False,
|
|
3803
|
-
compact_mode: bool = False,
|
|
3804
|
-
strict_skill_required: bool = True,
|
|
3805
|
-
skills_needed: bool = False,
|
|
3806
|
-
skills_needed_reason: str = "",
|
|
3807
|
-
) -> str:
|
|
3808
|
-
"""Build a minimal, tool-first prompt for AGENTIC mode.
|
|
3809
|
-
|
|
3810
|
-
Intentionally avoids embedding large code snippets. The agent should
|
|
3811
|
-
retrieve required code/docs via attached toolsets.
|
|
3812
|
-
"""
|
|
3813
|
-
evidence_path_diagnostics = self._build_agentic_evidence_path_diagnostics(
|
|
3814
|
-
evidence=evidence,
|
|
3815
|
-
repo_path=repo_path,
|
|
3816
|
-
)
|
|
3817
|
-
|
|
3818
|
-
context_lines: list[str] = [
|
|
3819
|
-
f"Repository path: {repo_path}",
|
|
3820
|
-
f"Repository name: {evidence.repository}",
|
|
3821
|
-
f"Git evidence files available: {len(evidence.git_evidence)}",
|
|
3822
|
-
]
|
|
3823
|
-
|
|
3824
|
-
state_context = dict(self._state_context) if isinstance(self._state_context, dict) else {}
|
|
3825
|
-
search_strategy_guidance = ""
|
|
3826
|
-
|
|
3827
|
-
if state_context:
|
|
3828
|
-
raw_analysis = state_context.get("requirement_analysis_result")
|
|
3829
|
-
if not raw_analysis:
|
|
3830
|
-
raw_analysis = state_context.get("context", {}).get("requirement_analysis_result")
|
|
3831
|
-
if raw_analysis:
|
|
3832
|
-
analysis_res = RequirementAnalysisResult.from_mapping(raw_analysis)
|
|
3833
|
-
if analysis_res:
|
|
3834
|
-
# Phase 123 (DD-123.9): Thread guidance text for shared-library promotion.
|
|
3835
|
-
_interp = state_context.get("context", {}).get("requirement_interpretation") or {}
|
|
3836
|
-
_guidance = str(_interp.get("detailed_guidance") or "") if isinstance(_interp, dict) else ""
|
|
3837
|
-
strategy_hint = derive_code_search_strategy(
|
|
3838
|
-
analysis_res,
|
|
3839
|
-
requirement_text=str(state_context.get("requirement_text") or ""),
|
|
3840
|
-
category=str(state_context.get("requirement_category") or ""),
|
|
3841
|
-
guidance_text=_guidance,
|
|
3842
|
-
)
|
|
3843
|
-
if strategy_hint is not None:
|
|
3844
|
-
search_strategy_guidance = _render_phase115_strategy_guidance(strategy_hint)
|
|
3845
|
-
|
|
3846
|
-
if state_context:
|
|
3847
|
-
project_storage_key = str(state_context.get("project_storage_key") or "").strip()
|
|
3848
|
-
repo_storage_key = str(state_context.get("repo_storage_key") or "").strip()
|
|
3849
|
-
resolved_project = str(state_context.get("resolved_project") or "").strip()
|
|
3850
|
-
if project_storage_key:
|
|
3851
|
-
context_lines.append(f"State project key: {project_storage_key}")
|
|
3852
|
-
if repo_storage_key:
|
|
3853
|
-
context_lines.append(f"State repo key: {repo_storage_key}")
|
|
3854
|
-
if resolved_project:
|
|
3855
|
-
context_lines.append(f"Resolved project alias: {resolved_project}")
|
|
3856
|
-
|
|
3857
|
-
if profile:
|
|
3858
|
-
domain = profile.get("domain", "unknown")
|
|
3859
|
-
criticality = profile.get("criticality", "unknown")
|
|
3860
|
-
context_lines.append(f"Project context: domain={domain}, criticality={criticality}")
|
|
3861
|
-
|
|
3862
|
-
sample_limit = 10 if compact_mode else 25
|
|
3863
|
-
sample_paths = [str(item.source_id).strip() for item in evidence.git_evidence[:sample_limit] if item.source_id]
|
|
3864
|
-
if sample_paths:
|
|
3865
|
-
context_lines.append("Example candidate files from evidence seed:")
|
|
3866
|
-
context_lines.extend(f"- {path}" for path in sample_paths)
|
|
3867
|
-
|
|
3868
|
-
docs_count = len(evidence_corpus.documents) if evidence_corpus is not None else 0
|
|
3869
|
-
if docs_count > 0:
|
|
3870
|
-
context_lines.append(f"Evidence corpus documents available: {docs_count}")
|
|
3871
|
-
context_lines.append(
|
|
3872
|
-
"Use list_evidence_documents/search_evidence/read_evidence_document for docs retrieval."
|
|
3873
|
-
)
|
|
3874
|
-
context_lines.append(
|
|
3875
|
-
"Docs location guard: keep retrieval scoped to current project context; avoid cross-project docs unless explicitly required."
|
|
3876
|
-
)
|
|
3877
|
-
if postgres_evidence_ready:
|
|
3878
|
-
context_lines.append(
|
|
3879
|
-
"State-backed evidence retrieval available (Postgres): prioritize targeted queries over broad scans."
|
|
3880
|
-
)
|
|
3881
|
-
if vector_docs_required:
|
|
3882
|
-
context_lines.append(
|
|
3883
|
-
"Vector retrieval available: use search_evidence_vector for docs and search_code_vector for code grounding."
|
|
3884
|
-
)
|
|
3885
|
-
elif postgres_evidence_ready or vector_docs_required:
|
|
3886
|
-
context_lines.append("Local evidence corpus is empty for this run.")
|
|
3887
|
-
if postgres_evidence_ready:
|
|
3888
|
-
context_lines.append(
|
|
3889
|
-
"State-backed evidence retrieval available (Postgres): use retrieval tools instead of broad repository scans."
|
|
3890
|
-
)
|
|
3891
|
-
if vector_docs_required:
|
|
3892
|
-
context_lines.append(
|
|
3893
|
-
"Vector retrieval available: call search_evidence_vector (docs) or search_code_vector (code) for requirement-level grounding."
|
|
3894
|
-
)
|
|
3895
|
-
else:
|
|
3896
|
-
context_lines.append("Evidence corpus unavailable for this run.")
|
|
3897
|
-
if skills_available:
|
|
3898
|
-
context_lines.append(
|
|
3899
|
-
"Skill activation decision: "
|
|
3900
|
-
f"skills_needed={'true' if skills_needed else 'false'}"
|
|
3901
|
-
+ (f" (reason={skills_needed_reason})" if str(skills_needed_reason).strip() else "")
|
|
3902
|
-
)
|
|
3903
|
-
context_lines.append(
|
|
3904
|
-
"Skills toolset available: use skills only when directly useful; list_skills is discovery, not sufficient evidence by itself."
|
|
3905
|
-
)
|
|
3906
|
-
if preloaded_skill_context:
|
|
3907
|
-
context_lines.append(
|
|
3908
|
-
"Preloaded skill guidance is already attached; avoid calling list_skills unless preloaded guidance is missing required details."
|
|
3909
|
-
)
|
|
3910
|
-
if available_skill_names:
|
|
3911
|
-
context_lines.append("Available skills (policy-allowed):")
|
|
3912
|
-
context_lines.extend(f"- {name}" for name in available_skill_names[:8])
|
|
3913
|
-
if not skills_needed:
|
|
3914
|
-
context_lines.append(
|
|
3915
|
-
"Skill policy: skills_needed=false for this run; keep skill usage optional and only call skill tools when they directly improve evidence quality."
|
|
3916
|
-
)
|
|
3917
|
-
else:
|
|
3918
|
-
context_lines.append("Skills toolset unavailable for this run.")
|
|
3919
|
-
if skills_needed:
|
|
3920
|
-
context_lines.append(
|
|
3921
|
-
"Skill policy fallback: skills were requested but toolset is unavailable; continue without skill calls."
|
|
3922
|
-
)
|
|
3923
|
-
|
|
3924
|
-
context = "\n".join(context_lines)
|
|
3925
|
-
preloaded_skill_section = ""
|
|
3926
|
-
if preloaded_skill_context:
|
|
3927
|
-
preloaded_skill_section = (
|
|
3928
|
-
"\n## Preloaded Skill Guidance\n"
|
|
3929
|
-
"Use this as immediate run guidance without requiring initial skill discovery calls:\n"
|
|
3930
|
-
f"{preloaded_skill_context}\n"
|
|
3931
|
-
)
|
|
3932
|
-
self._log_trace_payload(
|
|
3933
|
-
event_name="agentic_trace_evidence_context_assembly",
|
|
3934
|
-
elapsed_sec=0.0,
|
|
3935
|
-
payload={
|
|
3936
|
-
"repo_path": str(repo_path),
|
|
3937
|
-
"repository": evidence.repository,
|
|
3938
|
-
"evidence_path_diagnostics": evidence_path_diagnostics,
|
|
3939
|
-
"context_line_count": len(context_lines),
|
|
3940
|
-
"docs_available": docs_count > 0,
|
|
3941
|
-
"docs_document_count": docs_count,
|
|
3942
|
-
"skills_available": skills_available,
|
|
3943
|
-
"available_skill_names": list(available_skill_names or [])[:8],
|
|
3944
|
-
"vector_docs_required": vector_docs_required,
|
|
3945
|
-
"preloaded_skill_context_chars": len(preloaded_skill_context),
|
|
3946
|
-
"postgres_evidence_ready": postgres_evidence_ready,
|
|
3947
|
-
"compact_mode": compact_mode,
|
|
3948
|
-
"skills_needed": skills_needed,
|
|
3949
|
-
"skills_needed_reason": str(skills_needed_reason or ""),
|
|
3950
|
-
"strict_skill_required": strict_skill_required,
|
|
3951
|
-
},
|
|
3952
|
-
)
|
|
3953
|
-
compact_skill_guidance = (
|
|
3954
|
-
"9. Requirement-driven skill policy: skills_needed=false, so skill usage is optional and should be used only for clear evidence gains."
|
|
3955
|
-
if not skills_needed
|
|
3956
|
-
else (
|
|
3957
|
-
"9. Requirement-driven skill policy: skills_needed=true, so prioritize one effective skill sequence "
|
|
3958
|
-
"(load_skill -> read_skill_resource/run_skill_script) when it materially improves grounding."
|
|
3959
|
-
)
|
|
3960
|
-
)
|
|
3961
|
-
|
|
3962
|
-
interpretation = self._extract_requirement_interpretation_from_state_context(state_context)
|
|
3963
|
-
evidence_targets = []
|
|
3964
|
-
is_arch_requirement = False
|
|
3965
|
-
if isinstance(interpretation, dict):
|
|
3966
|
-
evidence_targets = [str(t).lower() for t in interpretation.get("evidence_targets", [])]
|
|
3967
|
-
combined_arch = f"{interpretation.get('intent', '')} {interpretation.get('control_objective', '')}".lower()
|
|
3968
|
-
is_arch_requirement = any(
|
|
3969
|
-
marker in combined_arch
|
|
3970
|
-
for marker in (
|
|
3971
|
-
"hexagonal",
|
|
3972
|
-
"clean architecture",
|
|
3973
|
-
"ports",
|
|
3974
|
-
"adapters",
|
|
3975
|
-
"domain logic",
|
|
3976
|
-
"domain",
|
|
3977
|
-
"kiến trúc",
|
|
3978
|
-
"phân lớp",
|
|
3979
|
-
)
|
|
3980
|
-
)
|
|
3981
|
-
|
|
3982
|
-
docs_guidance = ""
|
|
3983
|
-
if is_arch_requirement:
|
|
3984
|
-
docs_guidance = "\n10. Architecture Policy: This is a Clean Architecture requirement. Use `ast_grep_search` with pattern `import $A` to check cross-boundary imports (e.g. domain importing infrastructure or framework like @Entity/@Table). Do not guess dependencies without structural search."
|
|
3985
|
-
elif "docs" in evidence_targets and "code" not in evidence_targets:
|
|
3986
|
-
docs_guidance = "\n10. Docs-First Policy: This requirement relies exclusively on documentation (SLA, Support). ALWAYS call search_docs or search_evidence_vector BEFORE any code search. Source code rarely contains explicit SLA contracts."
|
|
3987
|
-
elif "docs" in evidence_targets:
|
|
3988
|
-
docs_guidance = "\n10. Hybrid Evidence Policy: This requirement needs both documentation and code. Start with search_docs or search_evidence_vector to understand the design, then use code tools to verify implementation."
|
|
3989
|
-
|
|
3990
|
-
if compact_mode:
|
|
3991
|
-
return f"""Perform code quality and security analysis using TOOL-FIRST investigation.
|
|
3992
|
-
|
|
3993
|
-
## Run Context
|
|
3994
|
-
{context}
|
|
3995
|
-
{preloaded_skill_section}
|
|
3996
|
-
|
|
3997
|
-
## Required Approach
|
|
3998
|
-
1. Start with grep_search or rg_search, then read_file on a concrete hit.
|
|
3999
|
-
2. Use focused reads only; avoid directory-chaining loops.
|
|
4000
|
-
3. If state/vector retrieval is available, call search_evidence_vector or search_code_vector at least once before final answer.
|
|
4001
|
-
4. Correlate findings with concrete file paths and line ranges when possible.
|
|
4002
|
-
5. Call exactly one tool per turn and inspect result before the next call.
|
|
4003
|
-
6. If path errors repeat twice, pivot to grep_search/rg_search and continue.
|
|
4004
|
-
7. Avoid repeating the same tool pattern more than twice without new evidence.
|
|
4005
|
-
8. Do not execute exhaustive checklist probing; use at most 6 total tool calls unless critical evidence is still missing.
|
|
4006
|
-
{compact_skill_guidance}{docs_guidance}
|
|
4007
|
-
{search_strategy_guidance}
|
|
4008
|
-
|
|
4009
|
-
## Output
|
|
4010
|
-
Provide:
|
|
4011
|
-
1. Overall score (0-10)
|
|
4012
|
-
2. Concrete issues (severity, file path, recommendation)
|
|
4013
|
-
3. Positive/negative patterns observed
|
|
4014
|
-
4. Confidence and concise reasoning
|
|
4015
|
-
"""
|
|
4016
|
-
if skills_available and skills_needed:
|
|
4017
|
-
skill_guidance = (
|
|
4018
|
-
"10. Requirement-driven skills activation: skills_needed=true.\n"
|
|
4019
|
-
" - Prefer one effective sequence in the first 2 turns when it materially improves grounding:\n"
|
|
4020
|
-
' - load_skill(name="<available-skill-name>")\n'
|
|
4021
|
-
' - read_skill_resource(name="<available-skill-name>", resource_path="<resource-from-load-skill>") '
|
|
4022
|
-
"or run_skill_script when explicitly available.\n"
|
|
4023
|
-
" - Skip list_skills when available skills are already listed in Run Context.\n"
|
|
4024
|
-
" - Do not call run_skill_script unless the loaded skill explicitly lists scripts in the load_skill result.\n"
|
|
4025
|
-
f" - {'This step is mandatory in this strict run.' if strict_skill_required else 'This step is optional in this run when strict skill enforcement is disabled.'}"
|
|
4026
|
-
)
|
|
4027
|
-
elif skills_available:
|
|
4028
|
-
skill_guidance = (
|
|
4029
|
-
"10. Requirement-driven skills activation: skills_needed=false.\n"
|
|
4030
|
-
" - Skill usage remains optional; avoid discovery-only churn.\n"
|
|
4031
|
-
" - Use skill tools only when they provide direct, row-specific evidence gains.\n"
|
|
4032
|
-
" - Keep analysis grounded with repository and evidence retrieval tools first."
|
|
4033
|
-
)
|
|
4034
|
-
else:
|
|
4035
|
-
skill_guidance = "10. Skills toolset unavailable for this run; do not emit skill tool calls and continue with repository/docs tools."
|
|
4036
|
-
|
|
4037
|
-
docs_guidance_nc = ""
|
|
4038
|
-
if is_arch_requirement:
|
|
4039
|
-
docs_guidance_nc = "\n14. Architecture Policy: This is a Clean Architecture requirement. Use `ast_grep_search` with pattern `import $A` to check cross-boundary imports (e.g. domain importing infrastructure or framework like @Entity/@Table). Do not guess dependencies without structural search."
|
|
4040
|
-
elif "docs" in evidence_targets and "code" not in evidence_targets:
|
|
4041
|
-
docs_guidance_nc = "\n14. Docs-First Policy: This requirement relies exclusively on documentation (SLA, Support). ALWAYS call search_docs or search_evidence_vector BEFORE any code search. Source code rarely contains explicit SLA contracts."
|
|
4042
|
-
elif "docs" in evidence_targets:
|
|
4043
|
-
docs_guidance_nc = "\n14. Hybrid Evidence Policy: This requirement needs both documentation and code. Start with search_docs or search_evidence_vector to understand the design, then use code tools to verify implementation."
|
|
4044
|
-
|
|
4045
|
-
return f"""Perform code quality and security analysis using TOOL-FIRST investigation.
|
|
4046
|
-
|
|
4047
|
-
## Run Context
|
|
4048
|
-
{context}
|
|
4049
|
-
{preloaded_skill_section}
|
|
4050
|
-
|
|
4051
|
-
## Required Approach
|
|
4052
|
-
1. Use repository exploration tools to locate relevant implementation files.
|
|
4053
|
-
2. In the first two repository calls, follow cadence: discovery (grep_search/rg_search preferred) then read_file on a concrete hit.
|
|
4054
|
-
3. Read only focused files/sections needed to justify findings.
|
|
4055
|
-
4. If evidence corpus is available, call search_evidence and then read_evidence_document for at least one matched ref.
|
|
4056
|
-
5. If vector retrieval is available, call search_evidence_vector (docs) or search_code_vector (code) at least once before final answer.
|
|
4057
|
-
6. If state-backed retrieval is available, prioritize Postgres-backed evidence queries for requirement-level grounding.
|
|
4058
|
-
7. Correlate findings with concrete file paths and, where possible, line ranges.
|
|
4059
|
-
8. Before final answer, complete at least one repository tool call and at least one code-read/navigation call.
|
|
4060
|
-
9. Call exactly one tool per turn, then inspect the result before next call.
|
|
4061
|
-
This step cadence is enforced by runtime caps (`agentic.max_turns`, `agentic.max_tool_calls`).
|
|
4062
|
-
{skill_guidance}
|
|
4063
|
-
11. Avoid repetitive loops: do not repeat the same tool pattern more than twice without new evidence.
|
|
4064
|
-
12. If search_evidence/search_evidence_vector/search_code_vector returns no useful hit twice, pivot to grep_search/rg_search/read_file or conclude evidence is insufficient.
|
|
4065
|
-
13. If a tool returns `[ERROR] Not a directory` or `[ERROR] Not a file` twice, stop path guessing.
|
|
4066
|
-
Pivot immediately to grep_search/rg_search to discover exact paths, then read_file on discovered files.{docs_guidance_nc}
|
|
4067
|
-
{search_strategy_guidance}
|
|
4068
|
-
|
|
4069
|
-
## Output
|
|
4070
|
-
Provide:
|
|
4071
|
-
1. Overall score (0-10)
|
|
4072
|
-
2. Concrete issues (severity, file path, recommendation)
|
|
4073
|
-
3. Positive/negative patterns observed
|
|
4074
|
-
4. Confidence and concise reasoning
|
|
4075
|
-
"""
|
|
4076
|
-
|
|
4077
|
-
def _build_agentic_evidence_path_diagnostics(
|
|
4078
|
-
self,
|
|
4079
|
-
*,
|
|
4080
|
-
evidence: EvidenceBundle,
|
|
4081
|
-
repo_path: Path,
|
|
4082
|
-
) -> dict[str, Any]:
|
|
4083
|
-
"""Summarize evidence path composition for trace-level diagnosability."""
|
|
4084
|
-
repo_root = repo_path.resolve()
|
|
4085
|
-
raw_paths = [str(item.source_id).strip() for item in evidence.git_evidence if item.source_id]
|
|
4086
|
-
unique_paths = list(dict.fromkeys(path for path in raw_paths if path))
|
|
4087
|
-
|
|
4088
|
-
absolute_count = 0
|
|
4089
|
-
relative_count = 0
|
|
4090
|
-
inside_repo_count = 0
|
|
4091
|
-
outside_repo_count = 0
|
|
4092
|
-
resolve_error_count = 0
|
|
4093
|
-
basename_counts: dict[str, int] = {}
|
|
4094
|
-
|
|
4095
|
-
for raw_path in unique_paths:
|
|
4096
|
-
path = Path(raw_path)
|
|
4097
|
-
if path.is_absolute():
|
|
4098
|
-
absolute_count += 1
|
|
4099
|
-
candidate = path
|
|
4100
|
-
else:
|
|
4101
|
-
relative_count += 1
|
|
4102
|
-
candidate = repo_root / path
|
|
4103
|
-
|
|
4104
|
-
basename = path.name
|
|
4105
|
-
basename_counts[basename] = basename_counts.get(basename, 0) + 1
|
|
4106
|
-
try:
|
|
4107
|
-
resolved = candidate.resolve()
|
|
4108
|
-
except PATH_RESOLUTION_RECOVERABLE_ERRORS:
|
|
4109
|
-
resolve_error_count += 1
|
|
4110
|
-
continue
|
|
4111
|
-
|
|
4112
|
-
if resolved == repo_root or repo_root in resolved.parents:
|
|
4113
|
-
inside_repo_count += 1
|
|
4114
|
-
else:
|
|
4115
|
-
outside_repo_count += 1
|
|
4116
|
-
|
|
4117
|
-
fragmented_basename_count = sum(1 for count in basename_counts.values() if count > 1)
|
|
4118
|
-
return {
|
|
4119
|
-
"total_evidence_files": len(evidence.git_evidence),
|
|
4120
|
-
"with_source_id": len(raw_paths),
|
|
4121
|
-
"missing_source_id": max(0, len(evidence.git_evidence) - len(raw_paths)),
|
|
4122
|
-
"unique_source_paths": len(unique_paths),
|
|
4123
|
-
"absolute_path_count": absolute_count,
|
|
4124
|
-
"relative_path_count": relative_count,
|
|
4125
|
-
"resolved_inside_repo_count": inside_repo_count,
|
|
4126
|
-
"resolved_outside_repo_count": outside_repo_count,
|
|
4127
|
-
"resolve_error_count": resolve_error_count,
|
|
4128
|
-
"fragmented_basename_count": fragmented_basename_count,
|
|
4129
|
-
"sample_paths": unique_paths[:12],
|
|
4130
|
-
}
|