275 lines
13 KiB
JavaScript
275 lines
13 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ASSISTANT_MCP_ROUTE_CANDIDATE_SCHEMA_VERSION = exports.ASSISTANT_MCP_DISCOVERY_LOOP_STATE_SCHEMA_VERSION = exports.ASSISTANT_MCP_DISCOVERY_RUNTIME_BRIDGE_SCHEMA_VERSION = void 0;
|
|
exports.runAssistantMcpDiscoveryRuntimeBridge = runAssistantMcpDiscoveryRuntimeBridge;
|
|
const assistantMcpDiscoveryAnswerAdapter_1 = require("./assistantMcpDiscoveryAnswerAdapter");
|
|
const assistantMcpDiscoveryPilotExecutor_1 = require("./assistantMcpDiscoveryPilotExecutor");
|
|
const assistantMcpDiscoveryPlanner_1 = require("./assistantMcpDiscoveryPlanner");
|
|
exports.ASSISTANT_MCP_DISCOVERY_RUNTIME_BRIDGE_SCHEMA_VERSION = "assistant_mcp_discovery_runtime_bridge_v1";
|
|
exports.ASSISTANT_MCP_DISCOVERY_LOOP_STATE_SCHEMA_VERSION = "assistant_mcp_discovery_loop_state_v1";
|
|
exports.ASSISTANT_MCP_ROUTE_CANDIDATE_SCHEMA_VERSION = "assistant_mcp_route_candidate_v1";
|
|
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 normalized = normalizeReasonCode(value);
|
|
if (normalized && !target.includes(normalized)) {
|
|
target.push(normalized);
|
|
}
|
|
}
|
|
function uniqueStrings(values) {
|
|
const result = [];
|
|
for (const value of values) {
|
|
const text = String(value ?? "").trim();
|
|
if (text && !result.includes(text)) {
|
|
result.push(text);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function bridgeStatusFor(pilot, draft) {
|
|
if (draft.answer_mode === "blocked" || pilot.pilot_status === "blocked") {
|
|
return "blocked";
|
|
}
|
|
if (draft.answer_mode === "needs_clarification" || pilot.pilot_status === "skipped_needs_clarification") {
|
|
return "needs_clarification";
|
|
}
|
|
if (pilot.pilot_status === "unsupported") {
|
|
return "unsupported";
|
|
}
|
|
if (draft.answer_mode === "checked_sources_only") {
|
|
return "checked_sources_only";
|
|
}
|
|
return "answer_draft_ready";
|
|
}
|
|
function businessFactAnswerAllowed(draft) {
|
|
return draft.answer_mode === "confirmed_with_bounded_inference" || draft.answer_mode === "bounded_inference_only";
|
|
}
|
|
function loopStatusFor(bridgeStatus) {
|
|
if (bridgeStatus === "needs_clarification") {
|
|
return "awaiting_clarification";
|
|
}
|
|
if (bridgeStatus === "blocked" || bridgeStatus === "unsupported") {
|
|
return "blocked";
|
|
}
|
|
return "ready_for_next_hop";
|
|
}
|
|
function routeCandidateStatusFor(bridgeStatus, pilot, missingProofFamily) {
|
|
if (bridgeStatus === "blocked" || pilot.pilot_status === "blocked") {
|
|
return "blocked";
|
|
}
|
|
if (bridgeStatus === "needs_clarification" || pilot.pilot_status === "skipped_needs_clarification") {
|
|
return "needs_user_scope";
|
|
}
|
|
if (bridgeStatus === "unsupported" || pilot.pilot_status === "unsupported") {
|
|
return "needs_route_enablement";
|
|
}
|
|
if (missingProofFamily) {
|
|
return "needs_route_enablement";
|
|
}
|
|
return "ready_for_reviewed_execution";
|
|
}
|
|
function flattenAxes(pilot, source) {
|
|
const result = [];
|
|
for (const step of pilot.dry_run.execution_steps) {
|
|
if (source === "provided_axes") {
|
|
for (const axis of step.provided_axes) {
|
|
if (axis && !result.includes(axis)) {
|
|
result.push(axis);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
for (const option of step.missing_axis_options) {
|
|
for (const axis of option) {
|
|
if (axis && !result.includes(axis)) {
|
|
result.push(axis);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function entityCandidatesFromPlanner(planner) {
|
|
const values = planner.discovery_plan.turn_meaning_ref?.explicit_entity_candidates ?? [];
|
|
return uniqueStrings(values);
|
|
}
|
|
function firstNonEmpty(values) {
|
|
for (const value of values) {
|
|
const text = String(value ?? "").trim();
|
|
if (text) {
|
|
return text;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
function routeCandidateProofFamiliesFor(actionFamily, proofExpectation) {
|
|
const combined = `${actionFamily ?? ""} ${proofExpectation ?? ""}`.trim().toLowerCase();
|
|
const result = [];
|
|
const add = (family) => {
|
|
if (!result.includes(family)) {
|
|
result.push(family);
|
|
}
|
|
};
|
|
if (!combined || combined === "broad_evaluation bounded_inference") {
|
|
return result;
|
|
}
|
|
if (/(?:inventory|stock|warehouse|reserve|liquidation|write[-_ ]?off|obsolete|obsolescence)/iu.test(combined)) {
|
|
add("inventory_reserve_liquidation_quality");
|
|
}
|
|
if (/(?:debt|due[-_ ]?date|overdue|aging|credit[-_ ]?risk)/iu.test(combined)) {
|
|
add("debt_due_date_aging_quality");
|
|
}
|
|
if (/(?:vendor|supplier|procurement|sourcing)/iu.test(combined)) {
|
|
add("vendor_risk_procurement_quality");
|
|
}
|
|
if (/(?:profit|margin|pnl|p&l|financial[-_ ]?result)/iu.test(combined)) {
|
|
add("accounting_profit_margin");
|
|
}
|
|
return result;
|
|
}
|
|
function routeCandidateMissingProofFamily(planner, pilot) {
|
|
if (planner.data_need_graph?.business_fact_family !== "business_overview") {
|
|
return null;
|
|
}
|
|
const wantedFamilies = routeCandidateProofFamiliesFor(planner.data_need_graph?.action_family ?? null, planner.data_need_graph?.proof_expectation ?? null);
|
|
if (wantedFamilies.length <= 0) {
|
|
return null;
|
|
}
|
|
const missingProofFamilies = pilot.derived_business_overview?.missing_proof_families ?? [];
|
|
return missingProofFamilies.find((item) => wantedFamilies.includes(item.family)) ?? null;
|
|
}
|
|
function routeCandidateEnablementReason(status, pilot, missingAxes, missingProofFamily) {
|
|
if (status === "ready_for_reviewed_execution") {
|
|
return null;
|
|
}
|
|
if (status === "needs_user_scope") {
|
|
return missingAxes.length > 0
|
|
? `Missing scope axes: ${missingAxes.join(", ")}`
|
|
: "Selected chain needs user clarification before MCP execution";
|
|
}
|
|
if (missingProofFamily) {
|
|
return [
|
|
`Missing reviewed proof family: ${missingProofFamily.family}`,
|
|
`next_required_evidence=${missingProofFamily.next_required_evidence}`,
|
|
missingProofFamily.current_supported_evidence
|
|
? `current_supported_evidence=${missingProofFamily.current_supported_evidence}`
|
|
: null,
|
|
`must_not_claim=${missingProofFamily.must_not_claim}`
|
|
]
|
|
.filter((item) => Boolean(item))
|
|
.join("; ");
|
|
}
|
|
return firstNonEmpty([
|
|
...pilot.query_limitations,
|
|
...pilot.evidence.unknown_facts,
|
|
"Selected chain is not safely executable by the reviewed MCP runtime yet"
|
|
]);
|
|
}
|
|
function routeCandidateNextAction(status) {
|
|
if (status === "ready_for_reviewed_execution") {
|
|
return "Execute through the reviewed runtime bridge and truth gate.";
|
|
}
|
|
if (status === "needs_user_scope") {
|
|
return "Ask the user for the missing scope axes before MCP execution.";
|
|
}
|
|
if (status === "needs_route_enablement") {
|
|
return "Create or wire a reviewed exact route for the selected chain before treating the fact as answerable.";
|
|
}
|
|
return "Do not execute until the blocking reason is resolved.";
|
|
}
|
|
function buildRouteCandidate(planner, pilot, bridgeStatus) {
|
|
const plannerClarificationGaps = planner.discovery_plan.clarification_gaps ?? [];
|
|
const providedAxes = flattenAxes(pilot, "provided_axes");
|
|
const missingAxes = plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options");
|
|
const missingProofFamily = routeCandidateMissingProofFamily(planner, pilot);
|
|
const candidateStatus = routeCandidateStatusFor(bridgeStatus, pilot, missingProofFamily);
|
|
return {
|
|
schema_version: exports.ASSISTANT_MCP_ROUTE_CANDIDATE_SCHEMA_VERSION,
|
|
policy_owner: "assistantMcpDiscoveryRuntimeBridge",
|
|
candidate_status: candidateStatus,
|
|
selected_chain_id: planner.selected_chain_id,
|
|
selected_chain_summary: planner.selected_chain_summary,
|
|
nearest_catalog_chain_template: planner.catalog_chain_template_alignment.top_chain_template_match,
|
|
catalog_alignment_status: planner.catalog_chain_template_alignment.alignment_status,
|
|
business_fact_family: planner.data_need_graph?.business_fact_family ?? null,
|
|
action_family: planner.data_need_graph?.action_family ?? null,
|
|
proof_expectation: planner.data_need_graph?.proof_expectation ?? null,
|
|
required_axes: [...planner.required_axes],
|
|
provided_axes: providedAxes,
|
|
missing_axes: missingAxes,
|
|
executable_now: candidateStatus === "ready_for_reviewed_execution",
|
|
enablement_reason: routeCandidateEnablementReason(candidateStatus, pilot, missingAxes, missingProofFamily),
|
|
recommended_next_action: routeCandidateNextAction(candidateStatus),
|
|
forbidden_overclaim_flags: uniqueStrings([
|
|
...(planner.data_need_graph?.forbidden_overclaim_flags ?? []),
|
|
...(missingProofFamily ? [missingProofFamily.must_not_claim] : [])
|
|
])
|
|
};
|
|
}
|
|
function buildLoopState(planner, pilot, bridgeStatus) {
|
|
const plannerClarificationGaps = planner.discovery_plan.clarification_gaps ?? [];
|
|
return {
|
|
schema_version: exports.ASSISTANT_MCP_DISCOVERY_LOOP_STATE_SCHEMA_VERSION,
|
|
policy_owner: "assistantMcpDiscoveryRuntimeBridge",
|
|
loop_status: loopStatusFor(bridgeStatus),
|
|
selected_chain_id: planner.selected_chain_id,
|
|
catalog_chain_template_matches: [...planner.catalog_chain_template_matches],
|
|
catalog_chain_template_alignment: planner.catalog_chain_template_alignment,
|
|
pilot_scope: pilot.pilot_scope,
|
|
asked_domain_family: planner.discovery_plan.turn_meaning_ref?.asked_domain_family ?? null,
|
|
asked_action_family: planner.discovery_plan.turn_meaning_ref?.asked_action_family ?? null,
|
|
unsupported_but_understood_family: planner.discovery_plan.turn_meaning_ref?.unsupported_but_understood_family ?? null,
|
|
ranking_need: planner.data_need_graph?.ranking_need ?? planner.discovery_plan.turn_meaning_ref?.seeded_ranking_need ?? null,
|
|
pending_axes: plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options"),
|
|
provided_axes: flattenAxes(pilot, "provided_axes"),
|
|
explicit_entity_candidates: entityCandidatesFromPlanner(planner),
|
|
metadata_scope_hint: planner.discovery_plan.turn_meaning_ref?.metadata_scope_hint ??
|
|
planner.data_need_graph?.metadata_scope_hint ??
|
|
null,
|
|
subject_resolution_optional: planner.discovery_plan.turn_meaning_ref?.subject_resolution_optional === true ||
|
|
planner.data_need_graph?.subject_resolution_optional === true,
|
|
explicit_organization_scope: planner.discovery_plan.turn_meaning_ref?.explicit_organization_scope ?? null,
|
|
explicit_date_scope: planner.discovery_plan.turn_meaning_ref?.explicit_date_scope ?? null
|
|
};
|
|
}
|
|
async function runAssistantMcpDiscoveryRuntimeBridge(input) {
|
|
const planner = (0, assistantMcpDiscoveryPlanner_1.planAssistantMcpDiscovery)({
|
|
semanticDataNeed: input.semanticDataNeed,
|
|
dataNeedGraph: input.dataNeedGraph,
|
|
metadataSurface: input.metadataSurface,
|
|
turnMeaning: input.turnMeaning
|
|
});
|
|
const pilot = await (0, assistantMcpDiscoveryPilotExecutor_1.executeAssistantMcpDiscoveryPilot)(planner, input.deps);
|
|
const answerDraft = (0, assistantMcpDiscoveryAnswerAdapter_1.buildAssistantMcpDiscoveryAnswerDraft)(pilot);
|
|
const bridgeStatus = bridgeStatusFor(pilot, answerDraft);
|
|
const loopState = buildLoopState(planner, pilot, bridgeStatus);
|
|
const routeCandidate = buildRouteCandidate(planner, pilot, bridgeStatus);
|
|
const reasonCodes = uniqueStrings([...planner.reason_codes, ...pilot.reason_codes, ...answerDraft.reason_codes]);
|
|
pushReason(reasonCodes, `runtime_bridge_status_${bridgeStatus}`);
|
|
pushReason(reasonCodes, "runtime_bridge_not_wired_to_hot_assistant_answer");
|
|
pushReason(reasonCodes, `runtime_bridge_loop_state_${loopState.loop_status}`);
|
|
pushReason(reasonCodes, "runtime_bridge_route_candidate_built");
|
|
pushReason(reasonCodes, `runtime_bridge_route_candidate_${routeCandidate.candidate_status}`);
|
|
return {
|
|
schema_version: exports.ASSISTANT_MCP_DISCOVERY_RUNTIME_BRIDGE_SCHEMA_VERSION,
|
|
policy_owner: "assistantMcpDiscoveryRuntimeBridge",
|
|
bridge_status: bridgeStatus,
|
|
hot_runtime_wired: false,
|
|
planner,
|
|
pilot,
|
|
answer_draft: answerDraft,
|
|
loop_state: loopState,
|
|
route_candidate: routeCandidate,
|
|
user_facing_response_allowed: bridgeStatus !== "blocked",
|
|
business_fact_answer_allowed: businessFactAnswerAllowed(answerDraft),
|
|
requires_user_clarification: bridgeStatus === "needs_clarification",
|
|
reason_codes: reasonCodes
|
|
};
|
|
}
|