АРЧ АП11 - Выделить truth и answer-shape policy в assistant runtime
This commit is contained in:
+7
-2
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.runAssistantAddressLaneResponseRuntime = runAssistantAddressLaneResponseRuntime;
|
||||
const assistantAddressTurnFinalizeRuntimeAdapter_1 = require("./assistantAddressTurnFinalizeRuntimeAdapter");
|
||||
const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver");
|
||||
const assistantTruthAnswerPolicyRuntimeAdapter_1 = require("./assistantTruthAnswerPolicyRuntimeAdapter");
|
||||
function toRecordObject(value) {
|
||||
if (!value || typeof value !== "object") {
|
||||
return null;
|
||||
@@ -192,6 +193,10 @@ function runAssistantAddressLaneResponseRuntime(input) {
|
||||
userMessage: input.userMessage,
|
||||
addressRuntimeMeta: input.llmPreDecomposeMeta
|
||||
});
|
||||
const debugWithTruthAnswerPolicy = (0, assistantTruthAnswerPolicyRuntimeAdapter_1.attachAssistantTruthAnswerPolicy)(debugWithRuntimeContracts, {
|
||||
addressRuntimeMeta: input.llmPreDecomposeMeta,
|
||||
replyType: normalizeAddressReplyType(input.addressLane.reply_type)
|
||||
});
|
||||
const finalization = finalizeAddressTurnSafe({
|
||||
sessionId: input.sessionId,
|
||||
userMessage: input.userMessage,
|
||||
@@ -199,7 +204,7 @@ function runAssistantAddressLaneResponseRuntime(input) {
|
||||
assistantReply: safeAddressReply,
|
||||
replyType: normalizeAddressReplyType(input.addressLane.reply_type),
|
||||
addressLaneDebug: normalizeAddressLaneDebug(input.addressLane.debug),
|
||||
debug: debugWithRuntimeContracts,
|
||||
debug: debugWithTruthAnswerPolicy,
|
||||
carryoverMeta: normalizeCarryoverMeta(input.carryoverMeta),
|
||||
llmPreDecomposeMeta: normalizeLlmPreDecomposeMeta(input.llmPreDecomposeMeta),
|
||||
appendItem: input.appendItem,
|
||||
@@ -211,6 +216,6 @@ function runAssistantAddressLaneResponseRuntime(input) {
|
||||
});
|
||||
return {
|
||||
response: finalization.response,
|
||||
debug: debugWithRuntimeContracts
|
||||
debug: debugWithTruthAnswerPolicy
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildDeepAnalysisDebugPayload = buildDeepAnalysisDebugPayload;
|
||||
const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver");
|
||||
const assistantTruthAnswerPolicyRuntimeAdapter_1 = require("./assistantTruthAnswerPolicyRuntimeAdapter");
|
||||
const assistantStage4AnswerContractAudit_1 = require("./assistantStage4AnswerContractAudit");
|
||||
function toAnalysisContext(input) {
|
||||
if (!input.active) {
|
||||
@@ -94,8 +95,14 @@ function buildDeepAnalysisDebugPayload(input) {
|
||||
investigation_state_snapshot: input.investigationStateSnapshot,
|
||||
normalized: input.normalizedPayload
|
||||
};
|
||||
return (0, assistantRuntimeContractResolver_1.attachAssistantRuntimeContractShadow)(debugPayload, {
|
||||
const debugWithRuntimeContracts = (0, assistantRuntimeContractResolver_1.attachAssistantRuntimeContractShadow)(debugPayload, {
|
||||
addressRuntimeMeta: input.addressRuntimeMetaForDeep,
|
||||
groundingStatus: input.groundingCheck.status
|
||||
});
|
||||
return (0, assistantTruthAnswerPolicyRuntimeAdapter_1.attachAssistantTruthAnswerPolicy)(debugWithRuntimeContracts, {
|
||||
addressRuntimeMeta: input.addressRuntimeMetaForDeep,
|
||||
groundingStatus: input.groundingCheck.status,
|
||||
coverageReport: input.coverageReport,
|
||||
replyType: "deep_analysis"
|
||||
});
|
||||
}
|
||||
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.resolveAssistantTruthAnswerPolicyRuntime = resolveAssistantTruthAnswerPolicyRuntime;
|
||||
exports.buildAssistantTruthAnswerPolicyRuntimeFields = buildAssistantTruthAnswerPolicyRuntimeFields;
|
||||
exports.attachAssistantTruthAnswerPolicy = attachAssistantTruthAnswerPolicy;
|
||||
const assistantRuntimeContracts_1 = require("../types/assistantRuntimeContracts");
|
||||
const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver");
|
||||
function toRecordObject(value) {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
function toNonEmptyString(value) {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
const text = String(value).trim();
|
||||
return text.length > 0 ? text : null;
|
||||
}
|
||||
function asNumber(value) {
|
||||
if (typeof value === "number" && Number.isFinite(value)) {
|
||||
return value;
|
||||
}
|
||||
if (typeof value === "string" && value.trim().length > 0) {
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) ? parsed : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function toStringList(value) {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
}
|
||||
return value
|
||||
.map((item) => toNonEmptyString(item))
|
||||
.filter((item) => Boolean(item));
|
||||
}
|
||||
function isGroundingStatus(value) {
|
||||
return (value === "grounded" ||
|
||||
value === "partial" ||
|
||||
value === "route_mismatch_blocked" ||
|
||||
value === "no_grounded_answer" ||
|
||||
value === "unsupported");
|
||||
}
|
||||
function isEvidenceGrade(value) {
|
||||
return value === "weak" || value === "medium" || value === "strong" || value === "none";
|
||||
}
|
||||
function normalizeReplyType(value) {
|
||||
if (value === "factual" || value === "partial_coverage" || value === "deep_analysis") {
|
||||
return value;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
function groundingStatusFrom(debug, input, truthGateStatus) {
|
||||
const explicit = toNonEmptyString(input.groundingStatus) ??
|
||||
toNonEmptyString(toRecordObject(debug.answer_grounding_check)?.status);
|
||||
if (isGroundingStatus(explicit)) {
|
||||
return explicit;
|
||||
}
|
||||
if (truthGateStatus === "blocked_route_expectation_failure") {
|
||||
return "route_mismatch_blocked";
|
||||
}
|
||||
if (truthGateStatus === "full_confirmed") {
|
||||
return "grounded";
|
||||
}
|
||||
if (truthGateStatus === "partial_supported" || truthGateStatus === "limited_temporal_or_contextual") {
|
||||
return "partial";
|
||||
}
|
||||
if (truthGateStatus === "blocked_missing_anchor" || truthGateStatus === "blocked_execution_error") {
|
||||
return "no_grounded_answer";
|
||||
}
|
||||
const rowsMatched = asNumber(debug.rows_matched);
|
||||
if (rowsMatched !== null && rowsMatched > 0) {
|
||||
return "grounded";
|
||||
}
|
||||
return "unsupported";
|
||||
}
|
||||
function coverageStatusFrom(debug, input, truthGateStatus, groundingStatus) {
|
||||
if (truthGateStatus === "full_confirmed") {
|
||||
return "full";
|
||||
}
|
||||
if (truthGateStatus === "partial_supported" || truthGateStatus === "limited_temporal_or_contextual") {
|
||||
return "partial";
|
||||
}
|
||||
if (truthGateStatus.startsWith("blocked")) {
|
||||
return "blocked";
|
||||
}
|
||||
if (toStringList(debug.missing_required_filters).length > 0 || groundingStatus === "route_mismatch_blocked" || groundingStatus === "no_grounded_answer") {
|
||||
return "blocked";
|
||||
}
|
||||
const coverageReport = toRecordObject(input.coverageReport) ?? toRecordObject(debug.coverage_report);
|
||||
if (coverageReport) {
|
||||
const total = asNumber(coverageReport.requirements_total);
|
||||
const covered = asNumber(coverageReport.requirements_covered) ?? 0;
|
||||
const uncovered = toStringList(coverageReport.requirements_uncovered);
|
||||
const partial = toStringList(coverageReport.requirements_partially_covered);
|
||||
const clarification = toStringList(coverageReport.clarification_needed_for);
|
||||
const outOfScope = toStringList(coverageReport.out_of_scope_requirements);
|
||||
if (total !== null && total > 0) {
|
||||
if (covered >= total && uncovered.length === 0 && partial.length === 0 && clarification.length === 0 && outOfScope.length === 0) {
|
||||
return "full";
|
||||
}
|
||||
if (covered > 0 || partial.length > 0) {
|
||||
return "partial";
|
||||
}
|
||||
return "blocked";
|
||||
}
|
||||
}
|
||||
const rowsMatched = asNumber(debug.rows_matched);
|
||||
if (rowsMatched !== null && rowsMatched > 0) {
|
||||
return "full";
|
||||
}
|
||||
return groundingStatus === "partial" ? "partial" : "blocked";
|
||||
}
|
||||
function truthModeFrom(input) {
|
||||
if (input.truthGateStatus === "blocked_missing_anchor" || toStringList(input.debug.missing_required_filters).length > 0) {
|
||||
return "clarification_required";
|
||||
}
|
||||
if (input.truthGateStatus === "full_confirmed" || (input.coverageStatus === "full" && input.groundingStatus === "grounded")) {
|
||||
return "confirmed";
|
||||
}
|
||||
if (input.truthGateStatus === "partial_supported" || input.truthGateStatus === "limited_temporal_or_contextual" || input.coverageStatus === "partial") {
|
||||
return "limited";
|
||||
}
|
||||
return "unsupported";
|
||||
}
|
||||
function evidenceGradeFrom(debug, coverageStatus, groundingStatus, truthGateStatus) {
|
||||
const explicit = toNonEmptyString(debug.evidence_strength);
|
||||
if (isEvidenceGrade(explicit)) {
|
||||
return explicit;
|
||||
}
|
||||
if (coverageStatus === "blocked") {
|
||||
return "none";
|
||||
}
|
||||
if (truthGateStatus === "full_confirmed" || groundingStatus === "grounded") {
|
||||
return "strong";
|
||||
}
|
||||
const rowsMatched = asNumber(debug.rows_matched);
|
||||
if (rowsMatched !== null && rowsMatched > 0) {
|
||||
return "medium";
|
||||
}
|
||||
return coverageStatus === "partial" ? "weak" : "none";
|
||||
}
|
||||
function normalizeReasonCode(value) {
|
||||
const normalized = value
|
||||
.trim()
|
||||
.replace(/[^\p{L}\p{N}_.:-]+/gu, "_")
|
||||
.replace(/^_+|_+$/g, "")
|
||||
.toLowerCase();
|
||||
return normalized.length > 0 ? normalized.slice(0, 120) : null;
|
||||
}
|
||||
function pushReason(target, value) {
|
||||
const text = toNonEmptyString(value);
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
const normalized = normalizeReasonCode(text);
|
||||
if (normalized && !target.includes(normalized)) {
|
||||
target.push(normalized);
|
||||
}
|
||||
}
|
||||
function collectReasonCodes(input) {
|
||||
const reasons = [];
|
||||
pushReason(reasons, `truth_gate_${input.truthGateStatus}`);
|
||||
pushReason(reasons, `truth_mode_${input.truthMode}`);
|
||||
input.shadow.transition_contract_reason.forEach((item) => pushReason(reasons, item));
|
||||
input.shadow.capability_contract_reason.forEach((item) => pushReason(reasons, item));
|
||||
toStringList(input.debug.missing_required_filters).forEach((item) => pushReason(reasons, `missing_filter_${item}`));
|
||||
toStringList(input.debug.limitations).forEach((item) => pushReason(reasons, item));
|
||||
toStringList(input.debug.reasons).forEach((item) => pushReason(reasons, item));
|
||||
pushReason(reasons, input.debug.route_expectation_reason);
|
||||
toStringList(toRecordObject(input.debug.answer_grounding_check)?.reasons).forEach((item) => pushReason(reasons, item));
|
||||
toStringList(input.coverageReport?.requirements_uncovered).forEach((item) => pushReason(reasons, `coverage_uncovered_${item}`));
|
||||
toStringList(input.coverageReport?.requirements_partially_covered).forEach((item) => pushReason(reasons, `coverage_partial_${item}`));
|
||||
toStringList(input.coverageReport?.clarification_needed_for).forEach((item) => pushReason(reasons, `coverage_clarification_${item}`));
|
||||
return reasons.slice(0, 32);
|
||||
}
|
||||
function explanationFor(truthGateStatus, truthMode, coverageStatus) {
|
||||
if (truthGateStatus === "full_confirmed" && truthMode === "confirmed") {
|
||||
return null;
|
||||
}
|
||||
if (truthGateStatus === "blocked_missing_anchor" || truthMode === "clarification_required") {
|
||||
return "required_anchor_missing";
|
||||
}
|
||||
if (truthGateStatus === "blocked_route_expectation_failure") {
|
||||
return "route_expectation_failed";
|
||||
}
|
||||
if (truthGateStatus === "blocked_execution_error") {
|
||||
return "execution_failed";
|
||||
}
|
||||
if (truthGateStatus === "limited_temporal_or_contextual") {
|
||||
return "temporal_or_contextual_limit";
|
||||
}
|
||||
if (truthGateStatus === "partial_supported" || truthMode === "limited" || coverageStatus === "partial") {
|
||||
return "evidence_or_coverage_is_partial";
|
||||
}
|
||||
return "truth_gate_not_confirmed";
|
||||
}
|
||||
function answerShapeFrom(input) {
|
||||
if (input.truthMode === "confirmed") {
|
||||
return "confirmed_factual";
|
||||
}
|
||||
if (input.truthMode === "limited") {
|
||||
return "limited_with_reason";
|
||||
}
|
||||
if (input.truthMode === "clarification_required") {
|
||||
return "clarification_required";
|
||||
}
|
||||
if (input.coverageStatus === "blocked" || input.truthGateStatus.startsWith("blocked")) {
|
||||
return "blocked_no_answer";
|
||||
}
|
||||
return input.truthGateStatus === "unknown" ? "unknown" : "unsupported_boundary";
|
||||
}
|
||||
function requiredSectionsFor(shape) {
|
||||
if (shape === "confirmed_factual") {
|
||||
return ["direct_answer", "evidence_basis"];
|
||||
}
|
||||
if (shape === "limited_with_reason") {
|
||||
return ["direct_answer", "evidence_window", "limitations"];
|
||||
}
|
||||
if (shape === "clarification_required") {
|
||||
return ["clarifying_question", "missing_anchors"];
|
||||
}
|
||||
if (shape === "blocked_no_answer") {
|
||||
return ["blocked_reason", "safe_next_step"];
|
||||
}
|
||||
if (shape === "unsupported_boundary") {
|
||||
return ["boundary_reason", "safe_next_step"];
|
||||
}
|
||||
return ["safe_next_step"];
|
||||
}
|
||||
function resolveAssistantTruthAnswerPolicyRuntime(input) {
|
||||
const debug = toRecordObject(input.addressDebug) ?? {};
|
||||
const shadow = (0, assistantRuntimeContractResolver_1.resolveAssistantRuntimeContractShadow)({
|
||||
addressDebug: debug,
|
||||
addressRuntimeMeta: input.addressRuntimeMeta,
|
||||
groundingStatus: input.groundingStatus
|
||||
});
|
||||
const truthGateStatus = shadow.truth_gate_contract_status;
|
||||
const groundingStatus = groundingStatusFrom(debug, input, truthGateStatus);
|
||||
const coverageStatus = coverageStatusFrom(debug, input, truthGateStatus, groundingStatus);
|
||||
const truthMode = truthModeFrom({
|
||||
coverageStatus,
|
||||
groundingStatus,
|
||||
truthGateStatus,
|
||||
debug
|
||||
});
|
||||
const evidenceGrade = evidenceGradeFrom(debug, coverageStatus, groundingStatus, truthGateStatus);
|
||||
const coverageReport = toRecordObject(input.coverageReport) ?? toRecordObject(debug.coverage_report);
|
||||
const reasonCodes = collectReasonCodes({
|
||||
debug,
|
||||
coverageReport,
|
||||
shadow,
|
||||
truthMode,
|
||||
truthGateStatus
|
||||
});
|
||||
const shape = answerShapeFrom({
|
||||
coverageStatus,
|
||||
truthMode,
|
||||
truthGateStatus
|
||||
});
|
||||
const carryoverEligibility = coverageStatus === "blocked" || truthMode === "unsupported" ? "none" : shadow.carryover_eligibility;
|
||||
const truthGate = {
|
||||
schema_version: assistantRuntimeContracts_1.ASSISTANT_TRUTH_ANSWER_POLICY_RUNTIME_SCHEMA_VERSION,
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter",
|
||||
coverage_status: coverageStatus,
|
||||
evidence_grade: evidenceGrade,
|
||||
grounding_status: groundingStatus,
|
||||
truth_mode: truthMode,
|
||||
carryover_eligibility: carryoverEligibility,
|
||||
reason_codes: reasonCodes,
|
||||
source_truth_gate_status: truthGateStatus,
|
||||
blocked_or_limited_explanation: explanationFor(truthGateStatus, truthMode, coverageStatus)
|
||||
};
|
||||
const answerShape = {
|
||||
schema_version: assistantRuntimeContracts_1.ASSISTANT_TRUTH_ANSWER_POLICY_RUNTIME_SCHEMA_VERSION,
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter",
|
||||
answer_shape: shape,
|
||||
reply_type: normalizeReplyType(input.replyType),
|
||||
capability_contract_id: shadow.capability_contract_id,
|
||||
transition_contract_id: shadow.transition_contract_id,
|
||||
may_state_confirmed_facts: truthMode === "confirmed" || truthMode === "limited",
|
||||
must_include_limitation: truthMode !== "confirmed",
|
||||
may_power_followup: carryoverEligibility !== "none" && coverageStatus !== "blocked",
|
||||
required_sections: requiredSectionsFor(shape),
|
||||
downgrade_only: true
|
||||
};
|
||||
return {
|
||||
schema_version: assistantRuntimeContracts_1.ASSISTANT_TRUTH_ANSWER_POLICY_RUNTIME_SCHEMA_VERSION,
|
||||
policy_owner: "assistantTruthAnswerPolicyRuntimeAdapter",
|
||||
truth_gate: truthGate,
|
||||
answer_shape: answerShape
|
||||
};
|
||||
}
|
||||
function buildAssistantTruthAnswerPolicyRuntimeFields(input) {
|
||||
const policy = resolveAssistantTruthAnswerPolicyRuntime(input);
|
||||
return {
|
||||
assistant_truth_answer_policy_v1: policy,
|
||||
coverage_gate_contract: policy.truth_gate,
|
||||
answer_shape_contract: policy.answer_shape,
|
||||
truth_mode: policy.truth_gate.truth_mode,
|
||||
carryover_eligibility: policy.truth_gate.carryover_eligibility,
|
||||
answer_shape: policy.answer_shape.answer_shape
|
||||
};
|
||||
}
|
||||
function attachAssistantTruthAnswerPolicy(debugPayload, input) {
|
||||
return {
|
||||
...debugPayload,
|
||||
...buildAssistantTruthAnswerPolicyRuntimeFields({
|
||||
...input,
|
||||
addressDebug: debugPayload
|
||||
})
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ASSISTANT_RUNTIME_CONTRACTS_SCHEMA_VERSION = void 0;
|
||||
exports.ASSISTANT_TRUTH_ANSWER_POLICY_RUNTIME_SCHEMA_VERSION = exports.ASSISTANT_RUNTIME_CONTRACTS_SCHEMA_VERSION = void 0;
|
||||
exports.ASSISTANT_RUNTIME_CONTRACTS_SCHEMA_VERSION = "assistant_runtime_contracts_v1";
|
||||
exports.ASSISTANT_TRUTH_ANSWER_POLICY_RUNTIME_SCHEMA_VERSION = "assistant_truth_answer_policy_runtime_v1";
|
||||
|
||||
Reference in New Issue
Block a user