core-runtime 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- api/__init__.py +4 -0
- api/cli/__init__.py +10 -0
- api/cli/audit_client.py +92 -0
- api/cli/census_client.py +77 -0
- api/cli/client.py +508 -0
- api/cli/coverage_client.py +121 -0
- api/cli/daemon_client.py +42 -0
- api/cli/fix_client.py +101 -0
- api/cli/inspect_client.py +143 -0
- api/cli/integration_client.py +42 -0
- api/cli/integrity_client.py +45 -0
- api/cli/proposals_client.py +101 -0
- api/cli/quality_client.py +83 -0
- api/cli/refactor_client.py +82 -0
- api/cli/sync_client.py +106 -0
- api/dependencies.py +37 -0
- api/errors.py +74 -0
- api/main.py +88 -0
- api/v1/__init__.py +4 -0
- api/v1/audit_routes.py +302 -0
- api/v1/census_routes.py +207 -0
- api/v1/coverage_routes.py +352 -0
- api/v1/daemon_routes.py +86 -0
- api/v1/development_routes.py +70 -0
- api/v1/fix_routes.py +428 -0
- api/v1/inspect_routes.py +220 -0
- api/v1/integration_routes.py +56 -0
- api/v1/integrity_routes.py +72 -0
- api/v1/knowledge_routes.py +36 -0
- api/v1/lint_routes.py +40 -0
- api/v1/proposals_routes.py +267 -0
- api/v1/quality_routes.py +272 -0
- api/v1/refactor_routes.py +225 -0
- api/v1/sync_routes.py +261 -0
- body/__init__.py +4 -0
- body/analyzers/__init__.py +25 -0
- body/analyzers/base_analyzer.py +28 -0
- body/analyzers/constitutional_path_analyzer.py +63 -0
- body/analyzers/file_analyzer.py +211 -0
- body/analyzers/knowledge_graph_analyzer.py +86 -0
- body/analyzers/prompt_analyzer.py +155 -0
- body/analyzers/symbol_extractor.py +280 -0
- body/atomic/__init__.py +74 -0
- body/atomic/build_tests_action.py +354 -0
- body/atomic/check_actions.py +142 -0
- body/atomic/crate_ops.py +59 -0
- body/atomic/executor.py +470 -0
- body/atomic/file_ops.py +153 -0
- body/atomic/fix_actions.py +1142 -0
- body/atomic/import_resolver.py +200 -0
- body/atomic/metadata_ops.py +161 -0
- body/atomic/modularity_fix.py +839 -0
- body/atomic/modularity_splitter.py +521 -0
- body/atomic/proposal_lifecycle_actions.py +171 -0
- body/atomic/registry.py +326 -0
- body/atomic/remediate_cognitive_role.py +104 -0
- body/atomic/sandbox_lifecycle.py +252 -0
- body/atomic/split_plan.py +155 -0
- body/atomic/sync_actions/__init__.py +22 -0
- body/atomic/sync_actions/chunking_helpers.py +218 -0
- body/atomic/sync_actions/sync_actions.py +431 -0
- body/atomic/test_actions.py +47 -0
- body/autonomy/__init__.py +16 -0
- body/autonomy/audit_analyzer.py +343 -0
- body/autonomy/micro_proposal_executor.py +316 -0
- body/crate_processing/canary_executor.py +144 -0
- body/evaluators/__init__.py +27 -0
- body/evaluators/atomic_actions_evaluator.py +162 -0
- body/evaluators/atomic_actions_format.py +45 -0
- body/evaluators/atomic_actions_rules.py +278 -0
- body/evaluators/base_evaluator.py +67 -0
- body/evaluators/clarity_evaluator.py +83 -0
- body/evaluators/constitutional_evaluator.py +227 -0
- body/evaluators/failure_evaluator.py +136 -0
- body/evaluators/performance_evaluator.py +341 -0
- body/evaluators/security_evaluator.py +393 -0
- body/flows/__init__.py +33 -0
- body/flows/executor.py +275 -0
- body/flows/registry.py +272 -0
- body/flows/result.py +113 -0
- body/governance/__init__.py +29 -0
- body/governance/body_contracts_service.py +317 -0
- body/governance/code_validator.py +118 -0
- body/governance/engine_dispatcher.py +128 -0
- body/governance/intent_guard.py +592 -0
- body/governance/intent_pattern_validators.py +197 -0
- body/governance/key_management_service.py +100 -0
- body/governance/path_validator.py +187 -0
- body/governance/remediation_service.py +263 -0
- body/governance/runtime_validator.py +184 -0
- body/infrastructure/bootstrap.py +135 -0
- body/infrastructure/lifespan.py +85 -0
- body/infrastructure/repositories/__init__.py +1 -0
- body/infrastructure/repositories/decision_trace_repository.py +210 -0
- body/infrastructure/repositories/refusal_repository.py +294 -0
- body/introspection/__init__.py +4 -0
- body/introspection/capability_discovery_service.py +107 -0
- body/introspection/discovery/from_kgb.py +33 -0
- body/introspection/discovery/from_source_scan.py +40 -0
- body/introspection/discovery/loader.py +62 -0
- body/introspection/discovery/registry.py +22 -0
- body/introspection/discovery/semantics.py +21 -0
- body/introspection/discovery/sync.py +47 -0
- body/introspection/drift_detector.py +81 -0
- body/introspection/drift_service.py +48 -0
- body/introspection/export_vectors.py +133 -0
- body/introspection/generate_capability_docs.py +130 -0
- body/introspection/generate_correction_map.py +98 -0
- body/introspection/graph_analysis_service.py +66 -0
- body/introspection/knowledge_graph_service.py +170 -0
- body/introspection/semantic_clusterer.py +128 -0
- body/introspection/symbol_index_builder.py +244 -0
- body/introspection/sync/engine.py +92 -0
- body/introspection/sync/scanner.py +56 -0
- body/introspection/sync/visitor.py +83 -0
- body/introspection/sync_service.py +62 -0
- body/invokers/__init__.py +4 -0
- body/invokers/capability_invoker.py +4 -0
- body/maintenance/command_sync_service.py +73 -0
- body/maintenance/dotenv_sync_service.py +99 -0
- body/maintenance/idempotency_harness.py +70 -0
- body/maintenance/maintenance_service.py +123 -0
- body/maintenance/memory_cleanup_service.py +131 -0
- body/maintenance/refactor_settings_access.py +274 -0
- body/maintenance/scripts/__init__.py +5 -0
- body/maintenance/scripts/context_export.py +278 -0
- body/maintenance/scripts/vector_verify.py +73 -0
- body/maintenance/sync_vectors.py +338 -0
- body/models/__init__.py +4 -0
- body/project_lifecycle/__init__.py +4 -0
- body/project_lifecycle/bootstrap_service.py +157 -0
- body/project_lifecycle/definition_service.py +264 -0
- body/project_lifecycle/integration_service.py +113 -0
- body/project_lifecycle/scaffolding_service.py +187 -0
- body/quality/coverage_analyzer.py +177 -0
- body/repositories/__init__.py +4 -0
- body/self_healing/atomic_actions_fixer.py +113 -0
- body/self_healing/body_ui_fixer.py +193 -0
- body/self_healing/capability_parser.py +65 -0
- body/self_healing/code_style_service.py +51 -0
- body/self_healing/complexity_filter.py +70 -0
- body/self_healing/docstring_service.py +345 -0
- body/self_healing/duplicate_id_service.py +407 -0
- body/self_healing/duplicates_service.py +165 -0
- body/self_healing/handlers/__init__.py +1 -0
- body/self_healing/handlers/id_assignment_handler.py +201 -0
- body/self_healing/handlers/import_sorting_handler.py +181 -0
- body/self_healing/header_service.py +308 -0
- body/self_healing/id_tagging_service.py +227 -0
- body/self_healing/knowledge_consolidation_service.py +80 -0
- body/self_healing/logging_service.py +292 -0
- body/self_healing/owner_tagging_service.py +5 -0
- body/self_healing/placeholder_fixer_service.py +27 -0
- body/self_healing/prune_private_capabilities.py +144 -0
- body/self_healing/purge_legacy_tags_service.py +146 -0
- body/self_healing/remediation_models.py +238 -0
- body/self_healing/test_context/__init__.py +10 -0
- body/self_healing/test_context/detectors.py +74 -0
- body/self_healing/test_context/examples.py +53 -0
- body/self_healing/test_context/formatter.py +65 -0
- body/self_healing/test_context/metrics.py +62 -0
- body/self_healing/test_context/models.py +83 -0
- body/self_healing/test_context/parsers.py +70 -0
- body/self_healing/test_context_analyzer.py +79 -0
- body/self_healing/test_failure_analyzer.py +259 -0
- body/self_healing/test_target_analyzer.py +118 -0
- body/self_healing/vulture_healer.py +161 -0
- body/services/__init__.py +4 -0
- body/services/artifact_service.py +155 -0
- body/services/blackboard_service/__init__.py +22 -0
- body/services/blackboard_service/blackboard_claim_service.py +216 -0
- body/services/blackboard_service/blackboard_proposal_service.py +305 -0
- body/services/blackboard_service/blackboard_query_service.py +333 -0
- body/services/blackboard_service/blackboard_service.py +602 -0
- body/services/capabilities.py +51 -0
- body/services/cim/__init__.py +22 -0
- body/services/cim/baselines.py +102 -0
- body/services/cim/census_service.py +190 -0
- body/services/cim/cim_constants.py +116 -0
- body/services/cim/cim_path_utils.py +123 -0
- body/services/cim/diff.py +152 -0
- body/services/cim/history.py +94 -0
- body/services/cim/models.py +319 -0
- body/services/cim/policy.py +149 -0
- body/services/cim/scanners.py +332 -0
- body/services/coherence_service.py +552 -0
- body/services/consequence_log_service.py +189 -0
- body/services/constitutional_rule_loader.py +141 -0
- body/services/constitutional_validator.py +366 -0
- body/services/crate_creation_service.py +217 -0
- body/services/crate_processing_service.py +279 -0
- body/services/crawl_service/__init__.py +10 -0
- body/services/crawl_service/main_module.py +531 -0
- body/services/crawl_service/orchestrator.py +452 -0
- body/services/crawl_service/symbol_processing.py +279 -0
- body/services/database_service.py +242 -0
- body/services/doc_service.py +57 -0
- body/services/file_service.py +260 -0
- body/services/governance_claims_service.py +240 -0
- body/services/governance_init.py +41 -0
- body/services/health_log_service.py +167 -0
- body/services/intent_schema_validator.py +211 -0
- body/services/llm_client.py +87 -0
- body/services/mind_state_service.py +129 -0
- body/services/policy_expression_evaluator.py +154 -0
- body/services/proposal_supervision_service.py +187 -0
- body/services/representation_coherence_service.py +209 -0
- body/services/service_registry.py +431 -0
- body/services/session_attached_service.py +51 -0
- body/services/symbol_query_service.py +218 -0
- body/services/symbol_service.py +94 -0
- body/services/validation/__init__.py +14 -0
- body/services/validation/python_validator.py +89 -0
- body/services/validation/validation_policies.py +121 -0
- body/services/worker_registry_service.py +184 -0
- body/validators/__init__.py +1 -0
- body/validators/logic_conservation_validator.py +201 -0
- body/workers/call_site_rewriter.py +527 -0
- body/workers/prompt_artifact_writer.py +323 -0
- cli/__init__.py +4 -0
- cli/admin_cli.py +98 -0
- cli/cli_user.py +121 -0
- cli/commands/__init__.py +4 -0
- cli/commands/audit_reporter.py +272 -0
- cli/commands/check/__init__.py +115 -0
- cli/commands/check/audit.py +130 -0
- cli/commands/check/converters.py +129 -0
- cli/commands/check/diagnostics_commands.py +70 -0
- cli/commands/check/formatters.py +310 -0
- cli/commands/check/imports.py +73 -0
- cli/commands/check/quality.py +71 -0
- cli/commands/check/quality_gates.py +107 -0
- cli/commands/check/rule.py +136 -0
- cli/commands/check/utils.py +28 -0
- cli/commands/check_atomic_actions.py +167 -0
- cli/commands/components.py +66 -0
- cli/commands/coverage/__init__.py +22 -0
- cli/commands/coverage/analysis_commands.py +87 -0
- cli/commands/coverage/check_commands.py +173 -0
- cli/commands/coverage/generation_commands.py +155 -0
- cli/commands/coverage/services/__init__.py +15 -0
- cli/commands/coverage/services/coverage_checker.py +50 -0
- cli/commands/coverage/services/coverage_reporter.py +81 -0
- cli/commands/coverage/services/gaps_analyzer.py +114 -0
- cli/commands/daemon.py +908 -0
- cli/commands/develop.py +127 -0
- cli/commands/diagnostics.py +32 -0
- cli/commands/fix/__init__.py +84 -0
- cli/commands/fix/all_commands.py +94 -0
- cli/commands/fix/atomic_actions.py +48 -0
- cli/commands/fix/audit.py +146 -0
- cli/commands/fix/body_ui.py +93 -0
- cli/commands/fix/code_style.py +52 -0
- cli/commands/fix/db_tools.py +90 -0
- cli/commands/fix/fix_ir.py +79 -0
- cli/commands/fix/handler_discovery.py +54 -0
- cli/commands/fix/imports.py +55 -0
- cli/commands/fix/list_commands.py +54 -0
- cli/commands/fix/metadata.py +160 -0
- cli/commands/fix/modularity.py +88 -0
- cli/commands/fix/settings_access.py +65 -0
- cli/commands/fix_governed.py +103 -0
- cli/commands/fix_logging.py +24 -0
- cli/commands/governance.py +294 -0
- cli/commands/guard.py +125 -0
- cli/commands/inspect/__init__.py +79 -0
- cli/commands/inspect/_helpers.py +226 -0
- cli/commands/inspect/analysis.py +158 -0
- cli/commands/inspect/decisions.py +140 -0
- cli/commands/inspect/diagnostics.py +126 -0
- cli/commands/inspect/drift.py +100 -0
- cli/commands/inspect/patterns.py +102 -0
- cli/commands/inspect/refusals.py +211 -0
- cli/commands/inspect/repo_census.py +175 -0
- cli/commands/inspect/status.py +48 -0
- cli/commands/interactive_test.py +85 -0
- cli/commands/mind.py +49 -0
- cli/commands/refactor.py +234 -0
- cli/commands/refactor_support/__init__.py +7 -0
- cli/commands/refactor_support/analyzer.py +107 -0
- cli/commands/refactor_support/config.py +67 -0
- cli/commands/refactor_support/display.py +170 -0
- cli/commands/refactor_support/recommendations.py +55 -0
- cli/commands/run.py +60 -0
- cli/commands/search.py +103 -0
- cli/commands/status.py +86 -0
- cli/commands/submit.py +23 -0
- cli/interactive.py +177 -0
- cli/logic/__init__.py +7 -0
- cli/logic/agent.py +110 -0
- cli/logic/audit_capability_domains.py +106 -0
- cli/logic/audit_renderer.py +150 -0
- cli/logic/autonomy/actions.py +36 -0
- cli/logic/autonomy/views.py +116 -0
- cli/logic/body_contracts_checker.py +23 -0
- cli/logic/build.py +27 -0
- cli/logic/byor.py +148 -0
- cli/logic/capability.py +27 -0
- cli/logic/cli_utils.py +210 -0
- cli/logic/context.py +7 -0
- cli/logic/db.py +154 -0
- cli/logic/db_manage.py +22 -0
- cli/logic/decision_inspect_logic.py +62 -0
- cli/logic/diagnostics.py +148 -0
- cli/logic/diagnostics_policy.py +100 -0
- cli/logic/diagnostics_registry.py +165 -0
- cli/logic/duplicates.py +19 -0
- cli/logic/embeddings_cli.py +43 -0
- cli/logic/governance/__init__.py +16 -0
- cli/logic/governance/engine.py +216 -0
- cli/logic/governance/forensics_service.py +67 -0
- cli/logic/governance/limb_status_service.py +83 -0
- cli/logic/governance/renderer.py +115 -0
- cli/logic/governance/traceability_service.py +78 -0
- cli/logic/governance_logic.py +33 -0
- cli/logic/hub/__init__.py +14 -0
- cli/logic/hub/app.py +107 -0
- cli/logic/hub/formatter.py +29 -0
- cli/logic/hub/introspection.py +20 -0
- cli/logic/hub/repository.py +17 -0
- cli/logic/init.py +22 -0
- cli/logic/interactive_test/__init__.py +21 -0
- cli/logic/interactive_test/session.py +102 -0
- cli/logic/interactive_test/steps/__init__.py +23 -0
- cli/logic/interactive_test/steps/execution.py +53 -0
- cli/logic/interactive_test/steps/generation.py +88 -0
- cli/logic/interactive_test/steps/healing.py +79 -0
- cli/logic/interactive_test/steps/utils.py +31 -0
- cli/logic/interactive_test/steps/verification.py +71 -0
- cli/logic/interactive_test/ui.py +203 -0
- cli/logic/interactive_test/workflow.py +168 -0
- cli/logic/interactive_test_logic.py +41 -0
- cli/logic/knowledge.py +47 -0
- cli/logic/legacy_scan_logic.py +306 -0
- cli/logic/list_audits.py +49 -0
- cli/logic/log_audit.py +53 -0
- cli/logic/new.py +8 -0
- cli/logic/project_docs.py +28 -0
- cli/logic/reconcile.py +127 -0
- cli/logic/refusal_inspect_logic.py +208 -0
- cli/logic/report.py +47 -0
- cli/logic/status.py +47 -0
- cli/logic/symbol_drift.py +77 -0
- cli/logic/sync.py +48 -0
- cli/logic/sync_domains.py +72 -0
- cli/logic/sync_manifest.py +31 -0
- cli/logic/tools.py +133 -0
- cli/logic/utils_migration.py +43 -0
- cli/logic/validate.py +107 -0
- cli/logic/vector_drift.py +109 -0
- cli/logic/yaml_processor.py +5 -0
- cli/renderers/audit_detail.py +37 -0
- cli/renderers/audit_overview.py +39 -0
- cli/resources/__init__.py +27 -0
- cli/resources/admin/__init__.py +23 -0
- cli/resources/admin/coverage.py +63 -0
- cli/resources/admin/debt_scan.py +195 -0
- cli/resources/admin/forensics.py +97 -0
- cli/resources/admin/health.py +66 -0
- cli/resources/admin/hub.py +9 -0
- cli/resources/admin/meta.py +47 -0
- cli/resources/admin/patterns.py +28 -0
- cli/resources/admin/refusals.py +31 -0
- cli/resources/admin/self_check.py +175 -0
- cli/resources/admin/status.py +66 -0
- cli/resources/admin/summary.py +67 -0
- cli/resources/admin/traces.py +46 -0
- cli/resources/admin/validate_env.py +56 -0
- cli/resources/code/__init__.py +31 -0
- cli/resources/code/actions.py +48 -0
- cli/resources/code/audit.py +416 -0
- cli/resources/code/audit_duplicates.py +22 -0
- cli/resources/code/check_imports.py +75 -0
- cli/resources/code/check_ui.py +62 -0
- cli/resources/code/clarity.py +51 -0
- cli/resources/code/complexity.py +55 -0
- cli/resources/code/docstrings.py +51 -0
- cli/resources/code/fix_atomic.py +51 -0
- cli/resources/code/format.py +62 -0
- cli/resources/code/hub.py +10 -0
- cli/resources/code/integrity.py +75 -0
- cli/resources/code/lint.py +37 -0
- cli/resources/code/logging.py +49 -0
- cli/resources/code/refactor.py +32 -0
- cli/resources/code/test.py +30 -0
- cli/resources/coherence/__init__.py +13 -0
- cli/resources/coherence/check.py +111 -0
- cli/resources/coherence/hub.py +13 -0
- cli/resources/coherence/repair_counts.py +73 -0
- cli/resources/coherence/report.py +144 -0
- cli/resources/coherence/seed.py +297 -0
- cli/resources/coherence/supersede.py +124 -0
- cli/resources/coherence/triage.py +81 -0
- cli/resources/constitution/__init__.py +19 -0
- cli/resources/constitution/audit.py +49 -0
- cli/resources/constitution/query.py +45 -0
- cli/resources/constitution/status.py +34 -0
- cli/resources/constitution/validate.py +36 -0
- cli/resources/context/__init__.py +21 -0
- cli/resources/context/build.py +374 -0
- cli/resources/context/cache.py +156 -0
- cli/resources/context/explain.py +140 -0
- cli/resources/context/hub.py +11 -0
- cli/resources/context/search.py +114 -0
- cli/resources/database/__init__.py +13 -0
- cli/resources/database/cleanup.py +107 -0
- cli/resources/database/export.py +61 -0
- cli/resources/database/hub.py +11 -0
- cli/resources/database/migrate.py +57 -0
- cli/resources/database/status.py +101 -0
- cli/resources/database/sync.py +84 -0
- cli/resources/database/sync_env.py +76 -0
- cli/resources/database/sync_registry.py +48 -0
- cli/resources/dev/__init__.py +14 -0
- cli/resources/dev/hub.py +11 -0
- cli/resources/dev/refactor.py +92 -0
- cli/resources/dev/stability.py +60 -0
- cli/resources/dev/strategic_audit.py +113 -0
- cli/resources/dev/sync.py +51 -0
- cli/resources/dev/test.py +34 -0
- cli/resources/intent/__init__.py +11 -0
- cli/resources/intent/hub.py +9 -0
- cli/resources/intent/sync_vocabulary.py +396 -0
- cli/resources/project/__init__.py +19 -0
- cli/resources/project/docs.py +41 -0
- cli/resources/project/new.py +40 -0
- cli/resources/project/onboard.py +31 -0
- cli/resources/proposals/__init__.py +28 -0
- cli/resources/proposals/create.py +82 -0
- cli/resources/proposals/integrate.py +49 -0
- cli/resources/proposals/list.py +76 -0
- cli/resources/proposals/manage.py +117 -0
- cli/resources/runtime/__init__.py +9 -0
- cli/resources/runtime/health.py +925 -0
- cli/resources/secrets/__init__.py +10 -0
- cli/resources/secrets/hub.py +9 -0
- cli/resources/secrets/manage.py +309 -0
- cli/resources/symbols/__init__.py +13 -0
- cli/resources/symbols/audit.py +46 -0
- cli/resources/symbols/fix_ids.py +43 -0
- cli/resources/symbols/hub.py +11 -0
- cli/resources/symbols/resolve_duplicates.py +30 -0
- cli/resources/symbols/sync.py +39 -0
- cli/resources/symbols/tag.py +47 -0
- cli/resources/vectors/__init__.py +11 -0
- cli/resources/vectors/cleanup.py +95 -0
- cli/resources/vectors/hub.py +9 -0
- cli/resources/vectors/query.py +105 -0
- cli/resources/vectors/status.py +30 -0
- cli/resources/vectors/sync.py +57 -0
- cli/resources/vectors/sync_code.py +67 -0
- cli/resources/workers/__init__.py +13 -0
- cli/resources/workers/blackboard.py +253 -0
- cli/resources/workers/remediate.py +337 -0
- cli/resources/workers/run.py +140 -0
- cli/utils/__init__.py +32 -0
- cli/utils/annotation_formatter.py +154 -0
- cli/utils/decorators.py +184 -0
- cli/utils/display.py +79 -0
- cli/utils/exit_codes.py +59 -0
- cli/utils/helpers.py +34 -0
- cli/utils/prompts.py +21 -0
- core_runtime-0.1.1.dist-info/LICENSE +21 -0
- core_runtime-0.1.1.dist-info/METADATA +346 -0
- core_runtime-0.1.1.dist-info/RECORD +962 -0
- core_runtime-0.1.1.dist-info/WHEEL +4 -0
- core_runtime-0.1.1.dist-info/entry_points.txt +4 -0
- mind/__init__.py +4 -0
- mind/coherence/__init__.py +1 -0
- mind/coherence/checker.py +314 -0
- mind/coherence/checks/__init__.py +4 -0
- mind/coherence/checks/base.py +34 -0
- mind/coherence/checks/r1_scoped.py +228 -0
- mind/coherence/checks/row2_grounding.py +69 -0
- mind/coherence/checks/row3_citation.py +119 -0
- mind/coherence/checks/row4_naming.py +126 -0
- mind/coherence/checks/sameconcern.py +136 -0
- mind/coherence/checks/specgap.py +233 -0
- mind/coherence/checks/vocabulary.py +112 -0
- mind/coherence/llm_judge.py +207 -0
- mind/enforcement/audit.py +78 -0
- mind/governance/__init__.py +22 -0
- mind/governance/assumption_extractor.py +326 -0
- mind/governance/audit_context.py +520 -0
- mind/governance/audit_postprocessor.py +36 -0
- mind/governance/audit_report_writer.py +46 -0
- mind/governance/audit_types.py +98 -0
- mind/governance/auditor.py +179 -0
- mind/governance/authority_package_builder.py +502 -0
- mind/governance/constitutional_auditor_dynamic.py +362 -0
- mind/governance/enforcement/__init__.py +24 -0
- mind/governance/enforcement_loader.py +245 -0
- mind/governance/enforcement_methods.py +28 -0
- mind/governance/entry_point_policy.py +62 -0
- mind/governance/executable_rule.py +127 -0
- mind/governance/filtered_audit.py +272 -0
- mind/governance/finding_processor.py +76 -0
- mind/governance/meta_validator.py +259 -0
- mind/governance/micro_proposal_validator.py +169 -0
- mind/governance/policy_coverage_service.py +183 -0
- mind/governance/policy_rule.py +94 -0
- mind/governance/rule_conflict_detector.py +127 -0
- mind/governance/rule_executor.py +306 -0
- mind/governance/rule_extractor.py +376 -0
- mind/governance/stateless_audit.py +206 -0
- mind/governance/violation_report.py +136 -0
- mind/logic/engines/_knowledge_gate_duplication.py +117 -0
- mind/logic/engines/action_gate.py +76 -0
- mind/logic/engines/artifact_gate.py +1168 -0
- mind/logic/engines/ast_gate/__init__.py +9 -0
- mind/logic/engines/ast_gate/base.py +263 -0
- mind/logic/engines/ast_gate/checks/__init__.py +35 -0
- mind/logic/engines/ast_gate/checks/async_checks.py +276 -0
- mind/logic/engines/ast_gate/checks/capability_checks.py +197 -0
- mind/logic/engines/ast_gate/checks/conservation_checks.py +126 -0
- mind/logic/engines/ast_gate/checks/generic_checks.py +244 -0
- mind/logic/engines/ast_gate/checks/import_checks.py +164 -0
- mind/logic/engines/ast_gate/checks/knowledge_source_check.py +88 -0
- mind/logic/engines/ast_gate/checks/logging_checks.py +133 -0
- mind/logic/engines/ast_gate/checks/metadata_checks.py +242 -0
- mind/logic/engines/ast_gate/checks/modularity_checks.py +436 -0
- mind/logic/engines/ast_gate/checks/naming_checks.py +120 -0
- mind/logic/engines/ast_gate/checks/prompt_model_checks.py +83 -0
- mind/logic/engines/ast_gate/checks/protected_namespace_access_check.py +298 -0
- mind/logic/engines/ast_gate/checks/purity_checks.py +421 -0
- mind/logic/engines/ast_gate/checks/purity_enforcement_check.py +56 -0
- mind/logic/engines/ast_gate/checks/runtime_import_boundary.py +198 -0
- mind/logic/engines/ast_gate/checks/schema_conformance_checks.py +130 -0
- mind/logic/engines/ast_gate/engine.py +317 -0
- mind/logic/engines/ast_gate.py +19 -0
- mind/logic/engines/base.py +106 -0
- mind/logic/engines/cli_gate/__init__.py +25 -0
- mind/logic/engines/cli_gate/base_check.py +45 -0
- mind/logic/engines/cli_gate/checks/__init__.py +31 -0
- mind/logic/engines/cli_gate/checks/async_execution.py +65 -0
- mind/logic/engines/cli_gate/checks/dangerous_explicit.py +60 -0
- mind/logic/engines/cli_gate/checks/discovery_strict.py +167 -0
- mind/logic/engines/cli_gate/checks/help_required.py +43 -0
- mind/logic/engines/cli_gate/checks/no_duplicates.py +57 -0
- mind/logic/engines/cli_gate/checks/no_layer_exposure.py +48 -0
- mind/logic/engines/cli_gate/checks/resource_first.py +58 -0
- mind/logic/engines/cli_gate/checks/standard_verbs.py +50 -0
- mind/logic/engines/cli_gate/engine.py +211 -0
- mind/logic/engines/glob_gate.py +214 -0
- mind/logic/engines/knowledge_gate.py +410 -0
- mind/logic/engines/llm_gate.py +407 -0
- mind/logic/engines/llm_gate_stub.py +67 -0
- mind/logic/engines/passive_gate.py +45 -0
- mind/logic/engines/regex_gate.py +97 -0
- mind/logic/engines/registry.py +134 -0
- mind/logic/engines/runtime_gate.py +265 -0
- mind/logic/engines/taxonomy_gate.py +229 -0
- mind/logic/engines/workflow_gate/__init__.py +22 -0
- mind/logic/engines/workflow_gate/base_check.py +42 -0
- mind/logic/engines/workflow_gate/checks/__init__.py +32 -0
- mind/logic/engines/workflow_gate/checks/alignment.py +93 -0
- mind/logic/engines/workflow_gate/checks/audit.py +80 -0
- mind/logic/engines/workflow_gate/checks/canary.py +47 -0
- mind/logic/engines/workflow_gate/checks/coverage.py +74 -0
- mind/logic/engines/workflow_gate/checks/dead_code.py +53 -0
- mind/logic/engines/workflow_gate/checks/import_resolution.py +97 -0
- mind/logic/engines/workflow_gate/checks/linter.py +104 -0
- mind/logic/engines/workflow_gate/checks/quality.py +49 -0
- mind/logic/engines/workflow_gate/checks/ruff_format.py +99 -0
- mind/logic/engines/workflow_gate/checks/tests.py +81 -0
- mind/logic/engines/workflow_gate/engine.py +207 -0
- shared/__init__.py +32 -0
- shared/action_logger.py +61 -0
- shared/action_types.py +199 -0
- shared/activity_logging.py +149 -0
- shared/ai/constitutional_envelope.py +341 -0
- shared/ai/prompt_model.py +585 -0
- shared/ai/response_parser.py +191 -0
- shared/ast_utility.py +279 -0
- shared/atomic_action.py +117 -0
- shared/cli/__init__.py +6 -0
- shared/cli/app_introspection.py +134 -0
- shared/cli/command_meta.py +224 -0
- shared/cli_types.py +92 -0
- shared/component_primitive.py +216 -0
- shared/config.py +216 -0
- shared/config_loader.py +54 -0
- shared/context.py +113 -0
- shared/exceptions.py +100 -0
- shared/governance/__init__.py +9 -0
- shared/governance/coherence_harvester.py +258 -0
- shared/governance_token.py +77 -0
- shared/infrastructure/__init__.py +5 -0
- shared/infrastructure/adapters/__init__.py +5 -0
- shared/infrastructure/adapters/embedding_provider.py +66 -0
- shared/infrastructure/bootstrap_registry.py +57 -0
- shared/infrastructure/clients/__init__.py +5 -0
- shared/infrastructure/clients/qdrant_client.py +455 -0
- shared/infrastructure/config_service.py +382 -0
- shared/infrastructure/config_validator.py +70 -0
- shared/infrastructure/context/__init__.py +45 -0
- shared/infrastructure/context/builder.py +804 -0
- shared/infrastructure/context/cache.py +101 -0
- shared/infrastructure/context/database.py +205 -0
- shared/infrastructure/context/limb_workspace.py +134 -0
- shared/infrastructure/context/models.py +65 -0
- shared/infrastructure/context/providers/__init__.py +18 -0
- shared/infrastructure/context/providers/ast.py +211 -0
- shared/infrastructure/context/providers/db.py +165 -0
- shared/infrastructure/context/providers/vectors.py +195 -0
- shared/infrastructure/context/redactor.py +109 -0
- shared/infrastructure/context/serializers.py +144 -0
- shared/infrastructure/context/service.py +271 -0
- shared/infrastructure/context/validator.py +247 -0
- shared/infrastructure/database/models/__init__.py +80 -0
- shared/infrastructure/database/models/autonomous_proposals.py +83 -0
- shared/infrastructure/database/models/decision_traces.py +129 -0
- shared/infrastructure/database/models/governance.py +183 -0
- shared/infrastructure/database/models/knowledge.py +205 -0
- shared/infrastructure/database/models/learning.py +99 -0
- shared/infrastructure/database/models/llm_config.py +274 -0
- shared/infrastructure/database/models/operations.py +152 -0
- shared/infrastructure/database/models/refusals.py +147 -0
- shared/infrastructure/database/models/system.py +124 -0
- shared/infrastructure/database/models/vectors.py +113 -0
- shared/infrastructure/database/models/workers.py +96 -0
- shared/infrastructure/database/session_manager.py +166 -0
- shared/infrastructure/diagnostic_service.py +103 -0
- shared/infrastructure/events/__init__.py +5 -0
- shared/infrastructure/events/base.py +44 -0
- shared/infrastructure/events/bus.py +76 -0
- shared/infrastructure/git_service.py +385 -0
- shared/infrastructure/intent/action_risk.py +135 -0
- shared/infrastructure/intent/audit_verdict.py +131 -0
- shared/infrastructure/intent/autonomy_dirty_tree.py +104 -0
- shared/infrastructure/intent/canonical_enums.py +116 -0
- shared/infrastructure/intent/cognitive_roles.py +96 -0
- shared/infrastructure/intent/errors.py +13 -0
- shared/infrastructure/intent/filesystem_operations.py +359 -0
- shared/infrastructure/intent/intent_connector.py +157 -0
- shared/infrastructure/intent/intent_repository.py +707 -0
- shared/infrastructure/intent/intent_validator.py +248 -0
- shared/infrastructure/intent/operational_capabilities.py +470 -0
- shared/infrastructure/intent/operational_config.py +1343 -0
- shared/infrastructure/intent/operational_mode.py +66 -0
- shared/infrastructure/intent/task_type_phases.py +180 -0
- shared/infrastructure/intent/test_coverage_paths.py +181 -0
- shared/infrastructure/intent/vocabulary_projection.py +241 -0
- shared/infrastructure/knowledge/knowledge_service.py +155 -0
- shared/infrastructure/knowledge_graph_service.py +214 -0
- shared/infrastructure/llm/client.py +448 -0
- shared/infrastructure/llm/client_registry.py +153 -0
- shared/infrastructure/llm/fallback_client.py +144 -0
- shared/infrastructure/llm/providers/anthropic.py +113 -0
- shared/infrastructure/llm/providers/base.py +130 -0
- shared/infrastructure/llm/providers/ollama.py +265 -0
- shared/infrastructure/llm/providers/openai.py +168 -0
- shared/infrastructure/repositories/__init__.py +5 -0
- shared/infrastructure/repositories/db/__init__.py +5 -0
- shared/infrastructure/repositories/db/common.py +138 -0
- shared/infrastructure/repositories/db/engine.py +26 -0
- shared/infrastructure/repositories/db/migration_service.py +75 -0
- shared/infrastructure/repositories/db/status_service.py +61 -0
- shared/infrastructure/repositories/memory_repository.py +134 -0
- shared/infrastructure/repositories/symbol_definition_repository.py +170 -0
- shared/infrastructure/repositories/task_repository.py +59 -0
- shared/infrastructure/repositories/vector_link_repository.py +83 -0
- shared/infrastructure/rooted_repository.py +50 -0
- shared/infrastructure/secrets_service.py +317 -0
- shared/infrastructure/specs/__init__.py +9 -0
- shared/infrastructure/specs/specs_repository.py +100 -0
- shared/infrastructure/storage/file_classifier.py +32 -0
- shared/infrastructure/storage/file_handler.py +330 -0
- shared/infrastructure/storage/file_provider.py +233 -0
- shared/infrastructure/storage/integrity_service.py +108 -0
- shared/infrastructure/validation/black_formatter.py +41 -0
- shared/infrastructure/validation/quality.py +46 -0
- shared/infrastructure/validation/ruff_linter.py +104 -0
- shared/infrastructure/validation/syntax_checker.py +45 -0
- shared/infrastructure/validation/test_runner.py +167 -0
- shared/infrastructure/validation/yaml_validator.py +45 -0
- shared/infrastructure/vector/__init__.py +15 -0
- shared/infrastructure/vector/adapters/__init__.py +20 -0
- shared/infrastructure/vector/adapters/constitutional/__init__.py +26 -0
- shared/infrastructure/vector/adapters/constitutional/chunker.py +246 -0
- shared/infrastructure/vector/adapters/constitutional/doc_key_resolver.py +109 -0
- shared/infrastructure/vector/adapters/constitutional/item_builder.py +158 -0
- shared/infrastructure/vector/adapters/constitutional/utils.py +39 -0
- shared/infrastructure/vector/adapters/constitutional_adapter.py +309 -0
- shared/infrastructure/vector/adapters/specs_adapter.py +171 -0
- shared/infrastructure/vector/cognitive_adapter.py +119 -0
- shared/infrastructure/vector/vector_index_service.py +230 -0
- shared/logger.py +195 -0
- shared/models/__init__.py +47 -0
- shared/models/action_result.py +77 -0
- shared/models/audit_models.py +106 -0
- shared/models/audit_rendering.py +30 -0
- shared/models/capability_models.py +22 -0
- shared/models/constitutional_validation.py +185 -0
- shared/models/drift_models.py +24 -0
- shared/models/embedding_payload.py +45 -0
- shared/models/execution_models.py +71 -0
- shared/models/pattern_graph.py +62 -0
- shared/models/prompt_model.py +244 -0
- shared/models/refusal_result.py +294 -0
- shared/models/remediation.py +35 -0
- shared/models/validation_result.py +34 -0
- shared/models/vector_models.py +62 -0
- shared/models/workflow_models.py +242 -0
- shared/path_resolver.py +408 -0
- shared/path_utils.py +60 -0
- shared/processors/base_processor.py +171 -0
- shared/processors/yaml_processor.py +72 -0
- shared/protocols/__init__.py +21 -0
- shared/protocols/brain_services.py +35 -0
- shared/protocols/cognitive.py +35 -0
- shared/protocols/executor.py +47 -0
- shared/protocols/interpreter.py +24 -0
- shared/protocols/knowledge.py +21 -0
- shared/protocols/llm.py +25 -0
- shared/protocols/typer_protocols.py +37 -0
- shared/time.py +18 -0
- shared/universal.py +43 -0
- shared/utils/__init__.py +81 -0
- shared/utils/audit_grouping.py +50 -0
- shared/utils/common_knowledge.py +82 -0
- shared/utils/domain_mapper.py +61 -0
- shared/utils/embedding_utils.py +182 -0
- shared/utils/glob_match.py +93 -0
- shared/utils/header_tools.py +177 -0
- shared/utils/parallel_processor.py +60 -0
- shared/utils/parsing.py +189 -0
- shared/utils/path_utils.py +268 -0
- shared/utils/subprocess_utils.py +87 -0
- shared/workers/__init__.py +19 -0
- shared/workers/base.py +533 -0
- shared/workers/declaration_validator.py +124 -0
- shared/workers/loop_hold_telemetry.py +210 -0
- shared/workers/schedule.py +123 -0
- will/__init__.py +4 -0
- will/agents/__init__.py +4 -0
- will/agents/base_planner.py +133 -0
- will/agents/code_generation/__init__.py +15 -0
- will/agents/code_generation/code_generator.py +247 -0
- will/agents/code_generation/context_formatters.py +99 -0
- will/agents/code_generation/correction_engine.py +157 -0
- will/agents/code_generation/extraction.py +165 -0
- will/agents/code_generation/pattern_validator.py +264 -0
- will/agents/code_generation/prompt_builders.py +209 -0
- will/agents/coder_agent.py +229 -0
- will/agents/coder_agent_refusal_handler.py +168 -0
- will/agents/cognitive_orchestrator.py +152 -0
- will/agents/conversational/__init__.py +13 -0
- will/agents/conversational/agent.py +271 -0
- will/agents/conversational/factory.py +72 -0
- will/agents/conversational/helpers.py +116 -0
- will/agents/execution_agent.py +294 -0
- will/agents/governance_mixin.py +132 -0
- will/agents/planner_agent.py +261 -0
- will/agents/resource_selector.py +228 -0
- will/agents/strategic_auditor/__init__.py +15 -0
- will/agents/strategic_auditor/agent.py +199 -0
- will/agents/strategic_auditor/context_gatherer.py +586 -0
- will/agents/strategic_auditor/effects.py +136 -0
- will/agents/strategic_auditor/models.py +61 -0
- will/agents/strategic_auditor/reasoning.py +169 -0
- will/agents/tagger_agent.py +294 -0
- will/agents/traced_agent_mixin.py +33 -0
- will/autonomy/__init__.py +20 -0
- will/autonomy/autonomous_developer.py +127 -0
- will/autonomy/proposal.py +585 -0
- will/autonomy/proposal_execution_pipeline.py +264 -0
- will/autonomy/proposal_executor.py +410 -0
- will/autonomy/proposal_mapper.py +187 -0
- will/autonomy/proposal_repository.py +118 -0
- will/autonomy/proposal_service.py +251 -0
- will/autonomy/proposal_state_manager.py +239 -0
- will/deciders/__init__.py +9 -0
- will/deciders/governance_decider.py +207 -0
- will/governance/__init__.py +13 -0
- will/governance/audit_remediation_runner.py +197 -0
- will/governance/audit_runner.py +368 -0
- will/governance/census_runner.py +278 -0
- will/governance/coverage_runner.py +489 -0
- will/governance/daemon_runner.py +164 -0
- will/governance/fix_runner.py +693 -0
- will/governance/inspect_runner.py +521 -0
- will/governance/integrity_runner.py +66 -0
- will/governance/lint_runner.py +93 -0
- will/governance/refactor_runner.py +372 -0
- will/governance/sync_runner.py +186 -0
- will/interpreters/__init__.py +44 -0
- will/interpreters/cli_args_interpreter.py +106 -0
- will/interpreters/natural_language_interpreter.py +276 -0
- will/interpreters/request_interpreter.py +126 -0
- will/lifecycle/__init__.py +12 -0
- will/lifecycle/integration_runner.py +54 -0
- will/maintenance/metadata_scribe_service.py +64 -0
- will/orchestration/__init__.py +4 -0
- will/orchestration/cognitive_service.py +185 -0
- will/orchestration/decision_tracer.py +257 -0
- will/orchestration/intent_alignment.py +59 -0
- will/orchestration/intent_guard.py +20 -0
- will/orchestration/phase_registry.py +92 -0
- will/orchestration/process_orchestrator.py +270 -0
- will/orchestration/prompt_pipeline.py +174 -0
- will/orchestration/remediation_orchestrator.py +292 -0
- will/orchestration/self_correction_engine.py +154 -0
- will/orchestration/validation_pipeline.py +45 -0
- will/orchestration/workflow_orchestrator.py +277 -0
- will/phases/__init__.py +24 -0
- will/phases/audit_phase.py +152 -0
- will/phases/canary/pytest_runner.py +156 -0
- will/phases/canary/result_builder.py +130 -0
- will/phases/canary/test_discovery.py +104 -0
- will/phases/canary_validation_phase.py +188 -0
- will/phases/code_generation/artifact_saver.py +175 -0
- will/phases/code_generation/code_sensor.py +117 -0
- will/phases/code_generation/file_path_extractor.py +53 -0
- will/phases/code_generation/work_directory_manager.py +83 -0
- will/phases/code_generation_phase.py +480 -0
- will/phases/execution_phase.py +179 -0
- will/phases/interpret_phase.py +266 -0
- will/phases/load_phase.py +102 -0
- will/phases/parse_phase.py +117 -0
- will/phases/planning_phase.py +182 -0
- will/phases/runtime_phase.py +112 -0
- will/phases/sandbox_validation_phase.py +130 -0
- will/phases/style_check_phase.py +209 -0
- will/phases/test_generation_phase.py +159 -0
- will/self_healing/alignment/persistence.py +53 -0
- will/self_healing/alignment/sandbox.py +51 -0
- will/self_healing/alignment/specialists.py +165 -0
- will/self_healing/alignment_orchestrator.py +140 -0
- will/self_healing/audit_remediation_service.py +199 -0
- will/self_healing/batch_remediation_service.py +280 -0
- will/self_healing/capability_reconciliation_service.py +96 -0
- will/self_healing/capability_tagging_service.py +224 -0
- will/self_healing/clarity_service.py +204 -0
- will/self_healing/complexity_service.py +260 -0
- will/self_healing/context_aware_test_generator.py +298 -0
- will/self_healing/coverage_remediation_service.py +97 -0
- will/self_healing/coverage_watcher.py +192 -0
- will/self_healing/enrichment_service.py +211 -0
- will/self_healing/linelength_service.py +168 -0
- will/self_healing/modularity_remediation_service.py +203 -0
- will/self_healing/remediation_evidence_writer.py +144 -0
- will/self_healing/remediation_executor.py +113 -0
- will/self_healing/remediation_interpretation/__init__.py +1 -0
- will/self_healing/remediation_interpretation/file_context_assembler.py +383 -0
- will/self_healing/remediation_interpretation/file_role_detector.py +599 -0
- will/self_healing/remediation_interpretation/finding_normalizer.py +221 -0
- will/self_healing/remediation_interpretation/models.py +198 -0
- will/self_healing/remediation_interpretation/reasoning_brief_builder.py +235 -0
- will/self_healing/remediation_interpretation/responsibility_extractor.py +421 -0
- will/self_healing/remediation_interpretation/service.py +202 -0
- will/self_healing/remediation_interpretation/strategy_catalog.py +252 -0
- will/self_healing/remediation_interpretation/strategy_selector.py +395 -0
- will/self_healing/remediation_pattern_matcher.py +126 -0
- will/self_healing/simple_test_generator.py +252 -0
- will/self_healing/single_file_remediation.py +137 -0
- will/self_healing/test_generation/automatic_repair.py +377 -0
- will/self_healing/test_generation/code_extractor.py +238 -0
- will/self_healing/test_generation/context_builder.py +140 -0
- will/self_healing/test_generation/executor.py +64 -0
- will/self_healing/test_generation/failure_parser.py +37 -0
- will/self_healing/test_generation/generation_workflow.py +140 -0
- will/self_healing/test_generation/generator.py +283 -0
- will/self_healing/test_generation/llm_correction.py +160 -0
- will/self_healing/test_generation/repair_workflow.py +128 -0
- will/self_healing/test_generation/single_test_fixer.py +77 -0
- will/self_healing/test_generation/test_extractor.py +50 -0
- will/self_healing/test_generation/test_scorer.py +53 -0
- will/self_healing/test_generation/test_validator.py +64 -0
- will/self_healing/test_generator.py +12 -0
- will/strategists/__init__.py +46 -0
- will/strategists/base_strategist.py +29 -0
- will/strategists/clarity_strategist.py +55 -0
- will/strategists/complexity_strategist.py +55 -0
- will/strategists/fix_strategist.py +467 -0
- will/strategists/sync_strategist.py +369 -0
- will/strategists/test_strategist.py +140 -0
- will/strategists/validation_strategist.py +315 -0
- will/test_generation/__init__.py +46 -0
- will/test_generation/adaptive_test_generator.py +123 -0
- will/test_generation/artifacts.py +102 -0
- will/test_generation/harness_detection.py +103 -0
- will/test_generation/helpers/__init__.py +14 -0
- will/test_generation/helpers/context_extractor.py +100 -0
- will/test_generation/helpers/test_executor.py +230 -0
- will/test_generation/llm_output.py +62 -0
- will/test_generation/models.py +25 -0
- will/test_generation/persistence.py +248 -0
- will/test_generation/phases/__init__.py +16 -0
- will/test_generation/phases/generation_phase.py +150 -0
- will/test_generation/phases/load_phase.py +53 -0
- will/test_generation/phases/parse_phase.py +50 -0
- will/test_generation/prompt_engine.py +123 -0
- will/test_generation/result_aggregator.py +73 -0
- will/test_generation/sandbox.py +203 -0
- will/test_generation/strategy_link.py +56 -0
- will/test_generation/test_extractor.py +140 -0
- will/test_generation/validation.py +89 -0
- will/tools/__init__.py +13 -0
- will/tools/anchor_builder.py +111 -0
- will/tools/anchor_search.py +73 -0
- will/tools/anchors/discovery.py +55 -0
- will/tools/anchors/storage.py +32 -0
- will/tools/architectural_context_builder.py +94 -0
- will/tools/cognitive_toolbox.py +47 -0
- will/tools/context/code_snippet_extractor.py +83 -0
- will/tools/context/embedding_search.py +76 -0
- will/tools/context/formatter.py +87 -0
- will/tools/context/models.py +38 -0
- will/tools/context/query_builder.py +42 -0
- will/tools/context/retriever.py +182 -0
- will/tools/context/standards.py +53 -0
- will/tools/file_navigator.py +180 -0
- will/tools/layers.py +31 -0
- will/tools/module_anchor_generator.py +137 -0
- will/tools/module_descriptor.py +154 -0
- will/tools/policy_vectorizer.py +184 -0
- will/tools/symbol_finder.py +188 -0
- will/tools/tool_generator.py +103 -0
- will/workers/audit_ingest_worker.py +207 -0
- will/workers/audit_violation_filter.py +108 -0
- will/workers/audit_violation_normalizer.py +108 -0
- will/workers/audit_violation_sensor.py +370 -0
- will/workers/blackboard_shop_manager.py +280 -0
- will/workers/capability_tagger.py +153 -0
- will/workers/circuit_breaker.py +335 -0
- will/workers/coherence_sensor.py +212 -0
- will/workers/commit_reachability_auditor.py +135 -0
- will/workers/db_sync_worker.py +96 -0
- will/workers/governance_embedding/__init__.py +9 -0
- will/workers/governance_embedding/governance_embedder_worker.py +189 -0
- will/workers/intent_inspector.py +599 -0
- will/workers/observer_worker.py +158 -0
- will/workers/prompt_extractor_worker.py +241 -0
- will/workers/proposal_consumer_effects.py +216 -0
- will/workers/proposal_consumer_revival.py +131 -0
- will/workers/proposal_consumer_worker.py +271 -0
- will/workers/proposal_pipeline_shop_manager.py +273 -0
- will/workers/repo_crawler.py +171 -0
- will/workers/repo_embedding/__init__.py +18 -0
- will/workers/repo_embedding/helpers.py +245 -0
- will/workers/repo_embedding/repo_embedder_workers.py +163 -0
- will/workers/test_coverage_sensor.py +208 -0
- will/workers/test_remediator/__init__.py +12 -0
- will/workers/test_remediator/_operations.py +295 -0
- will/workers/test_remediator/worker.py +187 -0
- will/workers/test_runner_sensor.py +430 -0
- will/workers/violation_executor.py +496 -0
- will/workers/violation_remediator.py +394 -0
- will/workers/violation_remediator_blackboard.py +225 -0
- will/workers/violation_remediator_body/__init__.py +12 -0
- will/workers/violation_remediator_body/blackboard.py +139 -0
- will/workers/violation_remediator_body/ceremony.py +154 -0
- will/workers/violation_remediator_body/context.py +70 -0
- will/workers/violation_remediator_body/llm.py +112 -0
- will/workers/violation_remediator_body/models.py +35 -0
- will/workers/violation_remediator_body/worker.py +518 -0
- will/workers/violation_remediator_proposal.py +328 -0
- will/workers/worker_shop_manager.py +244 -0
- will/workflows/__init__.py +23 -0
- will/workflows/dev_sync_reporter.py +274 -0
- will/workflows/dev_sync_workflow.py +118 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# src/shared/infrastructure/llm/fallback_client.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
FallbackAwareLLMClient — wraps an ordered chain of LLM resources with
|
|
5
|
+
lazy client construction and transparent fallback.
|
|
6
|
+
|
|
7
|
+
Each resource in the chain is held as a factory callable. The wrapper
|
|
8
|
+
builds the underlying ``LLMClient`` only when a call actually reaches
|
|
9
|
+
that position. Two failure modes are skipped and recorded as "tried":
|
|
10
|
+
|
|
11
|
+
1. ``httpx.HTTPStatusError`` with status 402 (Payment Required) or 429
|
|
12
|
+
(Too Many Requests) — the resource is reachable but out of quota.
|
|
13
|
+
2. ``ValueError`` raised by the factory itself — typically a provisioning
|
|
14
|
+
failure (missing ``api_url`` / ``model_name`` in ``runtime_settings``,
|
|
15
|
+
missing ``env_prefix``). The resource cannot be reached at all.
|
|
16
|
+
|
|
17
|
+
When every resource has been disqualified, ``ProviderQuotaExhausted`` is
|
|
18
|
+
raised with the per-resource reason tags. Other exceptions propagate
|
|
19
|
+
unchanged so genuine bugs and 5xx failures are not masked.
|
|
20
|
+
|
|
21
|
+
Lazy construction matters: prior to this design, the orchestrator built
|
|
22
|
+
clients eagerly via a list comprehension, so a single misconfigured
|
|
23
|
+
resource anywhere in the qualified set raised ``ValueError`` during
|
|
24
|
+
chain construction and poisoned the entire role — even when an earlier,
|
|
25
|
+
healthy resource would have served the call. Surfaced as a regression
|
|
26
|
+
in the Architect role (#293 follow-up).
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
from collections.abc import Awaitable, Callable
|
|
32
|
+
from typing import Any
|
|
33
|
+
|
|
34
|
+
import httpx
|
|
35
|
+
|
|
36
|
+
from shared.exceptions import ProviderQuotaExhausted
|
|
37
|
+
from shared.infrastructure.llm.client import LLMClient
|
|
38
|
+
from shared.logger import getLogger
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
logger = getLogger(__name__)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
_RETRYABLE_STATUSES: frozenset[int] = frozenset({402, 429})
|
|
45
|
+
|
|
46
|
+
ClientFactory = Callable[[], Awaitable[LLMClient]]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ID: 4e7b9d2a-3c1f-4a85-b6d9-2e8c5f7a1b3d
|
|
50
|
+
class FallbackAwareLLMClient:
|
|
51
|
+
"""
|
|
52
|
+
Duck-compatible wrapper around an ordered chain of LLM resources.
|
|
53
|
+
Exposes the same public surface as ``LLMClient``
|
|
54
|
+
(``make_request_async``, ``make_request_with_system_async``,
|
|
55
|
+
``get_embedding``) so existing callers of
|
|
56
|
+
``CognitiveService.aget_client_for_role`` need no change.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
client_factories: list[ClientFactory],
|
|
62
|
+
resource_names: list[str],
|
|
63
|
+
) -> None:
|
|
64
|
+
if not client_factories:
|
|
65
|
+
raise ValueError(
|
|
66
|
+
"FallbackAwareLLMClient requires at least one client factory."
|
|
67
|
+
)
|
|
68
|
+
if len(client_factories) != len(resource_names):
|
|
69
|
+
raise ValueError(
|
|
70
|
+
"client_factories and resource_names must have the same length "
|
|
71
|
+
f"(got {len(client_factories)} factories, "
|
|
72
|
+
f"{len(resource_names)} names)."
|
|
73
|
+
)
|
|
74
|
+
self._client_factories = client_factories
|
|
75
|
+
self._resource_names = resource_names
|
|
76
|
+
self._clients: dict[int, LLMClient] = {}
|
|
77
|
+
self._unavailable: dict[int, str] = {}
|
|
78
|
+
|
|
79
|
+
# ID: 9c2e4d6f-5a8b-4d72-9e1c-3f8b6a2d5c4e
|
|
80
|
+
async def make_request_async(self, *args: Any, **kwargs: Any) -> str:
|
|
81
|
+
return await self._call_with_fallback("make_request_async", *args, **kwargs)
|
|
82
|
+
|
|
83
|
+
# ID: b7d3a5c9-2e4f-4861-9c8b-5d7a3e1f9c4b
|
|
84
|
+
async def make_request_with_system_async(self, *args: Any, **kwargs: Any) -> str:
|
|
85
|
+
return await self._call_with_fallback(
|
|
86
|
+
"make_request_with_system_async", *args, **kwargs
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# ID: 5f8a2c4d-9e3b-4751-8c2d-6a4b9e3f1c7d
|
|
90
|
+
async def get_embedding(self, *args: Any, **kwargs: Any) -> list[float]:
|
|
91
|
+
return await self._call_with_fallback("get_embedding", *args, **kwargs)
|
|
92
|
+
|
|
93
|
+
async def _ensure_client(self, idx: int) -> LLMClient:
|
|
94
|
+
if idx not in self._clients:
|
|
95
|
+
self._clients[idx] = await self._client_factories[idx]()
|
|
96
|
+
return self._clients[idx]
|
|
97
|
+
|
|
98
|
+
async def _call_with_fallback(
|
|
99
|
+
self, method_name: str, *args: Any, **kwargs: Any
|
|
100
|
+
) -> Any:
|
|
101
|
+
tried: list[tuple[str, str]] = []
|
|
102
|
+
for idx in range(len(self._client_factories)):
|
|
103
|
+
name = self._resource_names[idx]
|
|
104
|
+
|
|
105
|
+
if idx in self._unavailable:
|
|
106
|
+
tried.append((name, self._unavailable[idx]))
|
|
107
|
+
continue
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
client = await self._ensure_client(idx)
|
|
111
|
+
except ValueError as e:
|
|
112
|
+
tag = "provisioning_error"
|
|
113
|
+
self._unavailable[idx] = tag
|
|
114
|
+
tried.append((name, tag))
|
|
115
|
+
logger.warning(
|
|
116
|
+
"LLM resource '%s' failed to provision (%s) — marking "
|
|
117
|
+
"unavailable, trying next fallback (%d/%d)",
|
|
118
|
+
name,
|
|
119
|
+
e,
|
|
120
|
+
idx + 1,
|
|
121
|
+
len(self._client_factories),
|
|
122
|
+
)
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
return await getattr(client, method_name)(*args, **kwargs)
|
|
127
|
+
except httpx.HTTPStatusError as e:
|
|
128
|
+
status = e.response.status_code
|
|
129
|
+
if status not in _RETRYABLE_STATUSES:
|
|
130
|
+
raise
|
|
131
|
+
tag = str(status)
|
|
132
|
+
self._unavailable[idx] = tag
|
|
133
|
+
tried.append((name, tag))
|
|
134
|
+
logger.warning(
|
|
135
|
+
"LLM resource '%s' returned %d on %s — marking "
|
|
136
|
+
"unavailable, trying next fallback (%d/%d)",
|
|
137
|
+
name,
|
|
138
|
+
status,
|
|
139
|
+
method_name,
|
|
140
|
+
idx + 1,
|
|
141
|
+
len(self._client_factories),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
raise ProviderQuotaExhausted(tried_resources=tried)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# src/shared/infrastructure/llm/providers/anthropic.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Provides an AIProvider implementation for the Anthropic Messages API.
|
|
5
|
+
Uses httpx directly — no Anthropic SDK dependency required.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import httpx
|
|
13
|
+
|
|
14
|
+
from shared.infrastructure.intent.operational_config import load_operational_config
|
|
15
|
+
from shared.logger import getLogger
|
|
16
|
+
|
|
17
|
+
from .base import AIProvider
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
_DEFAULT_API_URL = "https://api.anthropic.com"
|
|
23
|
+
_ANTHROPIC_VERSION = "2023-06-01"
|
|
24
|
+
_DEFAULT_SYSTEM = "You are a helpful assistant."
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# ID: 3a1b2c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d
|
|
28
|
+
class AnthropicProvider(AIProvider):
|
|
29
|
+
"""Provider for the Anthropic Messages API."""
|
|
30
|
+
|
|
31
|
+
def _prepare_headers(self) -> dict[str, str]:
|
|
32
|
+
headers = {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
"anthropic-version": _ANTHROPIC_VERSION,
|
|
35
|
+
}
|
|
36
|
+
if self.api_key:
|
|
37
|
+
headers["x-api-key"] = self.api_key
|
|
38
|
+
return headers
|
|
39
|
+
|
|
40
|
+
# ID: 7b8c9d0e-1f2a-3b4c-5d6e-7f8a9b0c1d2e
|
|
41
|
+
async def chat_completion(
|
|
42
|
+
self,
|
|
43
|
+
prompt: str,
|
|
44
|
+
user_id: str,
|
|
45
|
+
system_prompt: str = "",
|
|
46
|
+
max_tokens: int | None = None,
|
|
47
|
+
response_format: dict[str, Any] | None = None,
|
|
48
|
+
usage_sink: dict[str, int] | None = None,
|
|
49
|
+
) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Generates a chat completion using the Anthropic Messages API.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
prompt: User-turn content.
|
|
55
|
+
user_id: Audit identifier (not forwarded — Anthropic API has no user field).
|
|
56
|
+
system_prompt: Constitutional system prompt. Falls back to a neutral
|
|
57
|
+
default when empty.
|
|
58
|
+
max_tokens: Maximum tokens to generate. When None, falls back to the
|
|
59
|
+
operational default.
|
|
60
|
+
response_format: Optional provider-agnostic structured-output contract.
|
|
61
|
+
|
|
62
|
+
Currently ignored for Anthropic in this implementation.
|
|
63
|
+
Anthropic structured output requires a different mapping model
|
|
64
|
+
(typically tool use / constrained interfaces), so unsupported
|
|
65
|
+
formats safely fall back to standard text generation.
|
|
66
|
+
"""
|
|
67
|
+
if max_tokens is None:
|
|
68
|
+
max_tokens = load_operational_config().llm.default_max_tokens
|
|
69
|
+
if response_format:
|
|
70
|
+
logger.debug(
|
|
71
|
+
"AnthropicProvider received response_format type '%s' but will ignore it "
|
|
72
|
+
"and fall back to standard text generation.",
|
|
73
|
+
response_format.get("type"),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
api_url = self.api_url if self.api_url else _DEFAULT_API_URL
|
|
77
|
+
endpoint = f"{api_url}/v1/messages"
|
|
78
|
+
effective_system = (
|
|
79
|
+
system_prompt.strip() if system_prompt.strip() else _DEFAULT_SYSTEM
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
payload = {
|
|
83
|
+
"model": self.model_name,
|
|
84
|
+
"max_tokens": max_tokens,
|
|
85
|
+
"system": effective_system,
|
|
86
|
+
"messages": [
|
|
87
|
+
{"role": "user", "content": prompt},
|
|
88
|
+
],
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
92
|
+
response = await client.post(endpoint, headers=self.headers, json=payload)
|
|
93
|
+
response.raise_for_status()
|
|
94
|
+
data = response.json()
|
|
95
|
+
if usage_sink is not None:
|
|
96
|
+
usage = data.get("usage") or {}
|
|
97
|
+
if "input_tokens" in usage:
|
|
98
|
+
usage_sink["prompt_tokens"] = int(usage["input_tokens"])
|
|
99
|
+
if "output_tokens" in usage:
|
|
100
|
+
usage_sink["completion_tokens"] = int(usage["output_tokens"])
|
|
101
|
+
return data["content"][0]["text"]
|
|
102
|
+
|
|
103
|
+
# ID: 4e5f6a7b-8c9d-0e1f-2a3b-4c5d6e7f8a9b
|
|
104
|
+
async def get_embedding(
|
|
105
|
+
self,
|
|
106
|
+
text: str,
|
|
107
|
+
usage_sink: dict[str, int] | None = None,
|
|
108
|
+
) -> list[float]:
|
|
109
|
+
"""Not supported — Anthropic does not offer an embeddings endpoint."""
|
|
110
|
+
raise NotImplementedError(
|
|
111
|
+
"AnthropicProvider does not support embeddings. "
|
|
112
|
+
"Use OllamaProvider or OpenAIProvider for embedding generation."
|
|
113
|
+
)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# src/shared/infrastructure/llm/providers/base.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Defines the abstract base class for all AI provider strategies.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import httpx
|
|
13
|
+
|
|
14
|
+
from shared.infrastructure.intent.operational_config import load_operational_config
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ID: 32b9740b-010f-4fd0-8886-f17093aa855f
|
|
18
|
+
class AIProvider(ABC):
|
|
19
|
+
"""
|
|
20
|
+
Abstract base class defining the interface for an AI service provider.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
api_url: str,
|
|
26
|
+
model_name: str,
|
|
27
|
+
api_key: str | None = None,
|
|
28
|
+
timeout: int | None = None,
|
|
29
|
+
):
|
|
30
|
+
if timeout is None:
|
|
31
|
+
timeout = load_operational_config().llm.provider_timeout_sec
|
|
32
|
+
self.api_url = api_url.rstrip("/")
|
|
33
|
+
self.model_name = model_name
|
|
34
|
+
self.api_key = api_key
|
|
35
|
+
self.timeout = httpx.Timeout(timeout)
|
|
36
|
+
self.headers = self._prepare_headers()
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def _prepare_headers(self) -> dict[str, str]:
|
|
40
|
+
"""Prepare the specific headers for this provider."""
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
# ID: af87b72f-3b74-419d-b6c1-635c4185c033
|
|
45
|
+
async def chat_completion(
|
|
46
|
+
self,
|
|
47
|
+
prompt: str,
|
|
48
|
+
user_id: str,
|
|
49
|
+
system_prompt: str = "",
|
|
50
|
+
max_tokens: int | None = None,
|
|
51
|
+
response_format: dict[str, Any] | None = None,
|
|
52
|
+
usage_sink: dict[str, int] | None = None,
|
|
53
|
+
) -> str:
|
|
54
|
+
"""
|
|
55
|
+
Generates a text completion for a given prompt.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
prompt: User-turn content.
|
|
59
|
+
user_id: Audit identifier.
|
|
60
|
+
system_prompt: Constitutional system prompt. Empty string uses
|
|
61
|
+
the provider's built-in default.
|
|
62
|
+
max_tokens: Maximum tokens to generate. Controls response length;
|
|
63
|
+
passed directly to the underlying API. When None,
|
|
64
|
+
concrete implementations fall back to the operational
|
|
65
|
+
default.
|
|
66
|
+
response_format: Optional provider-agnostic structured-output
|
|
67
|
+
request contract.
|
|
68
|
+
|
|
69
|
+
Supported shapes from upper layers:
|
|
70
|
+
{"type": "json_object"}
|
|
71
|
+
{"type": "json_schema", "schema": {...}}
|
|
72
|
+
|
|
73
|
+
Providers may:
|
|
74
|
+
- support both shapes natively,
|
|
75
|
+
- support only one of them,
|
|
76
|
+
- ignore unsupported variants and fall back
|
|
77
|
+
to normal text generation.
|
|
78
|
+
usage_sink: Optional dict mutated in place after a successful
|
|
79
|
+
HTTP response to record token usage from the provider
|
|
80
|
+
envelope. Populated keys: 'prompt_tokens' and
|
|
81
|
+
'completion_tokens' when the provider exposes them.
|
|
82
|
+
Allocated per-call by the caller; never shared across
|
|
83
|
+
concurrent invocations.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Raw provider response content as a string.
|
|
87
|
+
"""
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
@abstractmethod
|
|
91
|
+
# ID: bf6da823-1185-4a93-98bb-da095eb92f4f
|
|
92
|
+
async def get_embedding(
|
|
93
|
+
self,
|
|
94
|
+
text: str,
|
|
95
|
+
usage_sink: dict[str, int] | None = None,
|
|
96
|
+
) -> list[float]:
|
|
97
|
+
"""Generate an embedding vector for a given text.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
text: Source text to embed.
|
|
101
|
+
usage_sink: Optional dict mutated in place with 'prompt_tokens'
|
|
102
|
+
when the provider exposes embedding token counts.
|
|
103
|
+
"""
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
# ID: 6f5d4b78-0a92-4a3f-9c50-bb3a4f0e7b21
|
|
107
|
+
async def get_embeddings_batch(
|
|
108
|
+
self,
|
|
109
|
+
texts: list[str],
|
|
110
|
+
usage_sink: dict[str, int] | None = None,
|
|
111
|
+
) -> list[list[float]]:
|
|
112
|
+
"""Generate embedding vectors for a list of texts.
|
|
113
|
+
|
|
114
|
+
Default implementation loops `get_embedding` per text. Providers
|
|
115
|
+
whose backend natively supports list input (e.g., Ollama's
|
|
116
|
+
`/api/embed`) MUST override with a single round-trip variant to
|
|
117
|
+
realise the throughput win (#461). Providers without batch support
|
|
118
|
+
inherit this default unchanged — the call returns identical
|
|
119
|
+
vectors to N serial single-input calls, just without speedup.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
texts: Source texts to embed.
|
|
123
|
+
usage_sink: Optional dict mutated in place with summed
|
|
124
|
+
`prompt_tokens` across the batch. Per-text token
|
|
125
|
+
attribution is not preserved (#461 D2 decision).
|
|
126
|
+
"""
|
|
127
|
+
results: list[list[float]] = []
|
|
128
|
+
for text in texts:
|
|
129
|
+
results.append(await self.get_embedding(text, usage_sink=usage_sink))
|
|
130
|
+
return results
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# src/shared/infrastructure/llm/providers/ollama.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Provides an AIProvider implementation for Ollama APIs.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
from shared.infrastructure.intent.operational_config import load_operational_config
|
|
14
|
+
from shared.logger import getLogger
|
|
15
|
+
|
|
16
|
+
from .base import AIProvider
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = getLogger(__name__)
|
|
20
|
+
GHOST_VECTOR_START = [0.63719, 0.45393, -4.16063]
|
|
21
|
+
_DEFAULT_SYSTEM = "You are a helpful assistant."
|
|
22
|
+
|
|
23
|
+
# nomic-embed-text supports up to 8192 tokens. At ~3 chars/token for source
|
|
24
|
+
# code, the configured cap (default 20000) sits safely under the limit for
|
|
25
|
+
# the vast majority of files.
|
|
26
|
+
_CFG_EMB = load_operational_config().embedding
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# ID: 3f78f7ca-33b1-4ac3-a701-30885722e7b1
|
|
30
|
+
class OllamaProvider(AIProvider):
|
|
31
|
+
"""Provider for Ollama-compatible chat and embedding APIs."""
|
|
32
|
+
|
|
33
|
+
def _prepare_headers(self) -> dict[str, str]:
|
|
34
|
+
return {"Content-Type": "application/json"}
|
|
35
|
+
|
|
36
|
+
# ID: b4ddef76-9da6-4b19-ad12-8f92eac28f86
|
|
37
|
+
async def chat_completion(
|
|
38
|
+
self,
|
|
39
|
+
prompt: str,
|
|
40
|
+
user_id: str,
|
|
41
|
+
system_prompt: str = "",
|
|
42
|
+
max_tokens: int | None = None,
|
|
43
|
+
response_format: dict[str, Any] | None = None,
|
|
44
|
+
usage_sink: dict[str, int] | None = None,
|
|
45
|
+
) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Generates a chat completion using the Ollama /api/chat format.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
prompt: User-turn content.
|
|
51
|
+
user_id: Audit identifier (unused by Ollama but kept for interface parity).
|
|
52
|
+
system_prompt: Constitutional system prompt sent as the first
|
|
53
|
+
system-role message. Falls back to a neutral default
|
|
54
|
+
when empty so the model always receives a system turn.
|
|
55
|
+
max_tokens: Mapped to Ollama's options.num_predict to cap output length.
|
|
56
|
+
When None, falls back to the operational default.
|
|
57
|
+
response_format: Optional provider-agnostic structured-output contract.
|
|
58
|
+
|
|
59
|
+
Supported:
|
|
60
|
+
{"type": "json_object"}
|
|
61
|
+
{"type": "json_schema", "schema": {...}}
|
|
62
|
+
|
|
63
|
+
Ollama mapping:
|
|
64
|
+
- json_object -> payload["format"] = "json"
|
|
65
|
+
- json_schema -> payload["format"] = <raw schema dict>
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Raw text content from Ollama's assistant message.
|
|
69
|
+
"""
|
|
70
|
+
if max_tokens is None:
|
|
71
|
+
max_tokens = load_operational_config().llm.default_max_tokens
|
|
72
|
+
endpoint = f"{self.api_url}/api/chat"
|
|
73
|
+
effective_system = (
|
|
74
|
+
system_prompt.strip() if system_prompt.strip() else _DEFAULT_SYSTEM
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
payload: dict[str, Any] = {
|
|
78
|
+
"model": self.model_name,
|
|
79
|
+
"messages": [
|
|
80
|
+
{"role": "system", "content": effective_system},
|
|
81
|
+
{"role": "user", "content": prompt},
|
|
82
|
+
],
|
|
83
|
+
"stream": False,
|
|
84
|
+
"options": {
|
|
85
|
+
"num_predict": max_tokens,
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if response_format:
|
|
90
|
+
format_type = response_format.get("type")
|
|
91
|
+
|
|
92
|
+
if format_type == "json_schema":
|
|
93
|
+
schema = response_format.get("schema")
|
|
94
|
+
if isinstance(schema, dict) and schema:
|
|
95
|
+
payload["format"] = schema
|
|
96
|
+
logger.debug(
|
|
97
|
+
"OllamaProvider using native JSON Schema structured output "
|
|
98
|
+
"for model '%s'.",
|
|
99
|
+
self.model_name,
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
logger.warning(
|
|
103
|
+
"OllamaProvider received invalid json_schema response_format; "
|
|
104
|
+
"falling back to normal text generation."
|
|
105
|
+
)
|
|
106
|
+
elif format_type == "json_object":
|
|
107
|
+
payload["format"] = "json"
|
|
108
|
+
logger.debug(
|
|
109
|
+
"OllamaProvider using JSON object mode for model '%s'.",
|
|
110
|
+
self.model_name,
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
logger.warning(
|
|
114
|
+
"OllamaProvider received unsupported response_format type '%s'; "
|
|
115
|
+
"falling back to normal text generation.",
|
|
116
|
+
format_type,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
120
|
+
response = await client.post(endpoint, headers=self.headers, json=payload)
|
|
121
|
+
response.raise_for_status()
|
|
122
|
+
data = response.json()
|
|
123
|
+
if usage_sink is not None:
|
|
124
|
+
if "prompt_eval_count" in data:
|
|
125
|
+
usage_sink["prompt_tokens"] = int(data["prompt_eval_count"])
|
|
126
|
+
if "eval_count" in data:
|
|
127
|
+
usage_sink["completion_tokens"] = int(data["eval_count"])
|
|
128
|
+
return data["message"]["content"]
|
|
129
|
+
|
|
130
|
+
# ID: fcc3342d-746d-4bb4-b153-8eef9465c0f0
|
|
131
|
+
async def get_embedding(
|
|
132
|
+
self,
|
|
133
|
+
text: str,
|
|
134
|
+
usage_sink: dict[str, int] | None = None,
|
|
135
|
+
) -> list[float]:
|
|
136
|
+
"""
|
|
137
|
+
Generates an embedding using the Ollama /api/embed format (Ollama 0.4+).
|
|
138
|
+
|
|
139
|
+
Uses the current Ollama embedding API:
|
|
140
|
+
POST /api/embed
|
|
141
|
+
payload: {"model": ..., "input": ..., "options": {"num_ctx": ...}}
|
|
142
|
+
response: {"embeddings": [[...]]}
|
|
143
|
+
|
|
144
|
+
num_ctx is passed explicitly per-request because Ollama ignores
|
|
145
|
+
num_ctx in the Modelfile for embedding models.
|
|
146
|
+
|
|
147
|
+
Input is truncated to _CFG_EMB.max_chars before sending as a
|
|
148
|
+
last-resort safety net.
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
RuntimeError: If the model returns a Ghost Vector, indicating
|
|
152
|
+
an Ollama model failure rather than a real embedding.
|
|
153
|
+
"""
|
|
154
|
+
endpoint = f"{self.api_url}/api/embed"
|
|
155
|
+
|
|
156
|
+
if len(text) > _CFG_EMB.max_chars:
|
|
157
|
+
logger.warning(
|
|
158
|
+
"Embedding input truncated from %d to %d chars (model context limit).",
|
|
159
|
+
len(text),
|
|
160
|
+
_CFG_EMB.max_chars,
|
|
161
|
+
)
|
|
162
|
+
text = text[: _CFG_EMB.max_chars]
|
|
163
|
+
|
|
164
|
+
payload = {
|
|
165
|
+
"model": self.model_name,
|
|
166
|
+
"input": text,
|
|
167
|
+
"options": {"num_ctx": 8192},
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
171
|
+
response = await client.post(endpoint, headers=self.headers, json=payload)
|
|
172
|
+
response.raise_for_status()
|
|
173
|
+
data = response.json()
|
|
174
|
+
vec = data["embeddings"][0]
|
|
175
|
+
|
|
176
|
+
if len(vec) > 3:
|
|
177
|
+
is_ghost = all(
|
|
178
|
+
abs(a - b) < 0.001 for a, b in zip(vec[:3], GHOST_VECTOR_START)
|
|
179
|
+
)
|
|
180
|
+
if is_ghost:
|
|
181
|
+
logger.error(
|
|
182
|
+
"Ollama returned Ghost Vector (Model Failure) for input length %s",
|
|
183
|
+
len(text),
|
|
184
|
+
)
|
|
185
|
+
raise RuntimeError("Embedding model failed (Ghost Vector returned)")
|
|
186
|
+
|
|
187
|
+
return vec
|
|
188
|
+
|
|
189
|
+
# ID: 9e2c4f81-3a6d-4b85-b4f7-c8d3a1e09f72
|
|
190
|
+
async def get_embeddings_batch(
|
|
191
|
+
self,
|
|
192
|
+
texts: list[str],
|
|
193
|
+
usage_sink: dict[str, int] | None = None,
|
|
194
|
+
) -> list[list[float]]:
|
|
195
|
+
"""Generate embeddings for a list of texts in a single round-trip.
|
|
196
|
+
|
|
197
|
+
Uses Ollama's `/api/embed` list-input form (Ollama 0.4+):
|
|
198
|
+
payload: {"model": ..., "input": [t1, t2, ...], "options": {...}}
|
|
199
|
+
response: {"embeddings": [[...], [...], ...]} aligned to input order
|
|
200
|
+
|
|
201
|
+
Empty input list returns `[]` without an HTTP call. Each text is
|
|
202
|
+
truncated to `_CFG_EMB.max_chars` before sending, matching the
|
|
203
|
+
single-input path. Ghost-vector check applied per-element; one bad
|
|
204
|
+
vector raises and aborts the whole batch (consumer handles the
|
|
205
|
+
retry/skip — same posture as the single-input path).
|
|
206
|
+
|
|
207
|
+
Per #461 D2: token usage from the batch response is summed into
|
|
208
|
+
`usage_sink`; per-text attribution is lost.
|
|
209
|
+
"""
|
|
210
|
+
if not texts:
|
|
211
|
+
return []
|
|
212
|
+
|
|
213
|
+
endpoint = f"{self.api_url}/api/embed"
|
|
214
|
+
|
|
215
|
+
prepared: list[str] = []
|
|
216
|
+
for text in texts:
|
|
217
|
+
if len(text) > _CFG_EMB.max_chars:
|
|
218
|
+
logger.warning(
|
|
219
|
+
"Embedding input truncated from %d to %d chars (model context limit).",
|
|
220
|
+
len(text),
|
|
221
|
+
_CFG_EMB.max_chars,
|
|
222
|
+
)
|
|
223
|
+
prepared.append(text[: _CFG_EMB.max_chars])
|
|
224
|
+
else:
|
|
225
|
+
prepared.append(text)
|
|
226
|
+
|
|
227
|
+
payload = {
|
|
228
|
+
"model": self.model_name,
|
|
229
|
+
"input": prepared,
|
|
230
|
+
"options": {"num_ctx": 8192},
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
234
|
+
response = await client.post(endpoint, headers=self.headers, json=payload)
|
|
235
|
+
response.raise_for_status()
|
|
236
|
+
data = response.json()
|
|
237
|
+
vectors = data["embeddings"]
|
|
238
|
+
|
|
239
|
+
if len(vectors) != len(prepared):
|
|
240
|
+
raise RuntimeError(
|
|
241
|
+
f"Ollama returned {len(vectors)} embeddings for {len(prepared)} "
|
|
242
|
+
"inputs — batch response misalignment"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
for i, vec in enumerate(vectors):
|
|
246
|
+
if len(vec) > 3:
|
|
247
|
+
is_ghost = all(
|
|
248
|
+
abs(a - b) < 0.001 for a, b in zip(vec[:3], GHOST_VECTOR_START)
|
|
249
|
+
)
|
|
250
|
+
if is_ghost:
|
|
251
|
+
logger.error(
|
|
252
|
+
"Ollama returned Ghost Vector (Model Failure) for batch "
|
|
253
|
+
"input %d/%d (length %s)",
|
|
254
|
+
i,
|
|
255
|
+
len(prepared),
|
|
256
|
+
len(prepared[i]),
|
|
257
|
+
)
|
|
258
|
+
raise RuntimeError(
|
|
259
|
+
"Embedding model failed (Ghost Vector returned in batch)"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
if usage_sink is not None and "prompt_eval_count" in data:
|
|
263
|
+
usage_sink["prompt_tokens"] = int(data["prompt_eval_count"])
|
|
264
|
+
|
|
265
|
+
return vectors
|