onto-mcp 0.3.0
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/.onto/authority/core-lens-registry.yaml +134 -0
- package/.onto/authority/core-lexicon.yaml +1562 -0
- package/.onto/authority/diagnostic-codes.yaml +94 -0
- package/.onto/domains/accounting/competency_qs.md +384 -0
- package/.onto/domains/accounting/concepts.md +186 -0
- package/.onto/domains/accounting/conciseness_rules.md +160 -0
- package/.onto/domains/accounting/dependency_rules.md +239 -0
- package/.onto/domains/accounting/domain_scope.md +213 -0
- package/.onto/domains/accounting/extension_cases.md +416 -0
- package/.onto/domains/accounting/logic_rules.md +226 -0
- package/.onto/domains/accounting/structure_spec.md +298 -0
- package/.onto/domains/accounting-kr/competency_qs.md +562 -0
- package/.onto/domains/accounting-kr/concepts.md +187 -0
- package/.onto/domains/accounting-kr/conciseness_rules.md +125 -0
- package/.onto/domains/accounting-kr/dependency_rules.md +93 -0
- package/.onto/domains/accounting-kr/domain_scope.md +140 -0
- package/.onto/domains/accounting-kr/extension_cases.md +343 -0
- package/.onto/domains/accounting-kr/logic_rules.md +160 -0
- package/.onto/domains/accounting-kr/structure_spec.md +85 -0
- package/.onto/domains/business/competency_qs.md +263 -0
- package/.onto/domains/business/concepts.md +200 -0
- package/.onto/domains/business/conciseness_rules.md +135 -0
- package/.onto/domains/business/dependency_rules.md +113 -0
- package/.onto/domains/business/domain_scope.md +240 -0
- package/.onto/domains/business/extension_cases.md +249 -0
- package/.onto/domains/business/logic_rules.md +134 -0
- package/.onto/domains/business/structure_spec.md +114 -0
- package/.onto/domains/finance/competency_qs.md +362 -0
- package/.onto/domains/finance/concepts.md +194 -0
- package/.onto/domains/finance/conciseness_rules.md +155 -0
- package/.onto/domains/finance/dependency_rules.md +171 -0
- package/.onto/domains/finance/domain_scope.md +215 -0
- package/.onto/domains/finance/extension_cases.md +350 -0
- package/.onto/domains/finance/logic_rules.md +191 -0
- package/.onto/domains/finance/structure_spec.md +182 -0
- package/.onto/domains/llm-native-development/competency_qs.md +430 -0
- package/.onto/domains/llm-native-development/concepts.md +242 -0
- package/.onto/domains/llm-native-development/conciseness_rules.md +163 -0
- package/.onto/domains/llm-native-development/dependency_rules.md +216 -0
- package/.onto/domains/llm-native-development/domain_scope.md +197 -0
- package/.onto/domains/llm-native-development/extension_cases.md +474 -0
- package/.onto/domains/llm-native-development/logic_rules.md +123 -0
- package/.onto/domains/llm-native-development/prompt_interface.md +49 -0
- package/.onto/domains/llm-native-development/structure_spec.md +245 -0
- package/.onto/domains/market-intelligence/competency_qs.md +274 -0
- package/.onto/domains/market-intelligence/concepts.md +233 -0
- package/.onto/domains/market-intelligence/conciseness_rules.md +165 -0
- package/.onto/domains/market-intelligence/dependency_rules.md +197 -0
- package/.onto/domains/market-intelligence/domain_scope.md +231 -0
- package/.onto/domains/market-intelligence/extension_cases.md +425 -0
- package/.onto/domains/market-intelligence/logic_rules.md +247 -0
- package/.onto/domains/market-intelligence/structure_spec.md +209 -0
- package/.onto/domains/ontology/competency_qs.md +394 -0
- package/.onto/domains/ontology/concepts.md +172 -0
- package/.onto/domains/ontology/conciseness_rules.md +134 -0
- package/.onto/domains/ontology/dependency_rules.md +125 -0
- package/.onto/domains/ontology/domain_scope.md +114 -0
- package/.onto/domains/ontology/extension_cases.md +501 -0
- package/.onto/domains/ontology/logic_rules.md +114 -0
- package/.onto/domains/ontology/problem_framing_profile.md +67 -0
- package/.onto/domains/ontology/structure_spec.md +115 -0
- package/.onto/domains/palantir-foundry/RESEARCH_NOTES.md +911 -0
- package/.onto/domains/palantir-foundry/competency_qs.md +191 -0
- package/.onto/domains/palantir-foundry/competitive_comparison.md +329 -0
- package/.onto/domains/palantir-foundry/concepts.md +197 -0
- package/.onto/domains/palantir-foundry/conciseness_rules.md +245 -0
- package/.onto/domains/palantir-foundry/dependency_rules.md +135 -0
- package/.onto/domains/palantir-foundry/domain_scope.md +395 -0
- package/.onto/domains/palantir-foundry/extension_cases.md +210 -0
- package/.onto/domains/palantir-foundry/logic_rules.md +172 -0
- package/.onto/domains/palantir-foundry/structure_spec.md +291 -0
- package/.onto/domains/software-engineering/competency_qs.md +538 -0
- package/.onto/domains/software-engineering/concepts.md +238 -0
- package/.onto/domains/software-engineering/conciseness_rules.md +167 -0
- package/.onto/domains/software-engineering/dependency_rules.md +216 -0
- package/.onto/domains/software-engineering/domain_scope.md +183 -0
- package/.onto/domains/software-engineering/extension_cases.md +551 -0
- package/.onto/domains/software-engineering/logic_rules.md +240 -0
- package/.onto/domains/software-engineering/problem_framing_profile.md +68 -0
- package/.onto/domains/software-engineering/structure_spec.md +185 -0
- package/.onto/domains/ui-design/competency_qs.md +567 -0
- package/.onto/domains/ui-design/concepts.md +194 -0
- package/.onto/domains/ui-design/conciseness_rules.md +190 -0
- package/.onto/domains/ui-design/dependency_rules.md +323 -0
- package/.onto/domains/ui-design/domain_scope.md +340 -0
- package/.onto/domains/ui-design/extension_cases.md +563 -0
- package/.onto/domains/ui-design/logic_rules.md +349 -0
- package/.onto/domains/ui-design/structure_spec.md +252 -0
- package/.onto/domains/visual-design/competency_qs.md +472 -0
- package/.onto/domains/visual-design/concepts.md +147 -0
- package/.onto/domains/visual-design/conciseness_rules.md +186 -0
- package/.onto/domains/visual-design/dependency_rules.md +282 -0
- package/.onto/domains/visual-design/domain_scope.md +290 -0
- package/.onto/domains/visual-design/extension_cases.md +480 -0
- package/.onto/domains/visual-design/logic_rules.md +232 -0
- package/.onto/domains/visual-design/structure_spec.md +213 -0
- package/.onto/principles/llm-native-development-guideline.md +401 -0
- package/.onto/principles/llm-runtime-interface-principles.md +665 -0
- package/.onto/principles/non-specialist-communication-guideline.md +74 -0
- package/.onto/principles/ontology-as-code-guideline.md +243 -0
- package/.onto/principles/ontology-as-code-naming-charter.md +130 -0
- package/.onto/principles/product-locality-principle.md +129 -0
- package/.onto/principles/productization-charter.md +569 -0
- package/.onto/processes/evolve/material-kind-adapter-contract.md +113 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +366 -0
- package/.onto/processes/reconstruct/source-profile-contract.md +107 -0
- package/.onto/processes/reconstruct/source-profiles/code.md +72 -0
- package/.onto/processes/reconstruct/source-profiles/database.md +74 -0
- package/.onto/processes/reconstruct/source-profiles/document.md +71 -0
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +79 -0
- package/.onto/processes/review/binding-contract.md +270 -0
- package/.onto/processes/review/execution-preparation-artifacts.md +281 -0
- package/.onto/processes/review/interpretation-contract.md +245 -0
- package/.onto/processes/review/issue-stance-deliberation-contract.md +761 -0
- package/.onto/processes/review/lens-prompt-contract.md +402 -0
- package/.onto/processes/review/lens-registry.md +127 -0
- package/.onto/processes/review/pre-dispatch-contracts.md +428 -0
- package/.onto/processes/review/productized-live-path.md +398 -0
- package/.onto/processes/review/prompt-execution-runner-contract.md +187 -0
- package/.onto/processes/review/record-contract.md +427 -0
- package/.onto/processes/review/record-field-mapping.md +337 -0
- package/.onto/processes/review/review-context-manifest-contract.md +356 -0
- package/.onto/processes/review/review-execution-ux-contract.md +809 -0
- package/.onto/processes/review/review-target-profile-contract.md +259 -0
- package/.onto/processes/review/shared-phenomenon-contract.md +129 -0
- package/.onto/processes/review/synthesize-prompt-contract.md +343 -0
- package/.onto/processes/shared/target-material-kind-contract.md +198 -0
- package/.onto/roles/axiology.md +81 -0
- package/.onto/roles/conciseness.md +36 -0
- package/.onto/roles/coverage.md +34 -0
- package/.onto/roles/dependency.md +37 -0
- package/.onto/roles/evolution.md +35 -0
- package/.onto/roles/logic.md +104 -0
- package/.onto/roles/pragmatics.md +32 -0
- package/.onto/roles/semantics.md +36 -0
- package/.onto/roles/structure.md +33 -0
- package/.onto/roles/synthesize.md +92 -0
- package/AGENTS.md +240 -0
- package/CLAUDE.md +39 -0
- package/README.md +287 -0
- package/bin/onto +92 -0
- package/dist/cli.js +101 -0
- package/dist/core-api/reconstruct-api.js +222 -0
- package/dist/core-api/review-api.js +1271 -0
- package/dist/core-runtime/cli/assemble-review-record.js +431 -0
- package/dist/core-runtime/cli/bootstrap-review-binding.js +186 -0
- package/dist/core-runtime/cli/codex-nested-dispatch.js +226 -0
- package/dist/core-runtime/cli/codex-nested-dispatch.test.js +390 -0
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.js +464 -0
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +335 -0
- package/dist/core-runtime/cli/codex-review-unit-executor.js +228 -0
- package/dist/core-runtime/cli/complete-review-session.js +64 -0
- package/dist/core-runtime/cli/complexity-assessment.js +153 -0
- package/dist/core-runtime/cli/coordinator-helpers.js +583 -0
- package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +167 -0
- package/dist/core-runtime/cli/coordinator-state-machine.js +794 -0
- package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +615 -0
- package/dist/core-runtime/cli/e2e-start-review-session.test.js +312 -0
- package/dist/core-runtime/cli/health.js +44 -0
- package/dist/core-runtime/cli/inline-http-review-unit-executor.js +656 -0
- package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +567 -0
- package/dist/core-runtime/cli/materialize-review-execution-preparation.js +104 -0
- package/dist/core-runtime/cli/materialize-review-prompt-packets.js +952 -0
- package/dist/core-runtime/cli/migrate-session-roots.js +118 -0
- package/dist/core-runtime/cli/mock-review-unit-executor.js +285 -0
- package/dist/core-runtime/cli/onto-tools.js +369 -0
- package/dist/core-runtime/cli/prepare-review-session.js +272 -0
- package/dist/core-runtime/cli/render-review-final-output.js +350 -0
- package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +106 -0
- package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +268 -0
- package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +136 -0
- package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +201 -0
- package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +192 -0
- package/dist/core-runtime/cli/review-invoke.js +2030 -0
- package/dist/core-runtime/cli/run-review-prompt-execution.js +2152 -0
- package/dist/core-runtime/cli/session-root-guard.js +168 -0
- package/dist/core-runtime/cli/spawn-watcher.js +173 -0
- package/dist/core-runtime/cli/spawn-watcher.test.js +457 -0
- package/dist/core-runtime/cli/start-review-session.js +68 -0
- package/dist/core-runtime/cli/strip-wrapping-code-fence.js +56 -0
- package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +79 -0
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +412 -0
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +351 -0
- package/dist/core-runtime/cli/topology-executor-mapping.js +139 -0
- package/dist/core-runtime/cli/topology-executor-mapping.test.js +173 -0
- package/dist/core-runtime/cli/write-review-interpretation.js +81 -0
- package/dist/core-runtime/config/onto-config-cli.js +278 -0
- package/dist/core-runtime/config/onto-config-key-path.js +288 -0
- package/dist/core-runtime/config/onto-config-key-path.test.js +195 -0
- package/dist/core-runtime/config/onto-config-preview.js +108 -0
- package/dist/core-runtime/config/onto-config-preview.test.js +132 -0
- package/dist/core-runtime/discovery/config-chain.js +118 -0
- package/dist/core-runtime/discovery/config-chain.test.js +103 -0
- package/dist/core-runtime/discovery/config-profile.js +199 -0
- package/dist/core-runtime/discovery/config-profile.test.js +233 -0
- package/dist/core-runtime/discovery/host-detection.js +33 -0
- package/dist/core-runtime/discovery/host-detection.test.js +186 -0
- package/dist/core-runtime/discovery/installation-paths.js +21 -0
- package/dist/core-runtime/discovery/installation-paths.test.js +65 -0
- package/dist/core-runtime/discovery/lens-registry.js +60 -0
- package/dist/core-runtime/discovery/lens-registry.test.js +81 -0
- package/dist/core-runtime/discovery/onto-home.js +71 -0
- package/dist/core-runtime/discovery/path-normalization.js +28 -0
- package/dist/core-runtime/discovery/path-normalization.test.js +22 -0
- package/dist/core-runtime/discovery/plugin-path.js +72 -0
- package/dist/core-runtime/discovery/plugin-path.test.js +95 -0
- package/dist/core-runtime/discovery/project-root.js +47 -0
- package/dist/core-runtime/discovery/settings-chain.js +353 -0
- package/dist/core-runtime/discovery/walk-up.js +17 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +344 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +915 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +564 -0
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +708 -0
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +165 -0
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +227 -0
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +59 -0
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +205 -0
- package/dist/core-runtime/evolve/adapters/methodology/adapter.js +16 -0
- package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +9 -0
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +298 -0
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +70 -0
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +46 -0
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +73 -0
- package/dist/core-runtime/evolve/adapters/registry.js +47 -0
- package/dist/core-runtime/evolve/adapters/registry.test.js +67 -0
- package/dist/core-runtime/evolve/cli.js +256 -0
- package/dist/core-runtime/evolve/commands/align.js +194 -0
- package/dist/core-runtime/evolve/commands/align.test.js +82 -0
- package/dist/core-runtime/evolve/commands/apply.js +161 -0
- package/dist/core-runtime/evolve/commands/apply.test.js +138 -0
- package/dist/core-runtime/evolve/commands/close.js +39 -0
- package/dist/core-runtime/evolve/commands/close.test.js +99 -0
- package/dist/core-runtime/evolve/commands/defer.js +40 -0
- package/dist/core-runtime/evolve/commands/defer.test.js +134 -0
- package/dist/core-runtime/evolve/commands/draft.js +323 -0
- package/dist/core-runtime/evolve/commands/draft.test.js +178 -0
- package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +208 -0
- package/dist/core-runtime/evolve/commands/error-messages.js +125 -0
- package/dist/core-runtime/evolve/commands/error-messages.test.js +167 -0
- package/dist/core-runtime/evolve/commands/propose-align.js +222 -0
- package/dist/core-runtime/evolve/commands/propose-align.test.js +136 -0
- package/dist/core-runtime/evolve/commands/reconstruct.js +330 -0
- package/dist/core-runtime/evolve/commands/reconstruct.test.js +278 -0
- package/dist/core-runtime/evolve/commands/shared.js +22 -0
- package/dist/core-runtime/evolve/commands/stale-check.js +103 -0
- package/dist/core-runtime/evolve/commands/stale-check.test.js +84 -0
- package/dist/core-runtime/evolve/commands/start.js +887 -0
- package/dist/core-runtime/evolve/commands/start.test.js +396 -0
- package/dist/core-runtime/evolve/config/project-config.js +99 -0
- package/dist/core-runtime/evolve/config/project-config.test.js +170 -0
- package/dist/core-runtime/evolve/renderers/align-packet.js +280 -0
- package/dist/core-runtime/evolve/renderers/align-packet.test.js +332 -0
- package/dist/core-runtime/evolve/renderers/draft-packet.js +303 -0
- package/dist/core-runtime/evolve/renderers/draft-packet.test.js +377 -0
- package/dist/core-runtime/evolve/renderers/format.js +5 -0
- package/dist/core-runtime/evolve/renderers/scope-md.js +237 -0
- package/dist/core-runtime/evolve/renderers/scope-md.test.js +306 -0
- package/dist/core-runtime/govern/cli.js +369 -0
- package/dist/core-runtime/govern/cli.test.js +314 -0
- package/dist/core-runtime/govern/drift-engine.js +103 -0
- package/dist/core-runtime/govern/drift-engine.test.js +319 -0
- package/dist/core-runtime/govern/promote-principle.js +206 -0
- package/dist/core-runtime/govern/promote-principle.test.js +368 -0
- package/dist/core-runtime/govern/queue.js +81 -0
- package/dist/core-runtime/govern/types.js +16 -0
- package/dist/core-runtime/install/cli.js +530 -0
- package/dist/core-runtime/install/detect.js +128 -0
- package/dist/core-runtime/install/detect.test.js +155 -0
- package/dist/core-runtime/install/gitignore-update.js +74 -0
- package/dist/core-runtime/install/gitignore-update.test.js +64 -0
- package/dist/core-runtime/install/install-integration.test.js +373 -0
- package/dist/core-runtime/install/prompts.js +389 -0
- package/dist/core-runtime/install/prompts.test.js +293 -0
- package/dist/core-runtime/install/types.js +26 -0
- package/dist/core-runtime/install/validation.js +295 -0
- package/dist/core-runtime/install/validation.test.js +313 -0
- package/dist/core-runtime/install/writer.js +254 -0
- package/dist/core-runtime/install/writer.test.js +218 -0
- package/dist/core-runtime/learning/extractor.js +461 -0
- package/dist/core-runtime/learning/feedback.js +179 -0
- package/dist/core-runtime/learning/health-report.js +165 -0
- package/dist/core-runtime/learning/health-report.test.js +169 -0
- package/dist/core-runtime/learning/loader.js +388 -0
- package/dist/core-runtime/learning/loader.test.js +102 -0
- package/dist/core-runtime/learning/promote/apply-state.js +240 -0
- package/dist/core-runtime/learning/promote/audit-obligation.js +195 -0
- package/dist/core-runtime/learning/promote/collector.js +432 -0
- package/dist/core-runtime/learning/promote/degraded-state.js +125 -0
- package/dist/core-runtime/learning/promote/domain-doc-proposer.js +166 -0
- package/dist/core-runtime/learning/promote/e2e-promote.test.js +6385 -0
- package/dist/core-runtime/learning/promote/health-snapshot.js +150 -0
- package/dist/core-runtime/learning/promote/insight-reclassifier.js +544 -0
- package/dist/core-runtime/learning/promote/judgment-auditor.js +517 -0
- package/dist/core-runtime/learning/promote/panel-reviewer.js +1158 -0
- package/dist/core-runtime/learning/promote/promote-executor.js +1675 -0
- package/dist/core-runtime/learning/promote/promoter.js +307 -0
- package/dist/core-runtime/learning/promote/retirement.js +122 -0
- package/dist/core-runtime/learning/promote/types.js +23 -0
- package/dist/core-runtime/learning/prompt-sections.js +51 -0
- package/dist/core-runtime/learning/shared/artifact-registry-init.js +45 -0
- package/dist/core-runtime/learning/shared/artifact-registry.js +254 -0
- package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +73 -0
- package/dist/core-runtime/learning/shared/audit-state.js +99 -0
- package/dist/core-runtime/learning/shared/duplicate-check.js +28 -0
- package/dist/core-runtime/learning/shared/llm-caller.js +831 -0
- package/dist/core-runtime/learning/shared/llm-caller.test.js +601 -0
- package/dist/core-runtime/learning/shared/llm-tool-loop.js +393 -0
- package/dist/core-runtime/learning/shared/mode.js +25 -0
- package/dist/core-runtime/learning/shared/paths.js +84 -0
- package/dist/core-runtime/learning/shared/paths.test.js +79 -0
- package/dist/core-runtime/learning/shared/patterns.js +37 -0
- package/dist/core-runtime/learning/shared/recoverability.js +355 -0
- package/dist/core-runtime/learning/shared/recovery-context.js +374 -0
- package/dist/core-runtime/learning/shared/scope.js +1 -0
- package/dist/core-runtime/learning/shared/semantic-classifier.js +94 -0
- package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +42 -0
- package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +37 -0
- package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +39 -0
- package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +41 -0
- package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +38 -0
- package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +43 -0
- package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +113 -0
- package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +36 -0
- package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +48 -0
- package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +43 -0
- package/dist/core-runtime/learning/shared/specs/spec-helpers.js +64 -0
- package/dist/core-runtime/learning/usage-tracker.js +190 -0
- package/dist/core-runtime/learning/usage-tracker.test.js +176 -0
- package/dist/core-runtime/llm/llm-caller.js +649 -0
- package/dist/core-runtime/llm/llm-tool-loop.js +401 -0
- package/dist/core-runtime/llm/model-switcher.js +62 -0
- package/dist/core-runtime/logger.js +22 -0
- package/dist/core-runtime/onboard/detect-review-axes.js +122 -0
- package/dist/core-runtime/onboard/detect-review-axes.test.js +127 -0
- package/dist/core-runtime/onboard/write-review-block.js +188 -0
- package/dist/core-runtime/onboard/write-review-block.test.js +240 -0
- package/dist/core-runtime/readers/brownfield-builder.js +150 -0
- package/dist/core-runtime/readers/brownfield-builder.test.js +136 -0
- package/dist/core-runtime/readers/code-chunk-collector.js +53 -0
- package/dist/core-runtime/readers/code-chunk-collector.test.js +136 -0
- package/dist/core-runtime/readers/file-utils.js +240 -0
- package/dist/core-runtime/readers/file-utils.test.js +146 -0
- package/dist/core-runtime/readers/lexicon-citation-check.js +93 -0
- package/dist/core-runtime/readers/lexicon-citation-check.test.js +77 -0
- package/dist/core-runtime/readers/mcp-figma.js +30 -0
- package/dist/core-runtime/readers/mcp-figma.test.js +82 -0
- package/dist/core-runtime/readers/mcp-generic.js +31 -0
- package/dist/core-runtime/readers/mcp-generic.test.js +76 -0
- package/dist/core-runtime/readers/ontology-index.js +148 -0
- package/dist/core-runtime/readers/ontology-index.test.js +245 -0
- package/dist/core-runtime/readers/ontology-query.js +168 -0
- package/dist/core-runtime/readers/ontology-query.test.js +311 -0
- package/dist/core-runtime/readers/ontology-resolve.js +48 -0
- package/dist/core-runtime/readers/ontology-resolve.test.js +48 -0
- package/dist/core-runtime/readers/patterns/index.js +7 -0
- package/dist/core-runtime/readers/review-log.js +213 -0
- package/dist/core-runtime/readers/review-log.test.js +313 -0
- package/dist/core-runtime/readers/scan-local.js +102 -0
- package/dist/core-runtime/readers/scan-local.test.js +102 -0
- package/dist/core-runtime/readers/scan-tarball.js +121 -0
- package/dist/core-runtime/readers/scan-tarball.test.js +283 -0
- package/dist/core-runtime/readers/scan-vault.js +34 -0
- package/dist/core-runtime/readers/scan-vault.test.js +81 -0
- package/dist/core-runtime/readers/types.js +42 -0
- package/dist/core-runtime/readers/types.test.js +94 -0
- package/dist/core-runtime/readers/viewpoint-collectors.js +229 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +1 -0
- package/dist/core-runtime/reconstruct/directive-validation.js +123 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +251 -0
- package/dist/core-runtime/reconstruct/record.js +198 -0
- package/dist/core-runtime/reconstruct/run.js +578 -0
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +356 -0
- package/dist/core-runtime/reconstruct/source-observations.js +62 -0
- package/dist/core-runtime/reconstruct/source-profiles.js +73 -0
- package/dist/core-runtime/release-channel/release-channel.js +90 -0
- package/dist/core-runtime/review/artifact-types.js +13 -0
- package/dist/core-runtime/review/citation-audit.js +204 -0
- package/dist/core-runtime/review/citation-audit.test.js +165 -0
- package/dist/core-runtime/review/controlled-lens-deliberation.js +125 -0
- package/dist/core-runtime/review/execution-plan-resolver.js +247 -0
- package/dist/core-runtime/review/execution-plan-resolver.test.js +243 -0
- package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +246 -0
- package/dist/core-runtime/review/execution-topology-resolver.js +401 -0
- package/dist/core-runtime/review/execution-topology-resolver.test.js +315 -0
- package/dist/core-runtime/review/failure-records.js +57 -0
- package/dist/core-runtime/review/inline-context-embedder.js +141 -0
- package/dist/core-runtime/review/inline-context-embedder.test.js +154 -0
- package/dist/core-runtime/review/issue-artifact-runtime.js +859 -0
- package/dist/core-runtime/review/legacy-mode-policy.js +88 -0
- package/dist/core-runtime/review/lens-completion-policy.js +17 -0
- package/dist/core-runtime/review/materializers-effort-persist.test.js +79 -0
- package/dist/core-runtime/review/materializers.js +963 -0
- package/dist/core-runtime/review/ontology-path-classifier.js +179 -0
- package/dist/core-runtime/review/ontology-path-classifier.test.js +216 -0
- package/dist/core-runtime/review/packet-boundary-policy.js +215 -0
- package/dist/core-runtime/review/packet-boundary-policy.test.js +107 -0
- package/dist/core-runtime/review/participating-lens-paths.js +61 -0
- package/dist/core-runtime/review/participating-lens-paths.test.js +73 -0
- package/dist/core-runtime/review/review-artifact-utils.js +287 -0
- package/dist/core-runtime/review/review-config-legacy-translate.js +244 -0
- package/dist/core-runtime/review/review-config-legacy-translate.test.js +161 -0
- package/dist/core-runtime/review/review-config-validator.js +289 -0
- package/dist/core-runtime/review/review-config-validator.test.js +236 -0
- package/dist/core-runtime/review/review-execution-profile.js +193 -0
- package/dist/core-runtime/review/review-execution-route.js +52 -0
- package/dist/core-runtime/review/review-progress-contract.js +123 -0
- package/dist/core-runtime/review/review-record-validation.js +251 -0
- package/dist/core-runtime/review/review-result-classification.js +379 -0
- package/dist/core-runtime/review/review-state-machine.js +39 -0
- package/dist/core-runtime/review/route-visibility.js +125 -0
- package/dist/core-runtime/review/shape-pipeline-audit.test.js +311 -0
- package/dist/core-runtime/review/shape-to-topology-id.js +117 -0
- package/dist/core-runtime/review/shape-to-topology-id.test.js +132 -0
- package/dist/core-runtime/review/topology-shape-derivation.js +155 -0
- package/dist/core-runtime/review/topology-shape-derivation.test.js +195 -0
- package/dist/core-runtime/scope-runtime/constants.js +12 -0
- package/dist/core-runtime/scope-runtime/constraint-pool.js +166 -0
- package/dist/core-runtime/scope-runtime/constraint-pool.test.js +674 -0
- package/dist/core-runtime/scope-runtime/domain-validation-log.js +135 -0
- package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +156 -0
- package/dist/core-runtime/scope-runtime/eval-persistence.js +65 -0
- package/dist/core-runtime/scope-runtime/eval-persistence.test.js +84 -0
- package/dist/core-runtime/scope-runtime/event-pipeline.js +64 -0
- package/dist/core-runtime/scope-runtime/event-pipeline.test.js +450 -0
- package/dist/core-runtime/scope-runtime/event-store.js +39 -0
- package/dist/core-runtime/scope-runtime/event-store.test.js +95 -0
- package/dist/core-runtime/scope-runtime/gate-guard.js +348 -0
- package/dist/core-runtime/scope-runtime/gate-guard.test.js +1047 -0
- package/dist/core-runtime/scope-runtime/hash.js +4 -0
- package/dist/core-runtime/scope-runtime/hash.test.js +33 -0
- package/dist/core-runtime/scope-runtime/id.js +4 -0
- package/dist/core-runtime/scope-runtime/id.test.js +17 -0
- package/dist/core-runtime/scope-runtime/reducer.js +297 -0
- package/dist/core-runtime/scope-runtime/reducer.test.js +759 -0
- package/dist/core-runtime/scope-runtime/scope-manager.js +161 -0
- package/dist/core-runtime/scope-runtime/state-machine.js +309 -0
- package/dist/core-runtime/scope-runtime/state-machine.test.js +704 -0
- package/dist/core-runtime/scope-runtime/types.js +116 -0
- package/dist/core-runtime/scope-runtime/types.test.js +69 -0
- package/dist/core-runtime/target-material-kind.js +256 -0
- package/dist/core-runtime/translate/render-for-user.js +169 -0
- package/dist/core-runtime/translate/render-for-user.test.js +122 -0
- package/dist/mcp/server.js +1011 -0
- package/dist/mcp/tool-schemas.js +93 -0
- package/dist/providers/capability-contract.js +1 -0
- package/package.json +68 -0
- package/settings.example.json +33 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background task (learn/govern/promote) LLM call wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Canonical provider resolution:
|
|
5
|
+
* 1. Caller-explicit: callLlm(..., { provider }) — one provider only.
|
|
6
|
+
* 2. `llm.auth=oauth + llm.provider=openai` — Codex worker.
|
|
7
|
+
* 3. `llm.auth=api_key` — OpenAI / Anthropic / Grok API key from env.
|
|
8
|
+
* 4. `llm.auth=local + llm.provider=lmstudio` — local OpenAI-style endpoint.
|
|
9
|
+
*
|
|
10
|
+
* Priority 0 (special): ONTO_LLM_MOCK=1 → in-process mock (test only)
|
|
11
|
+
*
|
|
12
|
+
* Mock provider:
|
|
13
|
+
* When ONTO_LLM_MOCK=1 is set, callLlm() routes to an in-process mock that
|
|
14
|
+
* pattern-matches the system prompt against known Phase 3 prompts (panel
|
|
15
|
+
* review, judgment audit, insight reclassify, domain doc) and returns
|
|
16
|
+
* deterministic JSON. This unblocks E2E tests that need to exercise the
|
|
17
|
+
* full LLM call path without real API credentials. NEVER ship with this
|
|
18
|
+
* env var set in production — there's no real reasoning happening.
|
|
19
|
+
*
|
|
20
|
+
* Runtime config must reach this module through the canonical `llm` switcher
|
|
21
|
+
* or an explicit call-site override. Missing provider/model/credentials fail
|
|
22
|
+
* immediately.
|
|
23
|
+
*/
|
|
24
|
+
import crypto from "node:crypto";
|
|
25
|
+
import fs from "node:fs";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import os from "node:os";
|
|
28
|
+
import { loadCoreLensRegistry } from "../../discovery/lens-registry.js";
|
|
29
|
+
import { DEFAULT_GROK_BASE_URL, DEFAULT_LMSTUDIO_BASE_URL, normalizeLlmModelSwitcher, } from "../../llm/model-switcher.js";
|
|
30
|
+
/**
|
|
31
|
+
* Bridge: OntoConfig + CLI overrides → Partial<LlmCallConfig> that callLlm consumes.
|
|
32
|
+
*
|
|
33
|
+
* Callers (learning/promote panel-reviewer, promote-executor, judgment-auditor,
|
|
34
|
+
* insight-reclassifier, extractor, semantic-classifier) should:
|
|
35
|
+
*
|
|
36
|
+
* const partial = resolveLearningProviderConfig({ config: ontoConfig, cliOverrides });
|
|
37
|
+
* const result = await callLlm(system, user, { ...partial, max_tokens: 2048 });
|
|
38
|
+
*
|
|
39
|
+
* This replaces the pattern of callers building Partial<LlmCallConfig> ad-hoc, and is
|
|
40
|
+
* the canonical seat where OntoConfig translates to provider resolution input.
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
export function resolveLearningProviderConfig(args) {
|
|
44
|
+
const config = args.config ?? {};
|
|
45
|
+
const cli = args.cliOverrides ?? {};
|
|
46
|
+
const selection = normalizeLlmModelSwitcher(config.llm);
|
|
47
|
+
const provider = cli.provider ?? selection?.provider;
|
|
48
|
+
const model_id = cli.model ?? selection?.model_id;
|
|
49
|
+
const envBaseUrl = provider === "grok"
|
|
50
|
+
? process.env.GROK_BASE_URL ?? process.env.XAI_BASE_URL
|
|
51
|
+
: provider === "lmstudio"
|
|
52
|
+
? process.env.LMSTUDIO_BASE_URL
|
|
53
|
+
: undefined;
|
|
54
|
+
const base_url = cli.base_url ?? envBaseUrl ?? selection?.base_url;
|
|
55
|
+
const reasoning_effort = cli.reasoning_effort ?? selection?.reasoning_effort;
|
|
56
|
+
const service_tier = selection?.provider === "codex" ? selection.service_tier : undefined;
|
|
57
|
+
const api_key_env = selection?.api_key_env;
|
|
58
|
+
const models_per_provider = {};
|
|
59
|
+
if (provider && model_id)
|
|
60
|
+
models_per_provider[provider] = model_id;
|
|
61
|
+
const out = {};
|
|
62
|
+
if (provider)
|
|
63
|
+
out.provider = provider;
|
|
64
|
+
if (model_id)
|
|
65
|
+
out.model_id = model_id;
|
|
66
|
+
if (base_url)
|
|
67
|
+
out.base_url = base_url;
|
|
68
|
+
if (reasoning_effort)
|
|
69
|
+
out.reasoning_effort = reasoning_effort;
|
|
70
|
+
if (service_tier)
|
|
71
|
+
out.service_tier = service_tier;
|
|
72
|
+
if (api_key_env)
|
|
73
|
+
out.api_key_env = api_key_env;
|
|
74
|
+
if (Object.keys(models_per_provider).length > 0) {
|
|
75
|
+
out.models_per_provider = models_per_provider;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
// Phase 3 production found 30s too tight for large audit batches (37 items
|
|
80
|
+
// could time out then SDK-retry for 90s total). 120s is generous
|
|
81
|
+
// enough for ~50-item single-batch audits while still failing fast on real
|
|
82
|
+
// network problems.
|
|
83
|
+
const DEFAULT_TIMEOUT_MS = Number(process.env.ONTO_LLM_TIMEOUT_MS) || 120_000;
|
|
84
|
+
// SDK auto-retry hides failures behind a long stall. We surface failures
|
|
85
|
+
// faster (1 retry instead of the default 2) so operators see provider errors
|
|
86
|
+
// within ~2× timeout instead of ~3×.
|
|
87
|
+
const DEFAULT_MAX_RETRIES = 1;
|
|
88
|
+
/**
|
|
89
|
+
* Model-call observability — emits STDERR logs for each LLM API call, covering
|
|
90
|
+
* (a) pre-call model_id + provider + max_tokens, (b) post-call usage on success,
|
|
91
|
+
* (c) full SDK error fields (status / error.type / error.message / request_id)
|
|
92
|
+
* on failure. Silent "Connection error." wrapping by review runner no longer
|
|
93
|
+
* hides model-not-found / auth / quota / network distinctions.
|
|
94
|
+
*/
|
|
95
|
+
function emitModelCallLog(line) {
|
|
96
|
+
process.stderr.write(`[model-call] ${line}\n`);
|
|
97
|
+
}
|
|
98
|
+
function readCodexAuthState() {
|
|
99
|
+
const codexAuthPath = path.join(os.homedir(), ".codex", "auth.json");
|
|
100
|
+
if (!fs.existsSync(codexAuthPath)) {
|
|
101
|
+
return { chatgptOAuth: false, openaiApiKey: null };
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const auth = JSON.parse(fs.readFileSync(codexAuthPath, "utf8"));
|
|
105
|
+
const oauth = auth.auth_mode === "chatgpt" ||
|
|
106
|
+
(auth.tokens && typeof auth.tokens.access_token === "string");
|
|
107
|
+
const openaiKey = typeof auth.OPENAI_API_KEY === "string" && auth.OPENAI_API_KEY.length > 0
|
|
108
|
+
? auth.OPENAI_API_KEY
|
|
109
|
+
: null;
|
|
110
|
+
return { chatgptOAuth: Boolean(oauth), openaiApiKey: openaiKey };
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return { chatgptOAuth: false, openaiApiKey: null };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function readEnvApiKey(envNames) {
|
|
117
|
+
for (const envName of envNames) {
|
|
118
|
+
const value = process.env[envName];
|
|
119
|
+
if (typeof value === "string" && value.length > 0)
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function resolveProvider(preferred, configBaseUrl, apiKeyEnv) {
|
|
125
|
+
if (preferred === undefined) {
|
|
126
|
+
throw new Error(missingProviderSelectionError());
|
|
127
|
+
}
|
|
128
|
+
if (preferred === "anthropic") {
|
|
129
|
+
const apiKey = readEnvApiKey(apiKeyEnv ? [apiKeyEnv] : ["ANTHROPIC_API_KEY"]);
|
|
130
|
+
if (apiKey) {
|
|
131
|
+
return { provider: "anthropic", apiKey };
|
|
132
|
+
}
|
|
133
|
+
throw new Error(explicitProviderMissingCredentialError("anthropic"));
|
|
134
|
+
}
|
|
135
|
+
if (preferred === "openai") {
|
|
136
|
+
const envKey = readEnvApiKey(apiKeyEnv ? [apiKeyEnv] : ["OPENAI_API_KEY"]);
|
|
137
|
+
if (envKey) {
|
|
138
|
+
return { provider: "openai", apiKey: envKey };
|
|
139
|
+
}
|
|
140
|
+
const codexAuth = readCodexAuthState();
|
|
141
|
+
if (codexAuth.openaiApiKey) {
|
|
142
|
+
return { provider: "openai", apiKey: codexAuth.openaiApiKey };
|
|
143
|
+
}
|
|
144
|
+
throw new Error(explicitProviderMissingCredentialError("openai"));
|
|
145
|
+
}
|
|
146
|
+
if (preferred === "grok") {
|
|
147
|
+
const apiKey = readEnvApiKey(apiKeyEnv ? [apiKeyEnv] : ["XAI_API_KEY", "GROK_API_KEY"]);
|
|
148
|
+
if (apiKey) {
|
|
149
|
+
return {
|
|
150
|
+
provider: "grok",
|
|
151
|
+
apiKey,
|
|
152
|
+
baseUrl: configBaseUrl ?? DEFAULT_GROK_BASE_URL,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
throw new Error(explicitProviderMissingCredentialError("grok"));
|
|
156
|
+
}
|
|
157
|
+
if (preferred === "lmstudio") {
|
|
158
|
+
return {
|
|
159
|
+
provider: "lmstudio",
|
|
160
|
+
apiKey: "lmstudio-local",
|
|
161
|
+
baseUrl: configBaseUrl ?? process.env.LMSTUDIO_BASE_URL ?? DEFAULT_LMSTUDIO_BASE_URL,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
provider: "codex",
|
|
166
|
+
apiKey: "codex-oauth",
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function explicitProviderMissingCredentialError(provider) {
|
|
170
|
+
const envVar = provider === "anthropic"
|
|
171
|
+
? "ANTHROPIC_API_KEY"
|
|
172
|
+
: provider === "openai"
|
|
173
|
+
? "OPENAI_API_KEY"
|
|
174
|
+
: "XAI_API_KEY or GROK_API_KEY";
|
|
175
|
+
return [
|
|
176
|
+
`llm.provider=${provider} 명시적으로 선택되었으나 ${envVar}가 환경변수에 없습니다.`,
|
|
177
|
+
...(provider === "openai"
|
|
178
|
+
? ["(~/.codex/auth.json의 OPENAI_API_KEY 필드도 비어 있거나 없음)"]
|
|
179
|
+
: []),
|
|
180
|
+
`명시적 provider override를 사용하려면 ${envVar}를 export하세요.`,
|
|
181
|
+
"또는 .onto/settings.json 의 llm block 을 현재 credential에 맞게 수정하세요.",
|
|
182
|
+
].join("\n");
|
|
183
|
+
}
|
|
184
|
+
function missingProviderSelectionError() {
|
|
185
|
+
return [
|
|
186
|
+
"LLM provider가 지정되지 않았습니다.",
|
|
187
|
+
"`.onto/settings.json`에 `llm` 블록을 추가하거나 호출부에서 provider를 명시하세요:",
|
|
188
|
+
" llm:",
|
|
189
|
+
" auth: oauth | api_key | local",
|
|
190
|
+
" provider: openai | anthropic | grok | lmstudio",
|
|
191
|
+
" model: <model-id>",
|
|
192
|
+
].join("\n");
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Construct a fail-fast error for api-key providers when no model is specified.
|
|
196
|
+
* Used by anthropic / openai / grok / lmstudio dispatch branches. codex is exempt because
|
|
197
|
+
* the codex CLI picks its own default when `-m` is omitted.
|
|
198
|
+
*
|
|
199
|
+
* Hardcoded DEFAULT_ANTHROPIC_MODEL / DEFAULT_OPENAI_MODEL constants were removed
|
|
200
|
+
* from this module (2026-04-15): model choice is a user decision (cost / quality /
|
|
201
|
+
* account constraints) and should not be hardcoded in library code where it can
|
|
202
|
+
* go stale or mismatch account permissions.
|
|
203
|
+
*/
|
|
204
|
+
function missingModelError(provider) {
|
|
205
|
+
const providerField = provider;
|
|
206
|
+
return new Error([
|
|
207
|
+
`provider=${provider} 경로는 model 지정이 필요합니다. 하드코딩된 기본 모델은 제거되었습니다.`,
|
|
208
|
+
"다음 중 한 가지로 설정하세요:",
|
|
209
|
+
" 1. .onto/settings.json 의 `llm.model: <model-id>`",
|
|
210
|
+
" 3. 호출부에서 LlmCallConfig.model_id 인자 전달 (런타임 override)",
|
|
211
|
+
"(codex provider는 model 미지정 시 codex CLI가 자체 기본값을 사용하므로 이 메시지의 대상이 아닙니다.)",
|
|
212
|
+
].join("\n"));
|
|
213
|
+
}
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
// Anthropic call
|
|
216
|
+
// ---------------------------------------------------------------------------
|
|
217
|
+
async function callAnthropic(systemPrompt, userPrompt, apiKey, modelId, maxTokens) {
|
|
218
|
+
const { default: Anthropic } = await import("@anthropic-ai/sdk");
|
|
219
|
+
const client = new Anthropic({
|
|
220
|
+
apiKey,
|
|
221
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
222
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
223
|
+
});
|
|
224
|
+
emitModelCallLog(`anthropic call: model="${modelId}" max_tokens=${maxTokens}`);
|
|
225
|
+
let response;
|
|
226
|
+
try {
|
|
227
|
+
response = await client.messages.create({
|
|
228
|
+
model: modelId,
|
|
229
|
+
max_tokens: maxTokens,
|
|
230
|
+
system: systemPrompt,
|
|
231
|
+
messages: [{ role: "user", content: userPrompt }],
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
const e = err;
|
|
236
|
+
emitModelCallLog(`anthropic call FAILED: model="${modelId}" status=${e.status ?? "?"} type=${e.error?.type ?? e.name ?? "?"} message="${e.error?.message ?? e.message ?? String(err)}" request_id=${e.request_id ?? "?"}`);
|
|
237
|
+
throw err;
|
|
238
|
+
}
|
|
239
|
+
emitModelCallLog(`anthropic success: model_id=${response.model ?? modelId} input_tokens=${response.usage.input_tokens} output_tokens=${response.usage.output_tokens}`);
|
|
240
|
+
const text = response.content
|
|
241
|
+
.filter((block) => block.type === "text")
|
|
242
|
+
.map((block) => ("text" in block ? block.text : ""))
|
|
243
|
+
.join("\n");
|
|
244
|
+
return {
|
|
245
|
+
text,
|
|
246
|
+
input_tokens: response.usage.input_tokens,
|
|
247
|
+
output_tokens: response.usage.output_tokens,
|
|
248
|
+
model_id: modelId,
|
|
249
|
+
effective_base_url: "https://api.anthropic.com",
|
|
250
|
+
declared_billing_mode: "per_token",
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// OpenAI call
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
async function callOpenAI(systemPrompt, userPrompt, apiKey, modelId, maxTokens, baseUrl, providerLabel = "openai") {
|
|
257
|
+
const { default: OpenAI } = await import("openai");
|
|
258
|
+
const client = new OpenAI({
|
|
259
|
+
apiKey,
|
|
260
|
+
baseURL: baseUrl,
|
|
261
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
262
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
263
|
+
});
|
|
264
|
+
emitModelCallLog(`${providerLabel} call: model="${modelId}" max_tokens=${maxTokens}${baseUrl ? ` base_url=${baseUrl}` : ""}`);
|
|
265
|
+
let response;
|
|
266
|
+
try {
|
|
267
|
+
response = await client.chat.completions.create({
|
|
268
|
+
model: modelId,
|
|
269
|
+
max_tokens: maxTokens,
|
|
270
|
+
messages: [
|
|
271
|
+
{ role: "system", content: systemPrompt },
|
|
272
|
+
{ role: "user", content: userPrompt },
|
|
273
|
+
],
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
const e = err;
|
|
278
|
+
emitModelCallLog(`${providerLabel} call FAILED: model="${modelId}" status=${e.status ?? "?"} type=${e.error?.type ?? e.name ?? "?"} message="${e.error?.message ?? e.message ?? String(err)}" request_id=${e.request_id ?? "?"}`);
|
|
279
|
+
throw err;
|
|
280
|
+
}
|
|
281
|
+
emitModelCallLog(`${providerLabel} success: model_id=${response.model ?? modelId} input_tokens=${response.usage?.prompt_tokens ?? 0} output_tokens=${response.usage?.completion_tokens ?? 0}`);
|
|
282
|
+
const text = response.choices[0]?.message?.content ?? "";
|
|
283
|
+
const defaultBase = providerLabel === "grok"
|
|
284
|
+
? DEFAULT_GROK_BASE_URL
|
|
285
|
+
: providerLabel === "lmstudio"
|
|
286
|
+
? DEFAULT_LMSTUDIO_BASE_URL
|
|
287
|
+
: "https://api.openai.com/v1";
|
|
288
|
+
return {
|
|
289
|
+
text,
|
|
290
|
+
input_tokens: response.usage?.prompt_tokens ?? 0,
|
|
291
|
+
output_tokens: response.usage?.completion_tokens ?? 0,
|
|
292
|
+
model_id: modelId,
|
|
293
|
+
effective_base_url: baseUrl ?? defaultBase,
|
|
294
|
+
declared_billing_mode: providerLabel === "lmstudio" ? "local" : "per_token",
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// codex CLI call (OAuth subscription path)
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
/**
|
|
301
|
+
* Invoke `codex exec --ephemeral -` as a Codex worker for a single-turn
|
|
302
|
+
* prompt → text response. Uses the host's codex CLI authentication
|
|
303
|
+
* (chatgpt OAuth via ~/.codex/auth.json), which routes through chatgpt.com's
|
|
304
|
+
* backend — cannot be reached via the OpenAI SDK.
|
|
305
|
+
*
|
|
306
|
+
* --ephemeral keeps this learning call from persisting a session file
|
|
307
|
+
* alongside review sessions. --skip-git-repo-check lets learning run
|
|
308
|
+
* from non-repo cwd. No -C/-s/-o: this is single-turn, no agentic scaffold.
|
|
309
|
+
*/
|
|
310
|
+
async function callCodexCli(systemPrompt, userPrompt, modelId, reasoningEffort, serviceTier) {
|
|
311
|
+
const { spawn } = await import("node:child_process");
|
|
312
|
+
const args = ["exec", "--skip-git-repo-check", "--ephemeral"];
|
|
313
|
+
if (modelId)
|
|
314
|
+
args.push("-m", modelId);
|
|
315
|
+
if (reasoningEffort)
|
|
316
|
+
args.push("-c", `model_reasoning_effort="${reasoningEffort}"`);
|
|
317
|
+
if (serviceTier)
|
|
318
|
+
args.push("-c", `service_tier="${serviceTier}"`);
|
|
319
|
+
args.push("-");
|
|
320
|
+
const combinedPrompt = `${systemPrompt}\n\n---\n\n${userPrompt}`;
|
|
321
|
+
emitModelCallLog(`codex call: model="${modelId ?? "(codex default)"}" effort="${reasoningEffort ?? "(unset)"}" service_tier="${serviceTier ?? "(unset)"}" timeout_ms=${DEFAULT_TIMEOUT_MS}`);
|
|
322
|
+
const child = spawn("codex", args, {
|
|
323
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
324
|
+
});
|
|
325
|
+
let stdout = "";
|
|
326
|
+
let stderr = "";
|
|
327
|
+
let timedOut = false;
|
|
328
|
+
child.stdout.on("data", (chunk) => {
|
|
329
|
+
stdout += String(chunk);
|
|
330
|
+
});
|
|
331
|
+
child.stderr.on("data", (chunk) => {
|
|
332
|
+
stderr += String(chunk);
|
|
333
|
+
});
|
|
334
|
+
child.stdin.write(combinedPrompt);
|
|
335
|
+
child.stdin.end();
|
|
336
|
+
const timeoutHandle = setTimeout(() => {
|
|
337
|
+
timedOut = true;
|
|
338
|
+
child.kill("SIGTERM");
|
|
339
|
+
}, DEFAULT_TIMEOUT_MS);
|
|
340
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
341
|
+
child.on("error", (err) => {
|
|
342
|
+
clearTimeout(timeoutHandle);
|
|
343
|
+
if (err.code === "ENOENT") {
|
|
344
|
+
reject(new Error("codex CLI not found on PATH. Install codex to use the OAuth subscription path: https://github.com/openai/codex"));
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
reject(err);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
child.on("close", (code) => {
|
|
351
|
+
clearTimeout(timeoutHandle);
|
|
352
|
+
resolve(code ?? 1);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
if (timedOut) {
|
|
356
|
+
emitModelCallLog(`codex call FAILED: model="${modelId ?? "(codex default)"}" reason=timeout timeout_ms=${DEFAULT_TIMEOUT_MS}`);
|
|
357
|
+
throw new Error(`codex CLI call timed out after ${DEFAULT_TIMEOUT_MS}ms`);
|
|
358
|
+
}
|
|
359
|
+
if (exitCode !== 0) {
|
|
360
|
+
const combined = [stderr.trim(), stdout.trim()]
|
|
361
|
+
.filter((m) => m.length > 0)
|
|
362
|
+
.join("\n");
|
|
363
|
+
emitModelCallLog(`codex call FAILED: model="${modelId ?? "(codex default)"}" exit_code=${exitCode} message="${combined.slice(0, 200).replace(/\n/g, " ")}"`);
|
|
364
|
+
// A1: chatgpt account model allowlist rejection — augment with actionable hint.
|
|
365
|
+
// codex emits errors like:
|
|
366
|
+
// "The 'gpt-4o-mini' model is not supported when using Codex with a ChatGPT account."
|
|
367
|
+
// Surface a fix path so users don't have to decode the upstream message.
|
|
368
|
+
if (combined.includes("is not supported when using Codex with a ChatGPT account") ||
|
|
369
|
+
combined.includes("not supported when using Codex")) {
|
|
370
|
+
const requested = modelId ?? "(codex default)";
|
|
371
|
+
throw new Error([
|
|
372
|
+
combined,
|
|
373
|
+
"",
|
|
374
|
+
`지정된 모델 "${requested}"이 현재 ChatGPT 계정의 codex allowlist에 없습니다.`,
|
|
375
|
+
"다음 중 한 가지로 해결하세요:",
|
|
376
|
+
" 1. .onto/settings.json 의 llm.model 값을 현재 계정에서 허용되는 모델로 변경",
|
|
377
|
+
" 2. 터미널에서 `codex` 를 직접 실행해 현재 계정에서 선택 가능한 모델 확인",
|
|
378
|
+
" 3. `codex login` 으로 API-key 모드로 전환 (per-token 과금, 더 넓은 모델 범위)",
|
|
379
|
+
].join("\n"));
|
|
380
|
+
}
|
|
381
|
+
throw new Error(combined.length > 0 ? combined : `codex CLI exited with code ${exitCode}`);
|
|
382
|
+
}
|
|
383
|
+
const text = stdout.trim();
|
|
384
|
+
// codex exec does not return usage metadata in stdout; estimate by char count.
|
|
385
|
+
// LlmCallResult carries these as approximate; audit may flag via declared_billing_mode=subscription.
|
|
386
|
+
const estimateTokens = (s) => Math.max(1, Math.ceil(s.length / 4));
|
|
387
|
+
const in_tokens = estimateTokens(combinedPrompt);
|
|
388
|
+
const out_tokens = estimateTokens(text);
|
|
389
|
+
emitModelCallLog(`codex success: model_id=${modelId ?? "codex-default"} input_tokens~=${in_tokens} output_tokens~=${out_tokens}`);
|
|
390
|
+
return {
|
|
391
|
+
text,
|
|
392
|
+
input_tokens: in_tokens,
|
|
393
|
+
output_tokens: out_tokens,
|
|
394
|
+
model_id: modelId ?? "codex-default",
|
|
395
|
+
effective_base_url: "codex-cli://oauth",
|
|
396
|
+
declared_billing_mode: "subscription",
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
// ---------------------------------------------------------------------------
|
|
400
|
+
// Plan-aware dispatch (Review Recovery PR-1)
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
/**
|
|
403
|
+
* Dispatch an LLM call using a pre-resolved ExecutionPlan shape. The plan
|
|
404
|
+
* carries `provider_identity`, `model_id`, and `base_url`; credentials are
|
|
405
|
+
* still read from env (ANTHROPIC_API_KEY / OPENAI_API_KEY / XAI_API_KEY)
|
|
406
|
+
* since secrets never enter the plan by design.
|
|
407
|
+
*
|
|
408
|
+
* Why credentials stay in env:
|
|
409
|
+
* The plan is written to session artifacts (`execution-plan.yaml`) for
|
|
410
|
+
* reproducibility and audit. Including API keys would leak them; env-sourced
|
|
411
|
+
* credentials keep the plan portable while the runtime still has enough to
|
|
412
|
+
* authenticate.
|
|
413
|
+
*/
|
|
414
|
+
async function dispatchByPlan(systemPrompt, userPrompt, config) {
|
|
415
|
+
const { plan } = config;
|
|
416
|
+
const maxTokens = config.max_tokens ?? 1024;
|
|
417
|
+
if (plan.provider_identity === "mock") {
|
|
418
|
+
return callMockProvider(systemPrompt, userPrompt);
|
|
419
|
+
}
|
|
420
|
+
if (plan.provider_identity === "claude-code") {
|
|
421
|
+
throw new Error("callLlm: ExecutionPlan.provider_identity=claude-code is orchestrator-only; background LLM calls cannot dispatch through the host nested spawn path.");
|
|
422
|
+
}
|
|
423
|
+
if (plan.provider_identity === "codex") {
|
|
424
|
+
const modelId = config.model_id ?? plan.model_id ?? config.models_per_provider?.codex;
|
|
425
|
+
return callCodexCli(systemPrompt, userPrompt, modelId, config.reasoning_effort, config.service_tier);
|
|
426
|
+
}
|
|
427
|
+
if (plan.provider_identity === "anthropic") {
|
|
428
|
+
const apiKey = readEnvApiKey(config.api_key_env ? [config.api_key_env] : ["ANTHROPIC_API_KEY"]);
|
|
429
|
+
if (!apiKey) {
|
|
430
|
+
throw new Error(explicitProviderMissingCredentialError("anthropic"));
|
|
431
|
+
}
|
|
432
|
+
const modelId = config.model_id ?? plan.model_id ?? config.models_per_provider?.anthropic;
|
|
433
|
+
if (!modelId)
|
|
434
|
+
throw missingModelError("anthropic");
|
|
435
|
+
return callAnthropic(systemPrompt, userPrompt, apiKey, modelId, maxTokens);
|
|
436
|
+
}
|
|
437
|
+
if (plan.provider_identity === "openai") {
|
|
438
|
+
const envKey = readEnvApiKey(config.api_key_env ? [config.api_key_env] : ["OPENAI_API_KEY"]);
|
|
439
|
+
const codexAuth = readCodexAuthState();
|
|
440
|
+
const apiKey = envKey ?? codexAuth.openaiApiKey ?? null;
|
|
441
|
+
if (!apiKey) {
|
|
442
|
+
throw new Error(explicitProviderMissingCredentialError("openai"));
|
|
443
|
+
}
|
|
444
|
+
const modelId = config.model_id ?? plan.model_id ?? config.models_per_provider?.openai;
|
|
445
|
+
if (!modelId)
|
|
446
|
+
throw missingModelError("openai");
|
|
447
|
+
return callOpenAI(systemPrompt, userPrompt, apiKey, modelId, maxTokens);
|
|
448
|
+
}
|
|
449
|
+
if (plan.provider_identity === "grok") {
|
|
450
|
+
const apiKey = readEnvApiKey(config.api_key_env ? [config.api_key_env] : ["XAI_API_KEY", "GROK_API_KEY"]);
|
|
451
|
+
if (!apiKey) {
|
|
452
|
+
throw new Error(explicitProviderMissingCredentialError("grok"));
|
|
453
|
+
}
|
|
454
|
+
const modelId = config.model_id ?? plan.model_id ?? config.models_per_provider?.grok;
|
|
455
|
+
if (!modelId)
|
|
456
|
+
throw missingModelError("grok");
|
|
457
|
+
return callOpenAI(systemPrompt, userPrompt, apiKey, modelId, maxTokens, plan.base_url ?? config.base_url ?? DEFAULT_GROK_BASE_URL, "grok");
|
|
458
|
+
}
|
|
459
|
+
if (plan.provider_identity === "lmstudio") {
|
|
460
|
+
const modelId = config.model_id ?? plan.model_id ?? config.models_per_provider?.lmstudio;
|
|
461
|
+
if (!modelId)
|
|
462
|
+
throw missingModelError("lmstudio");
|
|
463
|
+
return callOpenAI(systemPrompt, userPrompt, "lmstudio-local", modelId, maxTokens, plan.base_url ?? config.base_url ?? process.env.LMSTUDIO_BASE_URL ?? DEFAULT_LMSTUDIO_BASE_URL, "lmstudio");
|
|
464
|
+
}
|
|
465
|
+
throw new Error(`dispatchByPlan: unexpected provider_identity=${String(plan.provider_identity)}`);
|
|
466
|
+
}
|
|
467
|
+
// ---------------------------------------------------------------------------
|
|
468
|
+
// Public API
|
|
469
|
+
// ---------------------------------------------------------------------------
|
|
470
|
+
/** Call an LLM through the explicitly selected provider path. */
|
|
471
|
+
export async function callLlm(systemPrompt, userPrompt, config) {
|
|
472
|
+
// Test-only mock provider — gated by ONTO_LLM_MOCK=1.
|
|
473
|
+
if (process.env.ONTO_LLM_MOCK === "1") {
|
|
474
|
+
return callMockProvider(systemPrompt, userPrompt);
|
|
475
|
+
}
|
|
476
|
+
if (config?.plan) {
|
|
477
|
+
return dispatchByPlan(systemPrompt, userPrompt, config);
|
|
478
|
+
}
|
|
479
|
+
if (config?.provider === "codex") {
|
|
480
|
+
return callCodexCli(systemPrompt, userPrompt, config.model_id ?? config.models_per_provider?.codex, config.reasoning_effort, config.service_tier);
|
|
481
|
+
}
|
|
482
|
+
if (config?.provider === "grok") {
|
|
483
|
+
const modelId = config.model_id ?? config.models_per_provider?.grok;
|
|
484
|
+
if (!modelId)
|
|
485
|
+
throw missingModelError("grok");
|
|
486
|
+
const apiKey = readEnvApiKey(config.api_key_env ? [config.api_key_env] : ["XAI_API_KEY", "GROK_API_KEY"]);
|
|
487
|
+
if (!apiKey)
|
|
488
|
+
throw new Error(explicitProviderMissingCredentialError("grok"));
|
|
489
|
+
const maxTokens = config.max_tokens ?? 1024;
|
|
490
|
+
return callOpenAI(systemPrompt, userPrompt, apiKey, modelId, maxTokens, config.base_url ?? DEFAULT_GROK_BASE_URL, "grok");
|
|
491
|
+
}
|
|
492
|
+
if (config?.provider === "lmstudio") {
|
|
493
|
+
const modelId = config.model_id ?? config.models_per_provider?.lmstudio;
|
|
494
|
+
if (!modelId)
|
|
495
|
+
throw missingModelError("lmstudio");
|
|
496
|
+
const maxTokens = config.max_tokens ?? 1024;
|
|
497
|
+
return callOpenAI(systemPrompt, userPrompt, "lmstudio-local", modelId, maxTokens, config.base_url ?? process.env.LMSTUDIO_BASE_URL ?? DEFAULT_LMSTUDIO_BASE_URL, "lmstudio");
|
|
498
|
+
}
|
|
499
|
+
const resolved = resolveProvider(config?.provider, config?.base_url, config?.api_key_env);
|
|
500
|
+
const maxTokens = config?.max_tokens ?? 1024;
|
|
501
|
+
const perProviderModel = config?.models_per_provider?.[resolved.provider];
|
|
502
|
+
switch (resolved.provider) {
|
|
503
|
+
case "codex": {
|
|
504
|
+
const modelId = config?.model_id ?? perProviderModel;
|
|
505
|
+
return callCodexCli(systemPrompt, userPrompt, modelId, config?.reasoning_effort, config?.service_tier);
|
|
506
|
+
}
|
|
507
|
+
case "anthropic": {
|
|
508
|
+
const modelId = config?.model_id ?? perProviderModel;
|
|
509
|
+
if (!modelId)
|
|
510
|
+
throw missingModelError("anthropic");
|
|
511
|
+
return callAnthropic(systemPrompt, userPrompt, resolved.apiKey, modelId, maxTokens);
|
|
512
|
+
}
|
|
513
|
+
case "openai": {
|
|
514
|
+
const modelId = config?.model_id ?? perProviderModel;
|
|
515
|
+
if (!modelId)
|
|
516
|
+
throw missingModelError("openai");
|
|
517
|
+
return callOpenAI(systemPrompt, userPrompt, resolved.apiKey, modelId, maxTokens);
|
|
518
|
+
}
|
|
519
|
+
case "grok": {
|
|
520
|
+
const modelId = config?.model_id ?? perProviderModel;
|
|
521
|
+
if (!modelId)
|
|
522
|
+
throw missingModelError("grok");
|
|
523
|
+
return callOpenAI(systemPrompt, userPrompt, resolved.apiKey, modelId, maxTokens, resolved.baseUrl ?? DEFAULT_GROK_BASE_URL, "grok");
|
|
524
|
+
}
|
|
525
|
+
case "lmstudio": {
|
|
526
|
+
const modelId = config?.model_id ?? perProviderModel;
|
|
527
|
+
if (!modelId)
|
|
528
|
+
throw missingModelError("lmstudio");
|
|
529
|
+
return callOpenAI(systemPrompt, userPrompt, resolved.apiKey, modelId, maxTokens, resolved.baseUrl ?? DEFAULT_LMSTUDIO_BASE_URL, "lmstudio");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
// ---------------------------------------------------------------------------
|
|
534
|
+
// Mock provider — test only, gated by ONTO_LLM_MOCK=1
|
|
535
|
+
// ---------------------------------------------------------------------------
|
|
536
|
+
const MOCK_MODEL_ID = "mock-llm-deterministic";
|
|
537
|
+
/**
|
|
538
|
+
* Pattern-match the system prompt against known Phase 3 prompt headers and
|
|
539
|
+
* return a deterministic JSON response shaped to satisfy each module's
|
|
540
|
+
* validator. The matching is intentionally string-prefix based — fragile by
|
|
541
|
+
* design so a prompt change forces a test update rather than silently
|
|
542
|
+
* accepting drift.
|
|
543
|
+
*
|
|
544
|
+
* Coverage:
|
|
545
|
+
* - Panel reviewer (criteria 1~5)
|
|
546
|
+
* - Judgment auditor (audit outcomes)
|
|
547
|
+
* - Insight reclassifier (proposed_role)
|
|
548
|
+
* - Domain doc proposer Phase B (reflection_form + content)
|
|
549
|
+
* - Cross-agent dedup (criterion 6, same-principle test)
|
|
550
|
+
* - Phase 2 semantic classifier (decision)
|
|
551
|
+
*
|
|
552
|
+
* N-1 fix: previously, unknown prompts fell through to a generic "ok" string,
|
|
553
|
+
* which made prompt drift a downstream parse failure instead of an immediate
|
|
554
|
+
* mock-dispatch failure. Now unknown prompts raise an error so test breakage
|
|
555
|
+
* surfaces at the mock layer with the actual prompt prefix in the message.
|
|
556
|
+
*/
|
|
557
|
+
function callMockProvider(systemPrompt, userPrompt) {
|
|
558
|
+
let text;
|
|
559
|
+
if (systemPrompt.startsWith("You are reviewing promotion candidates")) {
|
|
560
|
+
// Panel reviewer — extract candidate_ids from the user prompt and return
|
|
561
|
+
// one item per id with all-yes criteria + promote verdict.
|
|
562
|
+
const candidateIds = extractCandidateIds(userPrompt);
|
|
563
|
+
text = JSON.stringify({
|
|
564
|
+
items: candidateIds.map((id) => ({
|
|
565
|
+
candidate_id: id,
|
|
566
|
+
verdict: "promote",
|
|
567
|
+
criteria: [1, 2, 3, 4, 5].map((c) => ({
|
|
568
|
+
criterion: c,
|
|
569
|
+
judgment: "yes",
|
|
570
|
+
reasoning: `mock reasoning for criterion ${c}`,
|
|
571
|
+
})),
|
|
572
|
+
axis_tag_recommendation: "retain",
|
|
573
|
+
axis_tag_note: "mock — keep current tags",
|
|
574
|
+
contradiction_resolution: "n/a",
|
|
575
|
+
reason: "mock — all criteria passed deterministically",
|
|
576
|
+
})),
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
else if (systemPrompt.startsWith("You are re-verifying previously promoted [judgment]-type learnings")) {
|
|
580
|
+
// Judgment auditor — extract item count and return retain for each.
|
|
581
|
+
const count = extractJudgmentItemCount(userPrompt);
|
|
582
|
+
text = JSON.stringify({
|
|
583
|
+
outcomes: Array.from({ length: count }, (_, i) => ({
|
|
584
|
+
item_index: i,
|
|
585
|
+
decision: "retain",
|
|
586
|
+
reason: "mock — judgment still valid",
|
|
587
|
+
modified_content: null,
|
|
588
|
+
})),
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
else if (systemPrompt.startsWith("You are reclassifying [insight]-tagged learnings")) {
|
|
592
|
+
// Insight reclassifier — return foundation as a safe default.
|
|
593
|
+
text = JSON.stringify({
|
|
594
|
+
proposed_role: "foundation",
|
|
595
|
+
reason: "mock — defaulted to foundation",
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
else if (systemPrompt.startsWith("You are updating a domain document")) {
|
|
599
|
+
// Domain doc proposer Phase B.
|
|
600
|
+
text = JSON.stringify({
|
|
601
|
+
reflection_form: "add_term",
|
|
602
|
+
content: "**Mock Term** — A mock entry produced by the deterministic LLM provider.",
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
else if (systemPrompt.startsWith("You are detecting cross-agent principle duplication")) {
|
|
606
|
+
// Cross-agent dedup (criterion 6) — extract the first agent from the
|
|
607
|
+
// user prompt as primary owner and fabricate a consolidated line. The
|
|
608
|
+
// mock happy path always confirms same_principle so tests can exercise
|
|
609
|
+
// the structural path.
|
|
610
|
+
//
|
|
611
|
+
// Negative-path hooks (CG3 + UF3):
|
|
612
|
+
// ONTO_LLM_MOCK_DEDUP_BOGUS_OWNER=1
|
|
613
|
+
// → return a primary_owner_agent that is NOT in the shortlist so the
|
|
614
|
+
// C2 runtime guard in llmConfirmCluster rejects the cluster.
|
|
615
|
+
// ONTO_LLM_MOCK_DEDUP_SAME_PRINCIPLE_FALSE=1
|
|
616
|
+
// → return same_principle=false so the UF2 metric bucket bumps.
|
|
617
|
+
// ONTO_LLM_MOCK_DEDUP_MALFORMED=1
|
|
618
|
+
// → emit non-JSON so the malformed_json failure channel fires.
|
|
619
|
+
//
|
|
620
|
+
// These hooks are test-only and gated on the ONTO_LLM_MOCK=1 envelope
|
|
621
|
+
// already checked above; production runs never see them.
|
|
622
|
+
if (process.env.ONTO_LLM_MOCK_DEDUP_MALFORMED === "1") {
|
|
623
|
+
text = "{this is not valid json at all";
|
|
624
|
+
}
|
|
625
|
+
else if (process.env.ONTO_LLM_MOCK_DEDUP_SAME_PRINCIPLE_FALSE === "1") {
|
|
626
|
+
text = JSON.stringify({
|
|
627
|
+
same_principle: false,
|
|
628
|
+
primary_owner_agent: null,
|
|
629
|
+
primary_owner_reason: "mock — disagreement",
|
|
630
|
+
consolidated_principle: "",
|
|
631
|
+
representative_cases: [],
|
|
632
|
+
consolidated_line: "",
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
const firstAgent = extractFirstDedupAgent(userPrompt);
|
|
637
|
+
const agentCount = countDedupAgents(userPrompt);
|
|
638
|
+
const bogusOwner = process.env.ONTO_LLM_MOCK_DEDUP_BOGUS_OWNER === "1"
|
|
639
|
+
? "offshortlist_ghost_agent"
|
|
640
|
+
: firstAgent;
|
|
641
|
+
text = JSON.stringify({
|
|
642
|
+
same_principle: true,
|
|
643
|
+
primary_owner_agent: bogusOwner,
|
|
644
|
+
primary_owner_reason: "mock — first listed agent",
|
|
645
|
+
consolidated_principle: "Mock consolidated principle produced by the deterministic LLM provider.",
|
|
646
|
+
representative_cases: Array.from({ length: Math.min(agentCount, 3) }, (_, i) => `mock case ${i + 1}`),
|
|
647
|
+
consolidated_line: "- [fact] [methodology] [foundation] mock consolidated principle " +
|
|
648
|
+
"(Representative cases: mock case 1; mock case 2) (source: consolidated from mock-mock-2026-04-09)",
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
else if (systemPrompt.startsWith("You are a semantic classifier")) {
|
|
653
|
+
text = JSON.stringify({
|
|
654
|
+
decision: "save",
|
|
655
|
+
conflict_kind: null,
|
|
656
|
+
matched_existing_line: null,
|
|
657
|
+
reason: "mock — no overlap detected",
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
else if (systemPrompt.startsWith("You are a review complexity assessor")) {
|
|
661
|
+
// Phase 3: Step 1.5 complexity assessment mock — defaults to full review
|
|
662
|
+
text = JSON.stringify({
|
|
663
|
+
q2_cross_verification_secondary: false,
|
|
664
|
+
q2_rationale: "mock — defaulting to full review (cross-verification critical)",
|
|
665
|
+
q3_miss_risk_acceptable: false,
|
|
666
|
+
q3_rationale: "mock — defaulting to full review (risk not acceptable)",
|
|
667
|
+
suggest_core_axis: false,
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
else if (systemPrompt.startsWith("You are a review lens selector")) {
|
|
671
|
+
// Phase 3: Step 1.5 lens selection mock — default core-axis set.
|
|
672
|
+
// SSOT: .onto/authority/core-lens-registry.yaml (v0.2.1: cost-constrained
|
|
673
|
+
// Pareto-optimal lenses). Imported at module init (see top of file).
|
|
674
|
+
text = JSON.stringify({
|
|
675
|
+
selected_lens_ids: loadCoreLensRegistry().core_axis_lens_ids,
|
|
676
|
+
rationale: "mock — default core-axis review lens set",
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
else if (systemPrompt.startsWith("You are executing a single bounded review unit")) {
|
|
680
|
+
// Phase 2 host-decoupling: ts_inline_http review unit executor (lens
|
|
681
|
+
// variant). The mock returns a minimal lens-output-shaped markdown so
|
|
682
|
+
// executor tests can verify the full call → write → JSON-print path
|
|
683
|
+
// without needing a real LLM endpoint. Real lens output comes from a real
|
|
684
|
+
// LLM; this mock only exercises the executor wiring.
|
|
685
|
+
text = [
|
|
686
|
+
"# Mock Lens Output (ts_inline_http executor mock)",
|
|
687
|
+
"",
|
|
688
|
+
"## Structural Inspection",
|
|
689
|
+
"- Mock checklist item: PASS",
|
|
690
|
+
"",
|
|
691
|
+
"## Findings",
|
|
692
|
+
"(none — mock executor)",
|
|
693
|
+
"",
|
|
694
|
+
"## Newly Learned",
|
|
695
|
+
"(none — mock executor)",
|
|
696
|
+
"",
|
|
697
|
+
"## Applied Learnings",
|
|
698
|
+
"(none — mock executor)",
|
|
699
|
+
"",
|
|
700
|
+
"## Domain Constraints Used",
|
|
701
|
+
"[]",
|
|
702
|
+
"",
|
|
703
|
+
"## Domain Context Assumptions",
|
|
704
|
+
'- "Mock executor returned this output for test purposes via ONTO_LLM_MOCK=1."',
|
|
705
|
+
"",
|
|
706
|
+
].join("\n");
|
|
707
|
+
}
|
|
708
|
+
else if (systemPrompt.startsWith("You are the synthesize actor for a 9-lens review")) {
|
|
709
|
+
// Phase 3-3: synthesize-variant executor mock. Returns a minimal
|
|
710
|
+
// synthesize-shaped markdown with the 8 required sections + YAML
|
|
711
|
+
// frontmatter so downstream consumers can verify the structure.
|
|
712
|
+
//
|
|
713
|
+
// Phase 3-4 A2 negative-path hook: ONTO_LLM_MOCK_SYNTHESIZE_WRAP_FENCE=1
|
|
714
|
+
// makes the mock wrap its entire response in a ```yaml fence, simulating
|
|
715
|
+
// the 30B-A3B behavior that violates the "Do not wrap" prompt rule. This
|
|
716
|
+
// exercises the executor's stripWrappingCodeFence post-processor without
|
|
717
|
+
// needing a real LLM call.
|
|
718
|
+
//
|
|
719
|
+
// Phase 3-4 A5 negative-path hook: ONTO_LLM_MOCK_SYNTHESIZE_FABRICATE=1
|
|
720
|
+
// injects a fabricated quote (a phrase that won't appear in any lens
|
|
721
|
+
// pool content) into the Disagreement section, simulating the
|
|
722
|
+
// hallucination observed in the A3 benchmark. This exercises the
|
|
723
|
+
// citation audit layer. Both hooks are test-only and gated on the
|
|
724
|
+
// ONTO_LLM_MOCK=1 envelope already checked above.
|
|
725
|
+
const disagreementSection = process.env.ONTO_LLM_MOCK_SYNTHESIZE_FABRICATE === "1"
|
|
726
|
+
? 'Axiology said "A fabricated quote that is definitely nowhere in the lens pool for this mock test run".'
|
|
727
|
+
: "(none — mock executor)";
|
|
728
|
+
const synthesizeBody = [
|
|
729
|
+
"---",
|
|
730
|
+
"deliberation_status: performed",
|
|
731
|
+
"---",
|
|
732
|
+
"",
|
|
733
|
+
"# Mock Synthesize Output (ts_inline_http executor mock, synthesize variant)",
|
|
734
|
+
"",
|
|
735
|
+
"## Consensus",
|
|
736
|
+
"(none — mock executor)",
|
|
737
|
+
"",
|
|
738
|
+
"## Conditional Consensus",
|
|
739
|
+
"(none — mock executor)",
|
|
740
|
+
"",
|
|
741
|
+
"## Disagreement",
|
|
742
|
+
disagreementSection,
|
|
743
|
+
"",
|
|
744
|
+
"## Deliberation Decision",
|
|
745
|
+
"Mock synthesize consumed the controlled deliberation artifact via ONTO_LLM_MOCK=1.",
|
|
746
|
+
"",
|
|
747
|
+
"## Unique Finding Tagging",
|
|
748
|
+
"(none — mock executor)",
|
|
749
|
+
"",
|
|
750
|
+
"## Axiology Integration",
|
|
751
|
+
"(none — mock executor)",
|
|
752
|
+
"",
|
|
753
|
+
"## Newly Learned",
|
|
754
|
+
"(none — mock executor)",
|
|
755
|
+
"",
|
|
756
|
+
"## Degraded Lens Failures",
|
|
757
|
+
"(none — mock executor)",
|
|
758
|
+
"",
|
|
759
|
+
].join("\n");
|
|
760
|
+
text =
|
|
761
|
+
process.env.ONTO_LLM_MOCK_SYNTHESIZE_WRAP_FENCE === "1"
|
|
762
|
+
? "```yaml\n" + synthesizeBody + "```"
|
|
763
|
+
: synthesizeBody;
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
// Unknown prompt → throw with the prefix so tests point at the drifted prompt.
|
|
767
|
+
const prefix = systemPrompt.slice(0, 80).replace(/\n/g, " ");
|
|
768
|
+
return Promise.reject(new Error(`mock LLM provider: no pattern matched system prompt prefix "${prefix}". ` +
|
|
769
|
+
`If this is a new Phase 3 prompt, add a matching branch in callMockProvider. ` +
|
|
770
|
+
`If this is an old prompt that changed, update the matching prefix.`));
|
|
771
|
+
}
|
|
772
|
+
return Promise.resolve({
|
|
773
|
+
text,
|
|
774
|
+
input_tokens: estimateMockTokens(systemPrompt + userPrompt),
|
|
775
|
+
output_tokens: estimateMockTokens(text),
|
|
776
|
+
model_id: MOCK_MODEL_ID,
|
|
777
|
+
effective_base_url: "mock://deterministic",
|
|
778
|
+
declared_billing_mode: "per_token",
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
function extractCandidateIds(userPrompt) {
|
|
782
|
+
// Panel prompt format: `1. candidate_id=abc123 type=...`
|
|
783
|
+
const ids = [];
|
|
784
|
+
const re = /candidate_id=([A-Za-z0-9_-]+)/g;
|
|
785
|
+
let m;
|
|
786
|
+
while ((m = re.exec(userPrompt)) !== null) {
|
|
787
|
+
ids.push(m[1]);
|
|
788
|
+
}
|
|
789
|
+
return ids;
|
|
790
|
+
}
|
|
791
|
+
function extractJudgmentItemCount(userPrompt) {
|
|
792
|
+
const m = userPrompt.match(/Judgment items to re-verify:\s*(\d+)/);
|
|
793
|
+
return m ? Number(m[1]) : 0;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Cross-agent dedup user prompt lists items as:
|
|
797
|
+
* 1. agent_id=structure
|
|
798
|
+
* ...
|
|
799
|
+
* 2. agent_id=coverage
|
|
800
|
+
* ...
|
|
801
|
+
* Pick the first agent_id we see so the mock's primary_owner_agent matches
|
|
802
|
+
* the first listed shortlist member. Falls back to "structure" when no
|
|
803
|
+
* agent_id appears at all (shouldn't happen in practice).
|
|
804
|
+
*/
|
|
805
|
+
function extractFirstDedupAgent(userPrompt) {
|
|
806
|
+
const m = userPrompt.match(/agent_id=([A-Za-z0-9_-]+)/);
|
|
807
|
+
return m ? m[1] : "structure";
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* Count the distinct agent_id references in the cross-agent dedup user prompt
|
|
811
|
+
* so the mock can emit a plausible representative_cases list sized to the
|
|
812
|
+
* shortlist.
|
|
813
|
+
*/
|
|
814
|
+
function countDedupAgents(userPrompt) {
|
|
815
|
+
const ids = new Set();
|
|
816
|
+
const re = /agent_id=([A-Za-z0-9_-]+)/g;
|
|
817
|
+
let m;
|
|
818
|
+
while ((m = re.exec(userPrompt)) !== null) {
|
|
819
|
+
ids.add(m[1]);
|
|
820
|
+
}
|
|
821
|
+
return ids.size;
|
|
822
|
+
}
|
|
823
|
+
function estimateMockTokens(text) {
|
|
824
|
+
return Math.max(1, Math.ceil(text.length / 4));
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Compute a stable hash of a prompt string for audit trail.
|
|
828
|
+
*/
|
|
829
|
+
export function hashPrompt(prompt) {
|
|
830
|
+
return crypto.createHash("sha256").update(prompt).digest("hex").slice(0, 12);
|
|
831
|
+
}
|