ARCH: связать metadata grounding с document MCP lane
This commit is contained in:
parent
6d9c1568c3
commit
7ef788fa50
|
|
@ -1,6 +1,9 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.readAssistantMcpDiscoveryPilotScope = readAssistantMcpDiscoveryPilotScope;
|
exports.readAssistantMcpDiscoveryPilotScope = readAssistantMcpDiscoveryPilotScope;
|
||||||
|
exports.readAssistantMcpDiscoveryMetadataRouteFamily = readAssistantMcpDiscoveryMetadataRouteFamily;
|
||||||
|
exports.readAssistantMcpDiscoveryMetadataSelectedEntitySet = readAssistantMcpDiscoveryMetadataSelectedEntitySet;
|
||||||
|
exports.readAssistantMcpDiscoveryMetadataAmbiguityDetected = readAssistantMcpDiscoveryMetadataAmbiguityDetected;
|
||||||
exports.formatIsoDateForReply = formatIsoDateForReply;
|
exports.formatIsoDateForReply = formatIsoDateForReply;
|
||||||
exports.readAddressDebugFilters = readAddressDebugFilters;
|
exports.readAddressDebugFilters = readAddressDebugFilters;
|
||||||
exports.readAddressDebugItem = readAddressDebugItem;
|
exports.readAddressDebugItem = readAddressDebugItem;
|
||||||
|
|
@ -75,15 +78,32 @@ function readAssistantMcpDiscoveryActionFamily(debug, toNonEmptyString = fallbac
|
||||||
function readAssistantMcpDiscoveryBridge(debug) {
|
function readAssistantMcpDiscoveryBridge(debug) {
|
||||||
return toRecordObject(readAssistantMcpDiscoveryEntry(debug)?.bridge);
|
return toRecordObject(readAssistantMcpDiscoveryEntry(debug)?.bridge);
|
||||||
}
|
}
|
||||||
|
function readAssistantMcpDiscoveryDerivedMetadataSurface(debug) {
|
||||||
|
const bridge = readAssistantMcpDiscoveryBridge(debug);
|
||||||
|
const pilot = toRecordObject(bridge?.pilot);
|
||||||
|
return toRecordObject(pilot?.derived_metadata_surface);
|
||||||
|
}
|
||||||
function readAssistantMcpDiscoveryPilotScope(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
function readAssistantMcpDiscoveryPilotScope(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
const bridge = readAssistantMcpDiscoveryBridge(debug);
|
const bridge = readAssistantMcpDiscoveryBridge(debug);
|
||||||
const pilot = toRecordObject(bridge?.pilot);
|
const pilot = toRecordObject(bridge?.pilot);
|
||||||
return toNonEmptyString(pilot?.pilot_scope);
|
return toNonEmptyString(pilot?.pilot_scope);
|
||||||
}
|
}
|
||||||
|
function readAssistantMcpDiscoveryMetadataRouteFamily(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
|
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.downstream_route_family);
|
||||||
|
}
|
||||||
|
function readAssistantMcpDiscoveryMetadataSelectedEntitySet(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
|
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.selected_entity_set);
|
||||||
|
}
|
||||||
|
function readAssistantMcpDiscoveryMetadataAmbiguityDetected(debug) {
|
||||||
|
return readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.ambiguity_detected === true;
|
||||||
|
}
|
||||||
function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(pilotScope, actionFamily) {
|
function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(pilotScope, actionFamily) {
|
||||||
if (pilotScope === "counterparty_lifecycle_query_documents_v1") {
|
if (pilotScope === "counterparty_lifecycle_query_documents_v1") {
|
||||||
return "counterparty_activity_lifecycle";
|
return "counterparty_activity_lifecycle";
|
||||||
}
|
}
|
||||||
|
if (pilotScope === "counterparty_document_evidence_query_documents_v1") {
|
||||||
|
return "list_documents_by_counterparty";
|
||||||
|
}
|
||||||
if (pilotScope === "counterparty_supplier_payout_query_movements_v1") {
|
if (pilotScope === "counterparty_supplier_payout_query_movements_v1") {
|
||||||
return "supplier_payouts_profile";
|
return "supplier_payouts_profile";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,9 @@ function isValueFlowPilot(pilot) {
|
||||||
pilot.pilot_scope === "counterparty_supplier_payout_query_movements_v1" ||
|
pilot.pilot_scope === "counterparty_supplier_payout_query_movements_v1" ||
|
||||||
pilot.pilot_scope === "counterparty_bidirectional_value_flow_query_movements_v1");
|
pilot.pilot_scope === "counterparty_bidirectional_value_flow_query_movements_v1");
|
||||||
}
|
}
|
||||||
|
function isDocumentPilot(pilot) {
|
||||||
|
return pilot.pilot_scope === "counterparty_document_evidence_query_documents_v1";
|
||||||
|
}
|
||||||
function isMetadataPilot(pilot) {
|
function isMetadataPilot(pilot) {
|
||||||
return pilot.pilot_scope === "metadata_inspection_v1";
|
return pilot.pilot_scope === "metadata_inspection_v1";
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +112,9 @@ function headlineFor(mode, pilot) {
|
||||||
}
|
}
|
||||||
return "По данным 1С найдены строки денежных движений; сумму можно называть только в рамках проверенного периода и найденных строк.";
|
return "По данным 1С найдены строки денежных движений; сумму можно называть только в рамках проверенного периода и найденных строк.";
|
||||||
}
|
}
|
||||||
|
if (isDocumentPilot(pilot) && mode === "confirmed_with_bounded_inference") {
|
||||||
|
return "По данным 1С найдены строки документов; ответ ограничен проверенным периодом и найденными строками.";
|
||||||
|
}
|
||||||
if (mode === "confirmed_with_bounded_inference") {
|
if (mode === "confirmed_with_bounded_inference") {
|
||||||
return "По данным 1С есть подтвержденная активность; длительность можно оценивать только как вывод из этих строк.";
|
return "По данным 1С есть подтвержденная активность; длительность можно оценивать только как вывод из этих строк.";
|
||||||
}
|
}
|
||||||
|
|
@ -158,6 +164,10 @@ function buildMustNotClaim(pilot) {
|
||||||
claims.push("Do not claim full all-time turnover unless the checked period and coverage prove it.");
|
claims.push("Do not claim full all-time turnover unless the checked period and coverage prove it.");
|
||||||
claims.push("Do not present a derived sum as a legal/accounting final total outside the checked 1C rows.");
|
claims.push("Do not present a derived sum as a legal/accounting final total outside the checked 1C rows.");
|
||||||
}
|
}
|
||||||
|
if (isDocumentPilot(pilot)) {
|
||||||
|
claims.push("Do not claim full document history outside the checked period.");
|
||||||
|
claims.push("Do not present the confirmed document rows as a complete document universe.");
|
||||||
|
}
|
||||||
if (isMetadataPilot(pilot)) {
|
if (isMetadataPilot(pilot)) {
|
||||||
claims.push("Do not present metadata surface as confirmed business data rows.");
|
claims.push("Do not present metadata surface as confirmed business data rows.");
|
||||||
claims.push("Do not claim a document/register exists outside the checked metadata probe results.");
|
claims.push("Do not claim a document/register exists outside the checked metadata probe results.");
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,15 @@ function isLifecyclePilotEligible(planner) {
|
||||||
return (planner.proposed_primitives.includes("query_documents") &&
|
return (planner.proposed_primitives.includes("query_documents") &&
|
||||||
(combined.includes("lifecycle") || combined.includes("activity") || combined.includes("duration") || combined.includes("age")));
|
(combined.includes("lifecycle") || combined.includes("activity") || combined.includes("duration") || combined.includes("age")));
|
||||||
}
|
}
|
||||||
|
function isDocumentEvidencePilotEligible(planner) {
|
||||||
|
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||||
|
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
||||||
|
const action = String(meaning?.asked_action_family ?? "").toLowerCase();
|
||||||
|
const unsupported = String(meaning?.unsupported_but_understood_family ?? "").toLowerCase();
|
||||||
|
const combined = `${domain} ${action} ${unsupported}`;
|
||||||
|
return (planner.proposed_primitives.includes("query_documents") &&
|
||||||
|
(combined.includes("document") || combined.includes("list_documents")));
|
||||||
|
}
|
||||||
function isValueFlowPilotEligible(planner) {
|
function isValueFlowPilotEligible(planner) {
|
||||||
const meaning = planner.discovery_plan.turn_meaning_ref;
|
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||||
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
||||||
|
|
@ -379,6 +388,15 @@ function summarizeLifecycleRows(result) {
|
||||||
}
|
}
|
||||||
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
||||||
}
|
}
|
||||||
|
function summarizeDocumentRows(result) {
|
||||||
|
if (result.error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (result.fetched_rows <= 0) {
|
||||||
|
return "0 MCP document rows fetched";
|
||||||
|
}
|
||||||
|
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched document scope`;
|
||||||
|
}
|
||||||
function summarizeValueFlowRows(result) {
|
function summarizeValueFlowRows(result) {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -953,6 +971,16 @@ function buildLifecycleConfirmedFacts(result, counterparty) {
|
||||||
: "1C activity rows were found for the requested counterparty scope"
|
: "1C activity rows were found for the requested counterparty scope"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
function buildDocumentConfirmedFacts(result, counterparty) {
|
||||||
|
if (result.error || result.matched_rows <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
counterparty
|
||||||
|
? `1C document rows were found for counterparty ${counterparty}`
|
||||||
|
: "1C document rows were found for the requested scope"
|
||||||
|
];
|
||||||
|
}
|
||||||
function buildValueFlowConfirmedFacts(result, counterparty, direction) {
|
function buildValueFlowConfirmedFacts(result, counterparty, direction) {
|
||||||
if (result.error || result.matched_rows <= 0) {
|
if (result.error || result.matched_rows <= 0) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -991,6 +1019,12 @@ function buildLifecycleInferredFacts(result) {
|
||||||
}
|
}
|
||||||
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
|
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
|
||||||
}
|
}
|
||||||
|
function buildDocumentInferredFacts(result) {
|
||||||
|
if (result.error || result.fetched_rows <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return ["Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"];
|
||||||
|
}
|
||||||
function buildValueFlowInferredFacts(derived) {
|
function buildValueFlowInferredFacts(derived) {
|
||||||
if (!derived) {
|
if (!derived) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -1026,6 +1060,13 @@ function buildBidirectionalValueFlowInferredFacts(derived) {
|
||||||
function buildLifecycleUnknownFacts() {
|
function buildLifecycleUnknownFacts() {
|
||||||
return ["Legal registration date is not proven by this MCP discovery pilot"];
|
return ["Legal registration date is not proven by this MCP discovery pilot"];
|
||||||
}
|
}
|
||||||
|
function buildDocumentUnknownFacts(periodScope) {
|
||||||
|
return [
|
||||||
|
periodScope
|
||||||
|
? "Full document history outside the checked period is not proven by this MCP discovery pilot"
|
||||||
|
: "Full document history is not proven without an explicit checked period"
|
||||||
|
];
|
||||||
|
}
|
||||||
function buildValueFlowUnknownFacts(periodScope, direction, derived) {
|
function buildValueFlowUnknownFacts(periodScope, direction, derived) {
|
||||||
const unknownFacts = [];
|
const unknownFacts = [];
|
||||||
if (derived?.coverage_limited_by_probe_limit) {
|
if (derived?.coverage_limited_by_probe_limit) {
|
||||||
|
|
@ -1068,6 +1109,9 @@ function pilotScopeForPlanner(planner) {
|
||||||
if (isValueFlowPilotEligible(planner)) {
|
if (isValueFlowPilotEligible(planner)) {
|
||||||
return valueFlowPilotProfile(planner).scope;
|
return valueFlowPilotProfile(planner).scope;
|
||||||
}
|
}
|
||||||
|
if (isDocumentEvidencePilotEligible(planner)) {
|
||||||
|
return "counterparty_document_evidence_query_documents_v1";
|
||||||
|
}
|
||||||
return "counterparty_lifecycle_query_documents_v1";
|
return "counterparty_lifecycle_query_documents_v1";
|
||||||
}
|
}
|
||||||
async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||||
|
|
@ -1129,9 +1173,10 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const metadataPilotEligible = isMetadataPilotEligible(planner);
|
const metadataPilotEligible = isMetadataPilotEligible(planner);
|
||||||
|
const documentPilotEligible = isDocumentEvidencePilotEligible(planner);
|
||||||
const lifecyclePilotEligible = isLifecyclePilotEligible(planner);
|
const lifecyclePilotEligible = isLifecyclePilotEligible(planner);
|
||||||
const valueFlowPilotEligible = isValueFlowPilotEligible(planner);
|
const valueFlowPilotEligible = isValueFlowPilotEligible(planner);
|
||||||
if (!metadataPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
if (!metadataPilotEligible && !documentPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
||||||
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
|
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
|
||||||
for (const step of dryRun.execution_steps) {
|
for (const step of dryRun.execution_steps) {
|
||||||
skippedPrimitives.push(step.primitive_id);
|
skippedPrimitives.push(step.primitive_id);
|
||||||
|
|
@ -1221,6 +1266,86 @@ async function executeAssistantMcpDiscoveryPilot(planner, deps = DEFAULT_DEPS) {
|
||||||
reason_codes: reasonCodes
|
reason_codes: reasonCodes
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (documentPilotEligible) {
|
||||||
|
let queryResult = null;
|
||||||
|
const filters = buildLifecycleFilters(planner);
|
||||||
|
const selection = (0, addressRecipeCatalog_1.selectAddressRecipe)("list_documents_by_counterparty", filters);
|
||||||
|
if (!selection.selected_recipe) {
|
||||||
|
pushReason(reasonCodes, "pilot_document_recipe_not_available");
|
||||||
|
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "Document-evidence recipe is not available");
|
||||||
|
return {
|
||||||
|
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
|
||||||
|
policy_owner: "assistantMcpDiscoveryPilotExecutor",
|
||||||
|
pilot_status: "unsupported",
|
||||||
|
pilot_scope: "counterparty_document_evidence_query_documents_v1",
|
||||||
|
dry_run: dryRun,
|
||||||
|
mcp_execution_performed: false,
|
||||||
|
executed_primitives: executedPrimitives,
|
||||||
|
skipped_primitives: skippedPrimitives,
|
||||||
|
probe_results: probeResults,
|
||||||
|
evidence,
|
||||||
|
source_rows_summary: null,
|
||||||
|
derived_metadata_surface: null,
|
||||||
|
derived_activity_period: null,
|
||||||
|
derived_value_flow: null,
|
||||||
|
derived_bidirectional_value_flow: null,
|
||||||
|
query_limitations: ["Document-evidence recipe is not available"],
|
||||||
|
reason_codes: reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const recipePlan = (0, addressRecipeCatalog_1.buildAddressRecipePlan)(selection.selected_recipe, filters);
|
||||||
|
for (const step of dryRun.execution_steps) {
|
||||||
|
if (step.primitive_id !== "query_documents") {
|
||||||
|
skippedPrimitives.push(step.primitive_id);
|
||||||
|
probeResults.push(skippedProbeResult(step, "pilot_only_executes_query_documents"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
queryResult = await runtimeDeps.executeAddressMcpQuery({
|
||||||
|
query: recipePlan.query,
|
||||||
|
limit: recipePlan.limit,
|
||||||
|
account_scope: recipePlan.account_scope
|
||||||
|
});
|
||||||
|
executedPrimitives.push(step.primitive_id);
|
||||||
|
probeResults.push(queryResultToProbeResult(step.primitive_id, queryResult));
|
||||||
|
if (queryResult.error) {
|
||||||
|
pushUnique(queryLimitations, queryResult.error);
|
||||||
|
pushReason(reasonCodes, "pilot_query_documents_mcp_error");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pushReason(reasonCodes, "pilot_query_documents_mcp_executed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const sourceRowsSummary = queryResult ? summarizeDocumentRows(queryResult) : null;
|
||||||
|
const evidence = (0, assistantMcpDiscoveryPolicy_1.resolveAssistantMcpDiscoveryEvidence)({
|
||||||
|
plan: planner.discovery_plan,
|
||||||
|
probeResults,
|
||||||
|
confirmedFacts: queryResult ? buildDocumentConfirmedFacts(queryResult, counterparty) : [],
|
||||||
|
inferredFacts: queryResult ? buildDocumentInferredFacts(queryResult) : [],
|
||||||
|
unknownFacts: buildDocumentUnknownFacts(dateScope),
|
||||||
|
sourceRowsSummary,
|
||||||
|
queryLimitations,
|
||||||
|
recommendedNextProbe: "explain_evidence_basis"
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
schema_version: exports.ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
|
||||||
|
policy_owner: "assistantMcpDiscoveryPilotExecutor",
|
||||||
|
pilot_status: "executed",
|
||||||
|
pilot_scope: "counterparty_document_evidence_query_documents_v1",
|
||||||
|
dry_run: dryRun,
|
||||||
|
mcp_execution_performed: executedPrimitives.length > 0,
|
||||||
|
executed_primitives: executedPrimitives,
|
||||||
|
skipped_primitives: skippedPrimitives,
|
||||||
|
probe_results: probeResults,
|
||||||
|
evidence,
|
||||||
|
source_rows_summary: sourceRowsSummary,
|
||||||
|
derived_metadata_surface: null,
|
||||||
|
derived_activity_period: null,
|
||||||
|
derived_value_flow: null,
|
||||||
|
derived_bidirectional_value_flow: null,
|
||||||
|
query_limitations: queryLimitations,
|
||||||
|
reason_codes: reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
if (valueFlowPilotEligible) {
|
if (valueFlowPilotEligible) {
|
||||||
let queryResult = null;
|
let queryResult = null;
|
||||||
const filters = buildValueFlowFilters(planner);
|
const filters = buildValueFlowFilters(planner);
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,13 @@ function localizeLine(value) {
|
||||||
if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) {
|
if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) {
|
||||||
return "В 1С найдены строки денежных движений по запрошенному контрагентскому контуру.";
|
return "В 1С найдены строки денежных движений по запрошенному контрагентскому контуру.";
|
||||||
}
|
}
|
||||||
|
const documentRowsMatch = value.match(/^1C document rows were found for counterparty\s+(.+)$/i);
|
||||||
|
if (documentRowsMatch) {
|
||||||
|
return `В 1С найдены строки документов по контрагенту ${documentRowsMatch[1]}.`;
|
||||||
|
}
|
||||||
|
if (/^1C document rows were found for the requested scope$/i.test(value)) {
|
||||||
|
return "В 1С найдены строки документов по запрошенному контуру.";
|
||||||
|
}
|
||||||
const supplierPayoutMatch = value.match(/^1C supplier-payout rows were found for counterparty\s+(.+)$/i);
|
const supplierPayoutMatch = value.match(/^1C supplier-payout rows were found for counterparty\s+(.+)$/i);
|
||||||
if (supplierPayoutMatch) {
|
if (supplierPayoutMatch) {
|
||||||
return `В 1С найдены строки исходящих платежей/списаний по контрагенту ${supplierPayoutMatch[1]}.`;
|
return `В 1С найдены строки исходящих платежей/списаний по контрагенту ${supplierPayoutMatch[1]}.`;
|
||||||
|
|
@ -97,6 +104,9 @@ function localizeLine(value) {
|
||||||
if (/^Business activity duration may be inferred from first and latest confirmed 1C activity rows$/i.test(value)) {
|
if (/^Business activity duration may be inferred from first and latest confirmed 1C activity rows$/i.test(value)) {
|
||||||
return "Длительность деловой активности можно оценивать только как вывод по первой и последней подтвержденной строке активности в 1С.";
|
return "Длительность деловой активности можно оценивать только как вывод по первой и последней подтвержденной строке активности в 1С.";
|
||||||
}
|
}
|
||||||
|
if (/^Counterparty document evidence is limited to confirmed 1C document rows in the checked scope$/i.test(value)) {
|
||||||
|
return "Срез документов ограничен только подтвержденными строками документов в проверенном окне.";
|
||||||
|
}
|
||||||
if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) {
|
if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) {
|
||||||
return "Сумма рассчитана только по подтвержденным строкам денежных движений в 1С.";
|
return "Сумма рассчитана только по подтвержденным строкам денежных движений в 1С.";
|
||||||
}
|
}
|
||||||
|
|
@ -171,6 +181,12 @@ function localizeLine(value) {
|
||||||
if (/^Full all-time turnover is not proven without an explicit checked period$/i.test(value)) {
|
if (/^Full all-time turnover is not proven without an explicit checked period$/i.test(value)) {
|
||||||
return "Полный оборот за все время без явно проверенного периода не подтвержден.";
|
return "Полный оборот за все время без явно проверенного периода не подтвержден.";
|
||||||
}
|
}
|
||||||
|
if (/^Full document history outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||||
|
return "Полный исторический срез документов вне проверенного периода этим поиском не подтвержден.";
|
||||||
|
}
|
||||||
|
if (/^Full document history is not proven without an explicit checked period$/i.test(value)) {
|
||||||
|
return "Полный срез документов без явно проверенного периода не подтвержден.";
|
||||||
|
}
|
||||||
if (/^Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
if (/^Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||||
return "Полный объем исходящих платежей вне проверенного периода этим поиском не подтвержден.";
|
return "Полный объем исходящих платежей вне проверенного периода этим поиском не подтвержден.";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,10 @@ function collectFollowupDiscoverySeed(followupContext) {
|
||||||
counterparty,
|
counterparty,
|
||||||
discoveryEntity: discoveryEntities[0] ?? null,
|
discoveryEntity: discoveryEntities[0] ?? null,
|
||||||
organization,
|
organization,
|
||||||
dateScope
|
dateScope,
|
||||||
|
metadataRouteFamily: toNonEmptyString(followupContext?.previous_discovery_metadata_route_family),
|
||||||
|
metadataSelectedEntitySet: toNonEmptyString(followupContext?.previous_discovery_metadata_selected_entity_set),
|
||||||
|
metadataAmbiguityDetected: followupContext?.previous_discovery_metadata_ambiguity_detected === true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function hasLifecycleSignal(text) {
|
function hasLifecycleSignal(text) {
|
||||||
|
|
@ -239,6 +242,9 @@ function hasMetadataSignal(text) {
|
||||||
function hasMetadataObjectHint(text) {
|
function hasMetadataObjectHint(text) {
|
||||||
return /(?:\u0440\u0435\u0433\u0438\u0441\u0442\u0440(?:\u044b)?|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a(?:\u0438)?|\u043f\u043e\u043b(?:\u0435|\u044f)|registers?|documents?|catalogs?|fields?)/iu.test(text);
|
return /(?:\u0440\u0435\u0433\u0438\u0441\u0442\u0440(?:\u044b)?|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a(?:\u0438)?|\u043f\u043e\u043b(?:\u0435|\u044f)|registers?|documents?|catalogs?|fields?)/iu.test(text);
|
||||||
}
|
}
|
||||||
|
function hasDocumentEvidenceFollowupSignal(text) {
|
||||||
|
return /(?:\u043f\u043e\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u0430\u043c|\u044b)?|\u0434\u0430\u0432\u0430\u0439\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0438\u0449\u0438\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u043f\u043e\u043a\u0430\u0436\u0438\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|document(?:s)?\s+(?:then|next)?|(?:then|next)\s+documents?|go\s+to\s+documents?)/iu.test(text);
|
||||||
|
}
|
||||||
function metadataActionFromRawText(text) {
|
function metadataActionFromRawText(text) {
|
||||||
if (/(?:\u043f\u043e\u043b(?:\u0435|\u044f)|field)/iu.test(text)) {
|
if (/(?:\u043f\u043e\u043b(?:\u0435|\u044f)|field)/iu.test(text)) {
|
||||||
return "inspect_fields";
|
return "inspect_fields";
|
||||||
|
|
@ -338,9 +344,29 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
hasMetadataObjectHint(rawText));
|
hasMetadataObjectHint(rawText));
|
||||||
const seededDomain = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.domain : null;
|
const metadataGroundedDocumentFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
const seededAction = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.action : null;
|
followupSeed.metadataRouteFamily === "document_evidence" &&
|
||||||
const seededUnsupported = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.unsupported : null;
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
|
followupSeed.counterparty &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
hasDocumentEvidenceFollowupSignal(rawText));
|
||||||
|
const effectiveMetadataFollowupSeedApplicable = metadataFollowupSeedApplicable && !metadataGroundedDocumentFollowupApplicable;
|
||||||
|
const seededDomain = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "documents"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.domain
|
||||||
|
: null;
|
||||||
|
const seededAction = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "list_documents"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.action
|
||||||
|
: null;
|
||||||
|
const seededUnsupported = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "document_evidence"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.unsupported
|
||||||
|
: null;
|
||||||
const lifecycleSignal = rawLifecycleSignal || seededDomain === "counterparty_lifecycle";
|
const lifecycleSignal = rawLifecycleSignal || seededDomain === "counterparty_lifecycle";
|
||||||
const bidirectionalValueFlowSignal = !lifecycleSignal &&
|
const bidirectionalValueFlowSignal = !lifecycleSignal &&
|
||||||
(rawBidirectionalValueFlowSignal || seededAction === "net_value_flow");
|
(rawBidirectionalValueFlowSignal || seededAction === "net_value_flow");
|
||||||
|
|
@ -354,7 +380,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
unsupported: unsupported ?? seededUnsupported,
|
unsupported: unsupported ?? seededUnsupported,
|
||||||
lifecycleSignal,
|
lifecycleSignal,
|
||||||
valueFlowSignal,
|
valueFlowSignal,
|
||||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable
|
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
});
|
});
|
||||||
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
||||||
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
||||||
|
|
@ -375,7 +401,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
? "counterparty_lifecycle"
|
? "counterparty_lifecycle"
|
||||||
: valueFlowSignal
|
: valueFlowSignal
|
||||||
? "counterparty_value"
|
? "counterparty_value"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "documents"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "metadata"
|
? "metadata"
|
||||||
: rawDomain ?? seededDomain,
|
: rawDomain ?? seededDomain,
|
||||||
asked_action_family: lifecycleSignal
|
asked_action_family: lifecycleSignal
|
||||||
|
|
@ -386,7 +414,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
: payoutSignal
|
: payoutSignal
|
||||||
? "payout"
|
? "payout"
|
||||||
: rawAction ?? seededAction ?? "turnover"
|
: rawAction ?? seededAction ?? "turnover"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "list_documents"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? metadataActionFromRawText(rawText) ?? seededAction
|
? metadataActionFromRawText(rawText) ?? seededAction
|
||||||
: rawAction ?? seededAction,
|
: rawAction ?? seededAction,
|
||||||
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
||||||
|
|
@ -402,7 +432,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
: payoutSignal
|
: payoutSignal
|
||||||
? "counterparty_payouts_or_outflow"
|
? "counterparty_payouts_or_outflow"
|
||||||
: seededUnsupported ?? "counterparty_value_or_turnover"
|
: seededUnsupported ?? "counterparty_value_or_turnover"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "document_evidence"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "1c_metadata_surface"
|
? "1c_metadata_surface"
|
||||||
: followupDiscoverySeedApplicable
|
: followupDiscoverySeedApplicable
|
||||||
? seededUnsupported
|
? seededUnsupported
|
||||||
|
|
@ -411,8 +443,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
unsupported ||
|
unsupported ||
|
||||||
lifecycleSignal ||
|
lifecycleSignal ||
|
||||||
valueFlowSignal ||
|
valueFlowSignal ||
|
||||||
|
metadataGroundedDocumentFollowupApplicable ||
|
||||||
rawMetadataSignal ||
|
rawMetadataSignal ||
|
||||||
metadataFollowupSeedApplicable ||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
followupDiscoverySeedApplicable)
|
followupDiscoverySeedApplicable)
|
||||||
};
|
};
|
||||||
const cleanTurnMeaning = {};
|
const cleanTurnMeaning = {};
|
||||||
|
|
@ -444,15 +477,19 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
unsupported: unsupported ?? seededUnsupported,
|
unsupported: unsupported ?? seededUnsupported,
|
||||||
lifecycleSignal,
|
lifecycleSignal,
|
||||||
valueFlowSignal,
|
valueFlowSignal,
|
||||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable,
|
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable,
|
||||||
semanticDataNeed,
|
semanticDataNeed,
|
||||||
explicitIntentCandidate,
|
explicitIntentCandidate,
|
||||||
followupDiscoverySeedApplicable: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
followupDiscoverySeedApplicable: followupDiscoverySeedApplicable ||
|
||||||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
|
metadataGroundedDocumentFollowupApplicable
|
||||||
});
|
});
|
||||||
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
||||||
const sourceSignal = assistantTurnMeaning
|
const sourceSignal = assistantTurnMeaning
|
||||||
? "assistant_turn_meaning"
|
? "assistant_turn_meaning"
|
||||||
: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? "followup_context"
|
||||||
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
? "followup_context"
|
? "followup_context"
|
||||||
: predecomposeContract
|
: predecomposeContract
|
||||||
? "predecompose_contract"
|
? "predecompose_contract"
|
||||||
|
|
@ -460,7 +497,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: valueFlowSignal
|
: valueFlowSignal
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: "none";
|
: "none";
|
||||||
if (lifecycleSignal) {
|
if (lifecycleSignal) {
|
||||||
|
|
@ -484,9 +521,12 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
if (followupDiscoverySeedApplicable) {
|
if (followupDiscoverySeedApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_seeded_from_followup_context");
|
pushReason(reasonCodes, "mcp_discovery_seeded_from_followup_context");
|
||||||
}
|
}
|
||||||
if (metadataFollowupSeedApplicable) {
|
if (effectiveMetadataFollowupSeedApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_metadata_seeded_from_followup_context");
|
pushReason(reasonCodes, "mcp_discovery_metadata_seeded_from_followup_context");
|
||||||
}
|
}
|
||||||
|
if (metadataGroundedDocumentFollowupApplicable) {
|
||||||
|
pushReason(reasonCodes, "mcp_discovery_metadata_grounded_document_followup");
|
||||||
|
}
|
||||||
if (unsupported) {
|
if (unsupported) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -463,6 +463,9 @@ function createAssistantTransitionPolicy(deps) {
|
||||||
}
|
}
|
||||||
const sourceIntent = (0, assistantContinuityPolicy_1.readAddressDebugIntent)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceIntent = (0, assistantContinuityPolicy_1.readAddressDebugIntent)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const sourceDiscoveryPilotScope = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryPilotScope)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryPilotScope = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryPilotScope)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryMetadataRouteFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryMetadataRouteFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryMetadataSelectedEntitySet = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryMetadataSelectedEntitySet)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryMetadataAmbiguityDetected = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryMetadataAmbiguityDetected)(carryoverSourceDebug);
|
||||||
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
||||||
const llmSelectedObjectScopeDetected = llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true;
|
const llmSelectedObjectScopeDetected = llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true;
|
||||||
const resolvedPrimaryIntent = deps.resolveAddressIntent(deps.repairAddressMojibake(String(userMessage ?? ""))).intent;
|
const resolvedPrimaryIntent = deps.resolveAddressIntent(deps.repairAddressMojibake(String(userMessage ?? ""))).intent;
|
||||||
|
|
@ -693,6 +696,9 @@ function createAssistantTransitionPolicy(deps) {
|
||||||
previous_anchor_type: previousAnchorType ?? undefined,
|
previous_anchor_type: previousAnchorType ?? undefined,
|
||||||
previous_anchor_value: previousAnchor,
|
previous_anchor_value: previousAnchor,
|
||||||
previous_discovery_pilot_scope: sourceDiscoveryPilotScope ?? undefined,
|
previous_discovery_pilot_scope: sourceDiscoveryPilotScope ?? undefined,
|
||||||
|
previous_discovery_metadata_route_family: sourceDiscoveryMetadataRouteFamily ?? undefined,
|
||||||
|
previous_discovery_metadata_selected_entity_set: sourceDiscoveryMetadataSelectedEntitySet ?? undefined,
|
||||||
|
previous_discovery_metadata_ambiguity_detected: sourceDiscoveryMetadataAmbiguityDetected || undefined,
|
||||||
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
|
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
|
||||||
root_context_only: rootScopedPivot || undefined,
|
root_context_only: rootScopedPivot || undefined,
|
||||||
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,
|
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,14 @@ function readAssistantMcpDiscoveryBridge(
|
||||||
return toRecordObject(readAssistantMcpDiscoveryEntry(debug)?.bridge);
|
return toRecordObject(readAssistantMcpDiscoveryEntry(debug)?.bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readAssistantMcpDiscoveryDerivedMetadataSurface(
|
||||||
|
debug: Record<string, unknown> | null
|
||||||
|
): Record<string, unknown> | null {
|
||||||
|
const bridge = readAssistantMcpDiscoveryBridge(debug);
|
||||||
|
const pilot = toRecordObject(bridge?.pilot);
|
||||||
|
return toRecordObject(pilot?.derived_metadata_surface);
|
||||||
|
}
|
||||||
|
|
||||||
export function readAssistantMcpDiscoveryPilotScope(
|
export function readAssistantMcpDiscoveryPilotScope(
|
||||||
debug: Record<string, unknown> | null,
|
debug: Record<string, unknown> | null,
|
||||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||||
|
|
@ -164,6 +172,26 @@ export function readAssistantMcpDiscoveryPilotScope(
|
||||||
return toNonEmptyString(pilot?.pilot_scope);
|
return toNonEmptyString(pilot?.pilot_scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readAssistantMcpDiscoveryMetadataRouteFamily(
|
||||||
|
debug: Record<string, unknown> | null,
|
||||||
|
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||||
|
): string | null {
|
||||||
|
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.downstream_route_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readAssistantMcpDiscoveryMetadataSelectedEntitySet(
|
||||||
|
debug: Record<string, unknown> | null,
|
||||||
|
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||||
|
): string | null {
|
||||||
|
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.selected_entity_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readAssistantMcpDiscoveryMetadataAmbiguityDetected(
|
||||||
|
debug: Record<string, unknown> | null
|
||||||
|
): boolean {
|
||||||
|
return readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.ambiguity_detected === true;
|
||||||
|
}
|
||||||
|
|
||||||
function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(
|
function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(
|
||||||
pilotScope: string | null,
|
pilotScope: string | null,
|
||||||
actionFamily: string | null
|
actionFamily: string | null
|
||||||
|
|
@ -171,6 +199,9 @@ function mapAssistantMcpDiscoveryPilotScopeToAddressIntent(
|
||||||
if (pilotScope === "counterparty_lifecycle_query_documents_v1") {
|
if (pilotScope === "counterparty_lifecycle_query_documents_v1") {
|
||||||
return "counterparty_activity_lifecycle";
|
return "counterparty_activity_lifecycle";
|
||||||
}
|
}
|
||||||
|
if (pilotScope === "counterparty_document_evidence_query_documents_v1") {
|
||||||
|
return "list_documents_by_counterparty";
|
||||||
|
}
|
||||||
if (pilotScope === "counterparty_supplier_payout_query_movements_v1") {
|
if (pilotScope === "counterparty_supplier_payout_query_movements_v1") {
|
||||||
return "supplier_payouts_profile";
|
return "supplier_payouts_profile";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,10 @@ function isValueFlowPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): b
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDocumentPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
||||||
|
return pilot.pilot_scope === "counterparty_document_evidence_query_documents_v1";
|
||||||
|
}
|
||||||
|
|
||||||
function isMetadataPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
function isMetadataPilot(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
||||||
return pilot.pilot_scope === "metadata_inspection_v1";
|
return pilot.pilot_scope === "metadata_inspection_v1";
|
||||||
}
|
}
|
||||||
|
|
@ -147,6 +151,9 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
|
||||||
}
|
}
|
||||||
return "По данным 1С найдены строки денежных движений; сумму можно называть только в рамках проверенного периода и найденных строк.";
|
return "По данным 1С найдены строки денежных движений; сумму можно называть только в рамках проверенного периода и найденных строк.";
|
||||||
}
|
}
|
||||||
|
if (isDocumentPilot(pilot) && mode === "confirmed_with_bounded_inference") {
|
||||||
|
return "По данным 1С найдены строки документов; ответ ограничен проверенным периодом и найденными строками.";
|
||||||
|
}
|
||||||
if (mode === "confirmed_with_bounded_inference") {
|
if (mode === "confirmed_with_bounded_inference") {
|
||||||
return "По данным 1С есть подтвержденная активность; длительность можно оценивать только как вывод из этих строк.";
|
return "По данным 1С есть подтвержденная активность; длительность можно оценивать только как вывод из этих строк.";
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +205,10 @@ function buildMustNotClaim(pilot: AssistantMcpDiscoveryPilotExecutionContract):
|
||||||
claims.push("Do not claim full all-time turnover unless the checked period and coverage prove it.");
|
claims.push("Do not claim full all-time turnover unless the checked period and coverage prove it.");
|
||||||
claims.push("Do not present a derived sum as a legal/accounting final total outside the checked 1C rows.");
|
claims.push("Do not present a derived sum as a legal/accounting final total outside the checked 1C rows.");
|
||||||
}
|
}
|
||||||
|
if (isDocumentPilot(pilot)) {
|
||||||
|
claims.push("Do not claim full document history outside the checked period.");
|
||||||
|
claims.push("Do not present the confirmed document rows as a complete document universe.");
|
||||||
|
}
|
||||||
if (isMetadataPilot(pilot)) {
|
if (isMetadataPilot(pilot)) {
|
||||||
claims.push("Do not present metadata surface as confirmed business data rows.");
|
claims.push("Do not present metadata surface as confirmed business data rows.");
|
||||||
claims.push("Do not claim a document/register exists outside the checked metadata probe results.");
|
claims.push("Do not claim a document/register exists outside the checked metadata probe results.");
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ interface AssistantMcpDiscoveryCoverageAwareQueryExecution {
|
||||||
|
|
||||||
export type AssistantMcpDiscoveryPilotScope =
|
export type AssistantMcpDiscoveryPilotScope =
|
||||||
| "metadata_inspection_v1"
|
| "metadata_inspection_v1"
|
||||||
|
| "counterparty_document_evidence_query_documents_v1"
|
||||||
| "counterparty_lifecycle_query_documents_v1"
|
| "counterparty_lifecycle_query_documents_v1"
|
||||||
| "counterparty_value_flow_query_movements_v1"
|
| "counterparty_value_flow_query_movements_v1"
|
||||||
| "counterparty_supplier_payout_query_movements_v1"
|
| "counterparty_supplier_payout_query_movements_v1"
|
||||||
|
|
@ -291,6 +292,18 @@ function isLifecyclePilotEligible(planner: AssistantMcpDiscoveryPlannerContract)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDocumentEvidencePilotEligible(planner: AssistantMcpDiscoveryPlannerContract): boolean {
|
||||||
|
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||||
|
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
||||||
|
const action = String(meaning?.asked_action_family ?? "").toLowerCase();
|
||||||
|
const unsupported = String(meaning?.unsupported_but_understood_family ?? "").toLowerCase();
|
||||||
|
const combined = `${domain} ${action} ${unsupported}`;
|
||||||
|
return (
|
||||||
|
planner.proposed_primitives.includes("query_documents") &&
|
||||||
|
(combined.includes("document") || combined.includes("list_documents"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function isValueFlowPilotEligible(planner: AssistantMcpDiscoveryPlannerContract): boolean {
|
function isValueFlowPilotEligible(planner: AssistantMcpDiscoveryPlannerContract): boolean {
|
||||||
const meaning = planner.discovery_plan.turn_meaning_ref;
|
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||||
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
||||||
|
|
@ -641,6 +654,16 @@ function summarizeLifecycleRows(result: AddressMcpQueryExecutorResult): string |
|
||||||
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched lifecycle scope`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function summarizeDocumentRows(result: AddressMcpQueryExecutorResult): string | null {
|
||||||
|
if (result.error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (result.fetched_rows <= 0) {
|
||||||
|
return "0 MCP document rows fetched";
|
||||||
|
}
|
||||||
|
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched document scope`;
|
||||||
|
}
|
||||||
|
|
||||||
function summarizeValueFlowRows(result: AssistantMcpDiscoveryCoverageAwareQueryResult): string | null {
|
function summarizeValueFlowRows(result: AssistantMcpDiscoveryCoverageAwareQueryResult): string | null {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -1310,6 +1333,17 @@ function buildLifecycleConfirmedFacts(result: AddressMcpQueryExecutorResult, cou
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDocumentConfirmedFacts(result: AddressMcpQueryExecutorResult, counterparty: string | null): string[] {
|
||||||
|
if (result.error || result.matched_rows <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
counterparty
|
||||||
|
? `1C document rows were found for counterparty ${counterparty}`
|
||||||
|
: "1C document rows were found for the requested scope"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function buildValueFlowConfirmedFacts(
|
function buildValueFlowConfirmedFacts(
|
||||||
result: AssistantMcpDiscoveryCoverageAwareQueryResult,
|
result: AssistantMcpDiscoveryCoverageAwareQueryResult,
|
||||||
counterparty: string | null,
|
counterparty: string | null,
|
||||||
|
|
@ -1357,6 +1391,13 @@ function buildLifecycleInferredFacts(result: AddressMcpQueryExecutorResult): str
|
||||||
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
|
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDocumentInferredFacts(result: AddressMcpQueryExecutorResult): string[] {
|
||||||
|
if (result.error || result.fetched_rows <= 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return ["Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"];
|
||||||
|
}
|
||||||
|
|
||||||
function buildValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerivedValueFlow | null): string[] {
|
function buildValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerivedValueFlow | null): string[] {
|
||||||
if (!derived) {
|
if (!derived) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -1400,6 +1441,14 @@ function buildLifecycleUnknownFacts(): string[] {
|
||||||
return ["Legal registration date is not proven by this MCP discovery pilot"];
|
return ["Legal registration date is not proven by this MCP discovery pilot"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildDocumentUnknownFacts(periodScope: string | null): string[] {
|
||||||
|
return [
|
||||||
|
periodScope
|
||||||
|
? "Full document history outside the checked period is not proven by this MCP discovery pilot"
|
||||||
|
: "Full document history is not proven without an explicit checked period"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
function buildValueFlowUnknownFacts(
|
function buildValueFlowUnknownFacts(
|
||||||
periodScope: string | null,
|
periodScope: string | null,
|
||||||
direction: AssistantMcpDiscoveryDerivedValueFlow["value_flow_direction"],
|
direction: AssistantMcpDiscoveryDerivedValueFlow["value_flow_direction"],
|
||||||
|
|
@ -1465,6 +1514,9 @@ function pilotScopeForPlanner(planner: AssistantMcpDiscoveryPlannerContract): As
|
||||||
if (isValueFlowPilotEligible(planner)) {
|
if (isValueFlowPilotEligible(planner)) {
|
||||||
return valueFlowPilotProfile(planner).scope;
|
return valueFlowPilotProfile(planner).scope;
|
||||||
}
|
}
|
||||||
|
if (isDocumentEvidencePilotEligible(planner)) {
|
||||||
|
return "counterparty_document_evidence_query_documents_v1";
|
||||||
|
}
|
||||||
return "counterparty_lifecycle_query_documents_v1";
|
return "counterparty_lifecycle_query_documents_v1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1533,10 +1585,11 @@ export async function executeAssistantMcpDiscoveryPilot(
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadataPilotEligible = isMetadataPilotEligible(planner);
|
const metadataPilotEligible = isMetadataPilotEligible(planner);
|
||||||
|
const documentPilotEligible = isDocumentEvidencePilotEligible(planner);
|
||||||
const lifecyclePilotEligible = isLifecyclePilotEligible(planner);
|
const lifecyclePilotEligible = isLifecyclePilotEligible(planner);
|
||||||
const valueFlowPilotEligible = isValueFlowPilotEligible(planner);
|
const valueFlowPilotEligible = isValueFlowPilotEligible(planner);
|
||||||
|
|
||||||
if (!metadataPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
if (!metadataPilotEligible && !documentPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
||||||
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
|
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
|
||||||
for (const step of dryRun.execution_steps) {
|
for (const step of dryRun.execution_steps) {
|
||||||
skippedPrimitives.push(step.primitive_id);
|
skippedPrimitives.push(step.primitive_id);
|
||||||
|
|
@ -1631,6 +1684,89 @@ export async function executeAssistantMcpDiscoveryPilot(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (documentPilotEligible) {
|
||||||
|
let queryResult: AddressMcpQueryExecutorResult | null = null;
|
||||||
|
const filters = buildLifecycleFilters(planner);
|
||||||
|
const selection = selectAddressRecipe("list_documents_by_counterparty", filters);
|
||||||
|
if (!selection.selected_recipe) {
|
||||||
|
pushReason(reasonCodes, "pilot_document_recipe_not_available");
|
||||||
|
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "Document-evidence recipe is not available");
|
||||||
|
return {
|
||||||
|
schema_version: ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
|
||||||
|
policy_owner: "assistantMcpDiscoveryPilotExecutor",
|
||||||
|
pilot_status: "unsupported",
|
||||||
|
pilot_scope: "counterparty_document_evidence_query_documents_v1",
|
||||||
|
dry_run: dryRun,
|
||||||
|
mcp_execution_performed: false,
|
||||||
|
executed_primitives: executedPrimitives,
|
||||||
|
skipped_primitives: skippedPrimitives,
|
||||||
|
probe_results: probeResults,
|
||||||
|
evidence,
|
||||||
|
source_rows_summary: null,
|
||||||
|
derived_metadata_surface: null,
|
||||||
|
derived_activity_period: null,
|
||||||
|
derived_value_flow: null,
|
||||||
|
derived_bidirectional_value_flow: null,
|
||||||
|
query_limitations: ["Document-evidence recipe is not available"],
|
||||||
|
reason_codes: reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipePlan = buildAddressRecipePlan(selection.selected_recipe, filters);
|
||||||
|
for (const step of dryRun.execution_steps) {
|
||||||
|
if (step.primitive_id !== "query_documents") {
|
||||||
|
skippedPrimitives.push(step.primitive_id);
|
||||||
|
probeResults.push(skippedProbeResult(step, "pilot_only_executes_query_documents"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
queryResult = await runtimeDeps.executeAddressMcpQuery({
|
||||||
|
query: recipePlan.query,
|
||||||
|
limit: recipePlan.limit,
|
||||||
|
account_scope: recipePlan.account_scope
|
||||||
|
});
|
||||||
|
executedPrimitives.push(step.primitive_id);
|
||||||
|
probeResults.push(queryResultToProbeResult(step.primitive_id, queryResult));
|
||||||
|
if (queryResult.error) {
|
||||||
|
pushUnique(queryLimitations, queryResult.error);
|
||||||
|
pushReason(reasonCodes, "pilot_query_documents_mcp_error");
|
||||||
|
} else {
|
||||||
|
pushReason(reasonCodes, "pilot_query_documents_mcp_executed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceRowsSummary = queryResult ? summarizeDocumentRows(queryResult) : null;
|
||||||
|
const evidence = resolveAssistantMcpDiscoveryEvidence({
|
||||||
|
plan: planner.discovery_plan,
|
||||||
|
probeResults,
|
||||||
|
confirmedFacts: queryResult ? buildDocumentConfirmedFacts(queryResult, counterparty) : [],
|
||||||
|
inferredFacts: queryResult ? buildDocumentInferredFacts(queryResult) : [],
|
||||||
|
unknownFacts: buildDocumentUnknownFacts(dateScope),
|
||||||
|
sourceRowsSummary,
|
||||||
|
queryLimitations,
|
||||||
|
recommendedNextProbe: "explain_evidence_basis"
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
schema_version: ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
|
||||||
|
policy_owner: "assistantMcpDiscoveryPilotExecutor",
|
||||||
|
pilot_status: "executed",
|
||||||
|
pilot_scope: "counterparty_document_evidence_query_documents_v1",
|
||||||
|
dry_run: dryRun,
|
||||||
|
mcp_execution_performed: executedPrimitives.length > 0,
|
||||||
|
executed_primitives: executedPrimitives,
|
||||||
|
skipped_primitives: skippedPrimitives,
|
||||||
|
probe_results: probeResults,
|
||||||
|
evidence,
|
||||||
|
source_rows_summary: sourceRowsSummary,
|
||||||
|
derived_metadata_surface: null,
|
||||||
|
derived_activity_period: null,
|
||||||
|
derived_value_flow: null,
|
||||||
|
derived_bidirectional_value_flow: null,
|
||||||
|
query_limitations: queryLimitations,
|
||||||
|
reason_codes: reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (valueFlowPilotEligible) {
|
if (valueFlowPilotEligible) {
|
||||||
let queryResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
let queryResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
||||||
const filters = buildValueFlowFilters(planner);
|
const filters = buildValueFlowFilters(planner);
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,13 @@ function localizeLine(value: string): string {
|
||||||
if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) {
|
if (/^1C value-flow rows were found for the requested counterparty scope$/i.test(value)) {
|
||||||
return "В 1С найдены строки денежных движений по запрошенному контрагентскому контуру.";
|
return "В 1С найдены строки денежных движений по запрошенному контрагентскому контуру.";
|
||||||
}
|
}
|
||||||
|
const documentRowsMatch = value.match(/^1C document rows were found for counterparty\s+(.+)$/i);
|
||||||
|
if (documentRowsMatch) {
|
||||||
|
return `В 1С найдены строки документов по контрагенту ${documentRowsMatch[1]}.`;
|
||||||
|
}
|
||||||
|
if (/^1C document rows were found for the requested scope$/i.test(value)) {
|
||||||
|
return "В 1С найдены строки документов по запрошенному контуру.";
|
||||||
|
}
|
||||||
const supplierPayoutMatch = value.match(/^1C supplier-payout rows were found for counterparty\s+(.+)$/i);
|
const supplierPayoutMatch = value.match(/^1C supplier-payout rows were found for counterparty\s+(.+)$/i);
|
||||||
if (supplierPayoutMatch) {
|
if (supplierPayoutMatch) {
|
||||||
return `В 1С найдены строки исходящих платежей/списаний по контрагенту ${supplierPayoutMatch[1]}.`;
|
return `В 1С найдены строки исходящих платежей/списаний по контрагенту ${supplierPayoutMatch[1]}.`;
|
||||||
|
|
@ -131,6 +138,9 @@ function localizeLine(value: string): string {
|
||||||
if (/^Business activity duration may be inferred from first and latest confirmed 1C activity rows$/i.test(value)) {
|
if (/^Business activity duration may be inferred from first and latest confirmed 1C activity rows$/i.test(value)) {
|
||||||
return "Длительность деловой активности можно оценивать только как вывод по первой и последней подтвержденной строке активности в 1С.";
|
return "Длительность деловой активности можно оценивать только как вывод по первой и последней подтвержденной строке активности в 1С.";
|
||||||
}
|
}
|
||||||
|
if (/^Counterparty document evidence is limited to confirmed 1C document rows in the checked scope$/i.test(value)) {
|
||||||
|
return "Срез документов ограничен только подтвержденными строками документов в проверенном окне.";
|
||||||
|
}
|
||||||
if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) {
|
if (/^Counterparty value-flow total was calculated from confirmed 1C movement rows$/i.test(value)) {
|
||||||
return "Сумма рассчитана только по подтвержденным строкам денежных движений в 1С.";
|
return "Сумма рассчитана только по подтвержденным строкам денежных движений в 1С.";
|
||||||
}
|
}
|
||||||
|
|
@ -210,6 +220,12 @@ function localizeLine(value: string): string {
|
||||||
if (/^Full all-time turnover is not proven without an explicit checked period$/i.test(value)) {
|
if (/^Full all-time turnover is not proven without an explicit checked period$/i.test(value)) {
|
||||||
return "Полный оборот за все время без явно проверенного периода не подтвержден.";
|
return "Полный оборот за все время без явно проверенного периода не подтвержден.";
|
||||||
}
|
}
|
||||||
|
if (/^Full document history outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||||
|
return "Полный исторический срез документов вне проверенного периода этим поиском не подтвержден.";
|
||||||
|
}
|
||||||
|
if (/^Full document history is not proven without an explicit checked period$/i.test(value)) {
|
||||||
|
return "Полный срез документов без явно проверенного периода не подтвержден.";
|
||||||
|
}
|
||||||
if (/^Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
if (/^Full supplier-payout amount outside the checked period is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||||
return "Полный объем исходящих платежей вне проверенного периода этим поиском не подтвержден.";
|
return "Полный объем исходящих платежей вне проверенного периода этим поиском не подтвержден.";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,9 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
discoveryEntity: string | null;
|
discoveryEntity: string | null;
|
||||||
organization: string | null;
|
organization: string | null;
|
||||||
dateScope: string | null;
|
dateScope: string | null;
|
||||||
|
metadataRouteFamily: string | null;
|
||||||
|
metadataSelectedEntitySet: string | null;
|
||||||
|
metadataAmbiguityDetected: boolean;
|
||||||
} {
|
} {
|
||||||
const previousFilters = toRecordObject(followupContext?.previous_filters);
|
const previousFilters = toRecordObject(followupContext?.previous_filters);
|
||||||
const rootFilters = toRecordObject(followupContext?.root_filters);
|
const rootFilters = toRecordObject(followupContext?.root_filters);
|
||||||
|
|
@ -282,7 +285,10 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
counterparty,
|
counterparty,
|
||||||
discoveryEntity: discoveryEntities[0] ?? null,
|
discoveryEntity: discoveryEntities[0] ?? null,
|
||||||
organization,
|
organization,
|
||||||
dateScope
|
dateScope,
|
||||||
|
metadataRouteFamily: toNonEmptyString(followupContext?.previous_discovery_metadata_route_family),
|
||||||
|
metadataSelectedEntitySet: toNonEmptyString(followupContext?.previous_discovery_metadata_selected_entity_set),
|
||||||
|
metadataAmbiguityDetected: followupContext?.previous_discovery_metadata_ambiguity_detected === true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,6 +344,12 @@ function hasMetadataObjectHint(text: string): boolean {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasDocumentEvidenceFollowupSignal(text: string): boolean {
|
||||||
|
return /(?:\u043f\u043e\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u0430\u043c|\u044b)?|\u0434\u0430\u0432\u0430\u0439\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0438\u0449\u0438\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u043f\u043e\u043a\u0430\u0436\u0438\s+\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|document(?:s)?\s+(?:then|next)?|(?:then|next)\s+documents?|go\s+to\s+documents?)/iu.test(
|
||||||
|
text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function metadataActionFromRawText(text: string): string {
|
function metadataActionFromRawText(text: string): string {
|
||||||
if (/(?:\u043f\u043e\u043b(?:\u0435|\u044f)|field)/iu.test(text)) {
|
if (/(?:\u043f\u043e\u043b(?:\u0435|\u044f)|field)/iu.test(text)) {
|
||||||
return "inspect_fields";
|
return "inspect_fields";
|
||||||
|
|
@ -465,9 +477,32 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
hasMetadataObjectHint(rawText)
|
hasMetadataObjectHint(rawText)
|
||||||
);
|
);
|
||||||
const seededDomain = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.domain : null;
|
const metadataGroundedDocumentFollowupApplicable = Boolean(
|
||||||
const seededAction = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.action : null;
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
const seededUnsupported = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.unsupported : null;
|
followupSeed.metadataRouteFamily === "document_evidence" &&
|
||||||
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
|
followupSeed.counterparty &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
hasDocumentEvidenceFollowupSignal(rawText)
|
||||||
|
);
|
||||||
|
const effectiveMetadataFollowupSeedApplicable =
|
||||||
|
metadataFollowupSeedApplicable && !metadataGroundedDocumentFollowupApplicable;
|
||||||
|
const seededDomain = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "documents"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.domain
|
||||||
|
: null;
|
||||||
|
const seededAction = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "list_documents"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.action
|
||||||
|
: null;
|
||||||
|
const seededUnsupported = metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "document_evidence"
|
||||||
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? followupSeed.unsupported
|
||||||
|
: null;
|
||||||
const lifecycleSignal =
|
const lifecycleSignal =
|
||||||
rawLifecycleSignal || seededDomain === "counterparty_lifecycle";
|
rawLifecycleSignal || seededDomain === "counterparty_lifecycle";
|
||||||
const bidirectionalValueFlowSignal =
|
const bidirectionalValueFlowSignal =
|
||||||
|
|
@ -485,7 +520,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
unsupported: unsupported ?? seededUnsupported,
|
unsupported: unsupported ?? seededUnsupported,
|
||||||
lifecycleSignal,
|
lifecycleSignal,
|
||||||
valueFlowSignal,
|
valueFlowSignal,
|
||||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable
|
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
});
|
});
|
||||||
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
||||||
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
||||||
|
|
@ -509,7 +544,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
? "counterparty_lifecycle"
|
? "counterparty_lifecycle"
|
||||||
: valueFlowSignal
|
: valueFlowSignal
|
||||||
? "counterparty_value"
|
? "counterparty_value"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "documents"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "metadata"
|
? "metadata"
|
||||||
: rawDomain ?? seededDomain,
|
: rawDomain ?? seededDomain,
|
||||||
asked_action_family: lifecycleSignal
|
asked_action_family: lifecycleSignal
|
||||||
|
|
@ -520,7 +557,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
: payoutSignal
|
: payoutSignal
|
||||||
? "payout"
|
? "payout"
|
||||||
: rawAction ?? seededAction ?? "turnover"
|
: rawAction ?? seededAction ?? "turnover"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "list_documents"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? metadataActionFromRawText(rawText) ?? seededAction
|
? metadataActionFromRawText(rawText) ?? seededAction
|
||||||
: rawAction ?? seededAction,
|
: rawAction ?? seededAction,
|
||||||
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
||||||
|
|
@ -537,7 +576,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
: payoutSignal
|
: payoutSignal
|
||||||
? "counterparty_payouts_or_outflow"
|
? "counterparty_payouts_or_outflow"
|
||||||
: seededUnsupported ?? "counterparty_value_or_turnover"
|
: seededUnsupported ?? "counterparty_value_or_turnover"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
|
? "document_evidence"
|
||||||
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "1c_metadata_surface"
|
? "1c_metadata_surface"
|
||||||
: followupDiscoverySeedApplicable
|
: followupDiscoverySeedApplicable
|
||||||
? seededUnsupported
|
? seededUnsupported
|
||||||
|
|
@ -547,8 +588,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
unsupported ||
|
unsupported ||
|
||||||
lifecycleSignal ||
|
lifecycleSignal ||
|
||||||
valueFlowSignal ||
|
valueFlowSignal ||
|
||||||
|
metadataGroundedDocumentFollowupApplicable ||
|
||||||
rawMetadataSignal ||
|
rawMetadataSignal ||
|
||||||
metadataFollowupSeedApplicable ||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
followupDiscoverySeedApplicable
|
followupDiscoverySeedApplicable
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
@ -583,15 +625,20 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
unsupported: unsupported ?? seededUnsupported,
|
unsupported: unsupported ?? seededUnsupported,
|
||||||
lifecycleSignal,
|
lifecycleSignal,
|
||||||
valueFlowSignal,
|
valueFlowSignal,
|
||||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable,
|
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable,
|
||||||
semanticDataNeed,
|
semanticDataNeed,
|
||||||
explicitIntentCandidate,
|
explicitIntentCandidate,
|
||||||
followupDiscoverySeedApplicable: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
followupDiscoverySeedApplicable:
|
||||||
|
followupDiscoverySeedApplicable ||
|
||||||
|
effectiveMetadataFollowupSeedApplicable ||
|
||||||
|
metadataGroundedDocumentFollowupApplicable
|
||||||
});
|
});
|
||||||
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
||||||
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning
|
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning
|
||||||
? "assistant_turn_meaning"
|
? "assistant_turn_meaning"
|
||||||
: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
: followupDiscoverySeedApplicable || effectiveMetadataFollowupSeedApplicable
|
||||||
|
? "followup_context"
|
||||||
|
: metadataGroundedDocumentFollowupApplicable
|
||||||
? "followup_context"
|
? "followup_context"
|
||||||
: predecomposeContract
|
: predecomposeContract
|
||||||
? "predecompose_contract"
|
? "predecompose_contract"
|
||||||
|
|
@ -599,7 +646,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: valueFlowSignal
|
: valueFlowSignal
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable
|
||||||
? "raw_text"
|
? "raw_text"
|
||||||
: "none";
|
: "none";
|
||||||
|
|
||||||
|
|
@ -624,9 +671,12 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
if (followupDiscoverySeedApplicable) {
|
if (followupDiscoverySeedApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_seeded_from_followup_context");
|
pushReason(reasonCodes, "mcp_discovery_seeded_from_followup_context");
|
||||||
}
|
}
|
||||||
if (metadataFollowupSeedApplicable) {
|
if (effectiveMetadataFollowupSeedApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_metadata_seeded_from_followup_context");
|
pushReason(reasonCodes, "mcp_discovery_metadata_seeded_from_followup_context");
|
||||||
}
|
}
|
||||||
|
if (metadataGroundedDocumentFollowupApplicable) {
|
||||||
|
pushReason(reasonCodes, "mcp_discovery_metadata_grounded_document_followup");
|
||||||
|
}
|
||||||
if (unsupported) {
|
if (unsupported) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ import {
|
||||||
readAddressDebugIntent,
|
readAddressDebugIntent,
|
||||||
readAddressDebugFilters,
|
readAddressDebugFilters,
|
||||||
readAddressDebugItem,
|
readAddressDebugItem,
|
||||||
|
readAssistantMcpDiscoveryMetadataAmbiguityDetected,
|
||||||
|
readAssistantMcpDiscoveryMetadataRouteFamily,
|
||||||
|
readAssistantMcpDiscoveryMetadataSelectedEntitySet,
|
||||||
readAddressDebugTemporalScope,
|
readAddressDebugTemporalScope,
|
||||||
readAssistantMcpDiscoveryPilotScope,
|
readAssistantMcpDiscoveryPilotScope,
|
||||||
resolveOrganizationClarificationContinuation,
|
resolveOrganizationClarificationContinuation,
|
||||||
|
|
@ -607,6 +610,17 @@ export function createAssistantTransitionPolicy(deps) {
|
||||||
}
|
}
|
||||||
const sourceIntent = readAddressDebugIntent(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceIntent = readAddressDebugIntent(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const sourceDiscoveryPilotScope = readAssistantMcpDiscoveryPilotScope(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryPilotScope = readAssistantMcpDiscoveryPilotScope(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryMetadataRouteFamily = readAssistantMcpDiscoveryMetadataRouteFamily(
|
||||||
|
carryoverSourceDebug,
|
||||||
|
deps.toNonEmptyString
|
||||||
|
);
|
||||||
|
const sourceDiscoveryMetadataSelectedEntitySet = readAssistantMcpDiscoveryMetadataSelectedEntitySet(
|
||||||
|
carryoverSourceDebug,
|
||||||
|
deps.toNonEmptyString
|
||||||
|
);
|
||||||
|
const sourceDiscoveryMetadataAmbiguityDetected = readAssistantMcpDiscoveryMetadataAmbiguityDetected(
|
||||||
|
carryoverSourceDebug
|
||||||
|
);
|
||||||
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
||||||
const llmSelectedObjectScopeDetected =
|
const llmSelectedObjectScopeDetected =
|
||||||
llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true;
|
llmPreDecomposeMeta?.predecomposeContract?.semantics?.selected_object_scope_detected === true;
|
||||||
|
|
@ -939,6 +953,9 @@ export function createAssistantTransitionPolicy(deps) {
|
||||||
previous_anchor_type: previousAnchorType ?? undefined,
|
previous_anchor_type: previousAnchorType ?? undefined,
|
||||||
previous_anchor_value: previousAnchor,
|
previous_anchor_value: previousAnchor,
|
||||||
previous_discovery_pilot_scope: sourceDiscoveryPilotScope ?? undefined,
|
previous_discovery_pilot_scope: sourceDiscoveryPilotScope ?? undefined,
|
||||||
|
previous_discovery_metadata_route_family: sourceDiscoveryMetadataRouteFamily ?? undefined,
|
||||||
|
previous_discovery_metadata_selected_entity_set: sourceDiscoveryMetadataSelectedEntitySet ?? undefined,
|
||||||
|
previous_discovery_metadata_ambiguity_detected: sourceDiscoveryMetadataAmbiguityDetected || undefined,
|
||||||
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
|
resolved_counterparty_from_display: resolvedCounterpartyFromDisplay || undefined,
|
||||||
root_context_only: rootScopedPivot || undefined,
|
root_context_only: rootScopedPivot || undefined,
|
||||||
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,
|
root_intent: shouldAttachInventoryRootFrame ? inventoryRootFrame?.intent ?? undefined : undefined,
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,33 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||||
expect(draft.must_not_claim).toContain("Do not claim a confirmed business fact when confirmed_facts is empty.");
|
expect(draft.must_not_claim).toContain("Do not claim a confirmed business fact when confirmed_facts is empty.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("turns generic document evidence into a bounded document answer draft", async () => {
|
||||||
|
const planner = planAssistantMcpDiscovery({
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "documents",
|
||||||
|
asked_action_family: "list_documents",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "document_evidence"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const pilot = await executeAssistantMcpDiscoveryPilot(
|
||||||
|
planner,
|
||||||
|
buildDeps([{ Period: "2020-01-15T00:00:00", Counterparty: "SVK", Registrar: "Doc1" }])
|
||||||
|
);
|
||||||
|
|
||||||
|
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||||
|
|
||||||
|
expect(draft.answer_mode).toBe("confirmed_with_bounded_inference");
|
||||||
|
expect(draft.headline).toContain("документ");
|
||||||
|
expect(draft.confirmed_lines).toContain("1C document rows were found for counterparty SVK");
|
||||||
|
expect(draft.inference_lines).toContain(
|
||||||
|
"Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"
|
||||||
|
);
|
||||||
|
expect(draft.unknown_lines).toContain("Full document history outside the checked period is not proven by this MCP discovery pilot");
|
||||||
|
expect(draft.must_not_claim).toContain("Do not claim full document history outside the checked period.");
|
||||||
|
});
|
||||||
|
|
||||||
it("asks for clarification when discovery did not execute due to missing scope", async () => {
|
it("asks for clarification when discovery did not execute due to missing scope", async () => {
|
||||||
const planner = planAssistantMcpDiscovery({
|
const planner = planAssistantMcpDiscovery({
|
||||||
turnMeaning: {
|
turnMeaning: {
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,36 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||||
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("executes generic document evidence through query_documents", async () => {
|
||||||
|
const planner = planAssistantMcpDiscovery({
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "documents",
|
||||||
|
asked_action_family: "list_documents",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "document_evidence"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const deps = buildDeps([
|
||||||
|
{ Period: "2020-01-15T00:00:00", Counterparty: "SVK", Registrar: "Doc1" },
|
||||||
|
{ Period: "2020-03-20T00:00:00", Counterparty: "SVK", Registrar: "Doc2" }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||||
|
|
||||||
|
expect(result.pilot_status).toBe("executed");
|
||||||
|
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||||
|
expect(result.executed_primitives).toEqual(["query_documents"]);
|
||||||
|
expect(result.evidence.confirmed_facts).toContain("1C document rows were found for counterparty SVK");
|
||||||
|
expect(result.evidence.inferred_facts).toContain(
|
||||||
|
"Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"
|
||||||
|
);
|
||||||
|
expect(result.evidence.unknown_facts).toContain(
|
||||||
|
"Full document history outside the checked period is not proven by this MCP discovery pilot"
|
||||||
|
);
|
||||||
|
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched document scope");
|
||||||
|
});
|
||||||
|
|
||||||
it("executes inspect_1c_metadata and derives a confirmed metadata surface", async () => {
|
it("executes inspect_1c_metadata and derives a confirmed metadata surface", async () => {
|
||||||
const planner = planAssistantMcpDiscovery({
|
const planner = planAssistantMcpDiscovery({
|
||||||
turnMeaning: {
|
turnMeaning: {
|
||||||
|
|
@ -535,7 +565,7 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
|
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps non-lifecycle ready plans unsupported until a dedicated pilot exists", async () => {
|
it("executes document-ready plans through the dedicated document pilot", async () => {
|
||||||
const planner = planAssistantMcpDiscovery({
|
const planner = planAssistantMcpDiscovery({
|
||||||
turnMeaning: {
|
turnMeaning: {
|
||||||
asked_domain_family: "counterparty_documents",
|
asked_domain_family: "counterparty_documents",
|
||||||
|
|
@ -547,11 +577,12 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||||
|
|
||||||
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||||
|
|
||||||
expect(result.pilot_status).toBe("unsupported");
|
expect(result.pilot_status).toBe("executed");
|
||||||
expect(result.mcp_execution_performed).toBe(false);
|
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||||
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "query_documents", "probe_coverage"]);
|
expect(result.mcp_execution_performed).toBe(true);
|
||||||
expect(result.reason_codes).toContain("pilot_scope_unsupported_for_live_execution");
|
expect(result.executed_primitives).toEqual(["query_documents"]);
|
||||||
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
|
||||||
|
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("records MCP errors as limitations without converting them into facts", async () => {
|
it("records MCP errors as limitations without converting them into facts", async () => {
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,33 @@ describe("assistant MCP discovery response candidate", () => {
|
||||||
expect(candidate.reply_text).not.toContain("broad probe hit the row limit");
|
expect(candidate.reply_text).not.toContain("broad probe hit the row limit");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("localizes document evidence without leaking raw English facts", () => {
|
||||||
|
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||||
|
entryPoint({
|
||||||
|
bridge: {
|
||||||
|
bridge_status: "answer_draft_ready",
|
||||||
|
user_facing_response_allowed: true,
|
||||||
|
business_fact_answer_allowed: true,
|
||||||
|
requires_user_clarification: false,
|
||||||
|
answer_draft: {
|
||||||
|
answer_mode: "confirmed_with_bounded_inference",
|
||||||
|
headline: "По данным 1С найдены строки документов; ответ ограничен проверенным периодом и найденными строками.",
|
||||||
|
confirmed_lines: ["1C document rows were found for counterparty SVK"],
|
||||||
|
inference_lines: ["Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"],
|
||||||
|
unknown_lines: ["Full document history outside the checked period is not proven by this MCP discovery pilot"],
|
||||||
|
limitation_lines: [],
|
||||||
|
next_step_line: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(candidate.reply_text).toContain("В 1С найдены строки документов по контрагенту SVK.");
|
||||||
|
expect(candidate.reply_text).toContain("Срез документов ограничен только подтвержденными строками документов");
|
||||||
|
expect(candidate.reply_text).toContain("Полный исторический срез документов вне проверенного периода этим поиском не подтвержден.");
|
||||||
|
expect(candidate.reply_text).not.toContain("1C document rows were found");
|
||||||
|
});
|
||||||
|
|
||||||
it("localizes metadata evidence without leaking raw MCP wording", () => {
|
it("localizes metadata evidence without leaking raw MCP wording", () => {
|
||||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||||
entryPoint({
|
entryPoint({
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||||
expect(result.answer_draft.next_step_line).toContain("Уточните контрагента");
|
expect(result.answer_draft.next_step_line).toContain("Уточните контрагента");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps unsupported ready plans outside the hot answer path", async () => {
|
it("keeps document-ready plans bounded when the pilot finds no confirmed rows", async () => {
|
||||||
const result = await runAssistantMcpDiscoveryRuntimeBridge({
|
const result = await runAssistantMcpDiscoveryRuntimeBridge({
|
||||||
turnMeaning: {
|
turnMeaning: {
|
||||||
asked_domain_family: "document",
|
asked_domain_family: "document",
|
||||||
|
|
@ -61,11 +61,12 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||||
deps: buildDeps([])
|
deps: buildDeps([])
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.bridge_status).toBe("unsupported");
|
expect(result.bridge_status).toBe("checked_sources_only");
|
||||||
expect(result.hot_runtime_wired).toBe(false);
|
expect(result.hot_runtime_wired).toBe(false);
|
||||||
expect(result.pilot.mcp_execution_performed).toBe(false);
|
expect(result.pilot.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||||
|
expect(result.pilot.mcp_execution_performed).toBe(true);
|
||||||
expect(result.business_fact_answer_allowed).toBe(false);
|
expect(result.business_fact_answer_allowed).toBe(false);
|
||||||
expect(result.reason_codes).toContain("runtime_bridge_status_unsupported");
|
expect(result.reason_codes).toContain("runtime_bridge_status_checked_sources_only");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("preserves the answer adapter boundary against internal mechanics leakage", async () => {
|
it("preserves the answer adapter boundary against internal mechanics leakage", async () => {
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,39 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||||
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("pivots grounded metadata follow-up into document evidence when the next lane is explicit", () => {
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage: "then documents",
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_pilot_scope: "metadata_inspection_v1",
|
||||||
|
previous_discovery_metadata_route_family: "document_evidence",
|
||||||
|
previous_discovery_metadata_selected_entity_set: "Документ",
|
||||||
|
previous_filters: {
|
||||||
|
counterparty: "SVK",
|
||||||
|
period_from: "2020-01-01",
|
||||||
|
period_to: "2020-12-31"
|
||||||
|
},
|
||||||
|
previous_anchor_type: "counterparty",
|
||||||
|
previous_anchor_value: "SVK"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.source_signal).toBe("followup_context");
|
||||||
|
expect(result.semantic_data_need).toBe("document evidence");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "documents",
|
||||||
|
asked_action_family: "list_documents",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "document_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_document_followup");
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
||||||
|
});
|
||||||
|
|
||||||
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
|
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
|
||||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
userMessage: "а теперь за 2021?",
|
userMessage: "а теперь за 2021?",
|
||||||
|
|
|
||||||
|
|
@ -1114,6 +1114,61 @@ describe("assistantTransitionPolicy", () => {
|
||||||
period_to: "2020-12-31"
|
period_to: "2020-12-31"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("carries grounded metadata downstream route hints into followup context", () => {
|
||||||
|
const policy = buildPolicy({
|
||||||
|
findLastAddressAssistantItem: () => null,
|
||||||
|
hasAddressFollowupContextSignal: () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||||
|
"then documents",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
role: "assistant",
|
||||||
|
text: "Metadata surface confirmed.",
|
||||||
|
debug: {
|
||||||
|
execution_lane: "living_chat",
|
||||||
|
mcp_discovery_response_applied: true,
|
||||||
|
assistant_mcp_discovery_entry_point_v1: {
|
||||||
|
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
|
||||||
|
entry_status: "bridge_executed",
|
||||||
|
turn_input: {
|
||||||
|
turn_meaning_ref: {
|
||||||
|
asked_domain_family: "metadata",
|
||||||
|
asked_action_family: "inspect_documents",
|
||||||
|
explicit_entity_candidates: ["SVK"],
|
||||||
|
explicit_date_scope: "2020"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bridge: {
|
||||||
|
bridge_status: "answer_draft_ready",
|
||||||
|
business_fact_answer_allowed: true,
|
||||||
|
pilot: {
|
||||||
|
pilot_scope: "metadata_inspection_v1",
|
||||||
|
derived_metadata_surface: {
|
||||||
|
selected_entity_set: "Документ",
|
||||||
|
downstream_route_family: "document_evidence",
|
||||||
|
ambiguity_detected: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
answer_draft: {
|
||||||
|
answer_mode: "confirmed_with_bounded_inference"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_pilot_scope).toBe("metadata_inspection_v1");
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_metadata_route_family).toBe("document_evidence");
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_metadata_selected_entity_set).toBe("Документ");
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_metadata_ambiguity_detected).toBeUndefined();
|
||||||
|
});
|
||||||
it("switches to VAT tax-period intent while preserving carried period filters", () => {
|
it("switches to VAT tax-period intent while preserving carried period filters", () => {
|
||||||
const policy = buildPolicy({
|
const policy = buildPolicy({
|
||||||
findLastAddressAssistantItem: () => ({
|
findLastAddressAssistantItem: () => ({
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue