ARCH: добавить MCP catalog index для discovery
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ASSISTANT_MCP_CATALOG_PLAN_REVIEW_SCHEMA_VERSION = exports.ASSISTANT_MCP_CATALOG_INDEX_SCHEMA_VERSION = void 0;
|
||||
exports.buildAssistantMcpCatalogIndex = buildAssistantMcpCatalogIndex;
|
||||
exports.getAssistantMcpCatalogPrimitive = getAssistantMcpCatalogPrimitive;
|
||||
exports.reviewAssistantMcpDiscoveryPlanAgainstCatalog = reviewAssistantMcpDiscoveryPlanAgainstCatalog;
|
||||
const assistantMcpDiscoveryPolicy_1 = require("./assistantMcpDiscoveryPolicy");
|
||||
exports.ASSISTANT_MCP_CATALOG_INDEX_SCHEMA_VERSION = "assistant_mcp_catalog_index_v1";
|
||||
exports.ASSISTANT_MCP_CATALOG_PLAN_REVIEW_SCHEMA_VERSION = "assistant_mcp_catalog_plan_review_v1";
|
||||
const PRIMITIVE_CONTRACTS = [
|
||||
{
|
||||
primitive_id: "search_business_entity",
|
||||
purpose: "Find candidate 1C business entities by user wording before a fact query is executed.",
|
||||
required_axes_any_of: [["business_entity"], ["counterparty"], ["organization"], ["contract"], ["item"]],
|
||||
optional_axes: ["period", "document", "account"],
|
||||
output_fact_kinds: ["entity_candidates", "entity_ambiguity"],
|
||||
evidence_floor: "rows_received",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "inspect_1c_metadata",
|
||||
purpose: "Inspect available 1C schema/catalog/document/register surface before selecting a query lane.",
|
||||
required_axes_any_of: [["metadata_scope"], ["domain_family"], ["document"], ["register"]],
|
||||
optional_axes: ["business_entity", "account", "counterparty"],
|
||||
output_fact_kinds: ["available_fields", "available_entity_sets", "known_limitations"],
|
||||
evidence_floor: "source_summary",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "resolve_entity_reference",
|
||||
purpose: "Resolve a user-visible entity name to a concrete 1C reference candidate.",
|
||||
required_axes_any_of: [["business_entity"], ["counterparty"], ["organization"], ["contract"], ["item"]],
|
||||
optional_axes: ["period", "inn", "document"],
|
||||
output_fact_kinds: ["resolved_entity_ref", "entity_conflict"],
|
||||
evidence_floor: "rows_matched",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "query_movements",
|
||||
purpose: "Fetch or aggregate accounting/register movements for a scoped business question.",
|
||||
required_axes_any_of: [["period", "account"], ["period", "counterparty"], ["period", "organization"]],
|
||||
optional_axes: ["contract", "document", "amount", "item", "warehouse"],
|
||||
output_fact_kinds: ["movement_rows", "turnover", "balance_delta"],
|
||||
evidence_floor: "rows_matched",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "query_documents",
|
||||
purpose: "Fetch documents related to a scoped entity, period, contract, or movement explanation.",
|
||||
required_axes_any_of: [["document"], ["counterparty"], ["contract"], ["period", "organization"]],
|
||||
optional_axes: ["account", "amount", "item", "warehouse"],
|
||||
output_fact_kinds: ["document_rows", "document_dates", "document_amounts"],
|
||||
evidence_floor: "rows_matched",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "aggregate_by_axis",
|
||||
purpose: "Aggregate already-scoped 1C evidence by a business axis such as counterparty, contract, or period.",
|
||||
required_axes_any_of: [["aggregate_axis", "period"], ["aggregate_axis", "counterparty"], ["aggregate_axis", "account"]],
|
||||
optional_axes: ["organization", "contract", "document", "amount"],
|
||||
output_fact_kinds: ["aggregate_totals", "ranked_axis_values"],
|
||||
evidence_floor: "rows_matched",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "drilldown_related_objects",
|
||||
purpose: "Drill from a known entity or document into related contracts, documents, movements, or payments.",
|
||||
required_axes_any_of: [["business_entity"], ["document"], ["contract"], ["counterparty"]],
|
||||
optional_axes: ["period", "account", "amount"],
|
||||
output_fact_kinds: ["related_objects", "relationship_edges"],
|
||||
evidence_floor: "rows_received",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "probe_coverage",
|
||||
purpose: "Check whether the selected MCP/schema route can prove the requested fact or only support a bounded inference.",
|
||||
required_axes_any_of: [["coverage_target"], ["domain_family"], ["primitive_id"]],
|
||||
optional_axes: ["period", "organization", "counterparty", "document", "account"],
|
||||
output_fact_kinds: ["coverage_status", "known_gaps"],
|
||||
evidence_floor: "source_summary",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
},
|
||||
{
|
||||
primitive_id: "explain_evidence_basis",
|
||||
purpose: "Produce a machine-readable explanation of which checked MCP evidence supports, limits, or fails the answer.",
|
||||
required_axes_any_of: [["evidence_basis"], ["primitive_id"], ["source_rows_summary"]],
|
||||
optional_axes: ["coverage_target", "domain_family"],
|
||||
output_fact_kinds: ["confirmed_facts", "inferred_facts", "unknown_facts"],
|
||||
evidence_floor: "source_summary",
|
||||
safe_for_model_planning: true,
|
||||
runtime_must_execute: true
|
||||
}
|
||||
];
|
||||
const PRIMITIVE_CONTRACT_MAP = new Map(PRIMITIVE_CONTRACTS.map((contract) => [contract.primitive_id, contract]));
|
||||
function toStringSet(values) {
|
||||
return new Set(values.map((item) => item.trim()).filter((item) => item.length > 0));
|
||||
}
|
||||
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 hasAnyAxisGroup(axisSet, groups) {
|
||||
return groups.some((group) => group.every((axis) => axisSet.has(axis)));
|
||||
}
|
||||
function missingAxisGroups(axisSet, groups) {
|
||||
return groups.filter((group) => !group.every((axis) => axisSet.has(axis)));
|
||||
}
|
||||
function buildAssistantMcpCatalogIndex() {
|
||||
const reasonCodes = [];
|
||||
const missingContracts = assistantMcpDiscoveryPolicy_1.ASSISTANT_MCP_DISCOVERY_PRIMITIVES.filter((primitive) => !PRIMITIVE_CONTRACT_MAP.has(primitive));
|
||||
if (missingContracts.length > 0) {
|
||||
pushReason(reasonCodes, "catalog_missing_discovery_primitive_contract");
|
||||
}
|
||||
else {
|
||||
pushReason(reasonCodes, "catalog_covers_all_discovery_primitives");
|
||||
}
|
||||
return {
|
||||
schema_version: exports.ASSISTANT_MCP_CATALOG_INDEX_SCHEMA_VERSION,
|
||||
policy_owner: "assistantMcpCatalogIndex",
|
||||
primitives: PRIMITIVE_CONTRACTS,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
}
|
||||
function getAssistantMcpCatalogPrimitive(primitive) {
|
||||
const contract = PRIMITIVE_CONTRACT_MAP.get(primitive);
|
||||
if (!contract) {
|
||||
throw new Error(`Missing MCP catalog primitive contract: ${primitive}`);
|
||||
}
|
||||
return contract;
|
||||
}
|
||||
function reviewAssistantMcpDiscoveryPlanAgainstCatalog(plan) {
|
||||
const reasonCodes = [];
|
||||
const axisSet = toStringSet(plan.required_axes);
|
||||
const reviewedPrimitives = [];
|
||||
const missingAxesByPrimitive = {};
|
||||
const unknownPrimitives = [];
|
||||
const evidenceFloors = {};
|
||||
for (const primitive of plan.allowed_primitives) {
|
||||
const contract = PRIMITIVE_CONTRACT_MAP.get(primitive);
|
||||
if (!contract) {
|
||||
unknownPrimitives.push(primitive);
|
||||
continue;
|
||||
}
|
||||
reviewedPrimitives.push(primitive);
|
||||
evidenceFloors[primitive] = contract.evidence_floor;
|
||||
if (!hasAnyAxisGroup(axisSet, contract.required_axes_any_of)) {
|
||||
missingAxesByPrimitive[primitive] = missingAxisGroups(axisSet, contract.required_axes_any_of);
|
||||
}
|
||||
}
|
||||
if (unknownPrimitives.length > 0) {
|
||||
pushReason(reasonCodes, "catalog_unknown_primitive_in_discovery_plan");
|
||||
}
|
||||
if (Object.keys(missingAxesByPrimitive).length > 0) {
|
||||
pushReason(reasonCodes, "catalog_required_axes_missing_for_primitive");
|
||||
}
|
||||
if (plan.plan_status !== "allowed") {
|
||||
pushReason(reasonCodes, "catalog_review_received_non_allowed_plan");
|
||||
}
|
||||
let reviewStatus = "catalog_compatible";
|
||||
if (unknownPrimitives.length > 0 || plan.plan_status === "blocked") {
|
||||
reviewStatus = "catalog_blocked";
|
||||
}
|
||||
else if (plan.plan_status !== "allowed" || Object.keys(missingAxesByPrimitive).length > 0) {
|
||||
reviewStatus = "needs_more_axes";
|
||||
}
|
||||
if (reviewStatus === "catalog_compatible") {
|
||||
pushReason(reasonCodes, "catalog_plan_compatible");
|
||||
}
|
||||
else if (reviewStatus === "catalog_blocked") {
|
||||
pushReason(reasonCodes, "catalog_plan_blocked");
|
||||
}
|
||||
else {
|
||||
pushReason(reasonCodes, "catalog_plan_needs_more_axes");
|
||||
}
|
||||
return {
|
||||
schema_version: exports.ASSISTANT_MCP_CATALOG_PLAN_REVIEW_SCHEMA_VERSION,
|
||||
policy_owner: "assistantMcpCatalogIndex",
|
||||
review_status: reviewStatus,
|
||||
reviewed_primitives: reviewedPrimitives,
|
||||
missing_axes_by_primitive: missingAxesByPrimitive,
|
||||
unknown_primitives: unknownPrimitives,
|
||||
evidence_floors: evidenceFloors,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user