ARCH: связать metadata grounding с movement lane и reusable follow-up
This commit is contained in:
@@ -149,6 +149,7 @@ interface AssistantMcpDiscoveryCoverageAwareQueryExecution {
|
||||
|
||||
export type AssistantMcpDiscoveryPilotScope =
|
||||
| "metadata_inspection_v1"
|
||||
| "counterparty_movement_evidence_query_movements_v1"
|
||||
| "counterparty_document_evidence_query_documents_v1"
|
||||
| "counterparty_lifecycle_query_documents_v1"
|
||||
| "counterparty_value_flow_query_movements_v1"
|
||||
@@ -304,6 +305,23 @@ function isDocumentEvidencePilotEligible(planner: AssistantMcpDiscoveryPlannerCo
|
||||
);
|
||||
}
|
||||
|
||||
function isMovementEvidencePilotEligible(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 semanticNeed = String(planner.semantic_data_need ?? "").toLowerCase();
|
||||
const combined = `${domain} ${action} ${unsupported} ${semanticNeed}`;
|
||||
return (
|
||||
planner.proposed_primitives.includes("query_movements") &&
|
||||
(combined.includes("movement") ||
|
||||
combined.includes("movements") ||
|
||||
combined.includes("bank_operations") ||
|
||||
combined.includes("movement_evidence") ||
|
||||
combined.includes("list_movements"))
|
||||
);
|
||||
}
|
||||
|
||||
function isValueFlowPilotEligible(planner: AssistantMcpDiscoveryPlannerContract): boolean {
|
||||
const meaning = planner.discovery_plan.turn_meaning_ref;
|
||||
const domain = String(meaning?.asked_domain_family ?? "").toLowerCase();
|
||||
@@ -664,6 +682,16 @@ function summarizeDocumentRows(result: AddressMcpQueryExecutorResult): string |
|
||||
return `${result.fetched_rows} MCP document rows fetched, ${result.matched_rows} matched document scope`;
|
||||
}
|
||||
|
||||
function summarizeMovementRows(result: AddressMcpQueryExecutorResult): string | null {
|
||||
if (result.error) {
|
||||
return null;
|
||||
}
|
||||
if (result.fetched_rows <= 0) {
|
||||
return "0 MCP movement rows fetched";
|
||||
}
|
||||
return `${result.fetched_rows} MCP movement rows fetched, ${result.matched_rows} matched movement scope`;
|
||||
}
|
||||
|
||||
function summarizeValueFlowRows(result: AssistantMcpDiscoveryCoverageAwareQueryResult): string | null {
|
||||
if (result.error) {
|
||||
return null;
|
||||
@@ -1344,6 +1372,17 @@ function buildDocumentConfirmedFacts(result: AddressMcpQueryExecutorResult, coun
|
||||
];
|
||||
}
|
||||
|
||||
function buildMovementConfirmedFacts(result: AddressMcpQueryExecutorResult, counterparty: string | null): string[] {
|
||||
if (result.error || result.matched_rows <= 0) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
counterparty
|
||||
? `1C movement rows were found for counterparty ${counterparty}`
|
||||
: "1C movement rows were found for the requested scope"
|
||||
];
|
||||
}
|
||||
|
||||
function buildValueFlowConfirmedFacts(
|
||||
result: AssistantMcpDiscoveryCoverageAwareQueryResult,
|
||||
counterparty: string | null,
|
||||
@@ -1398,6 +1437,13 @@ function buildDocumentInferredFacts(result: AddressMcpQueryExecutorResult): stri
|
||||
return ["Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"];
|
||||
}
|
||||
|
||||
function buildMovementInferredFacts(result: AddressMcpQueryExecutorResult): string[] {
|
||||
if (result.error || result.fetched_rows <= 0) {
|
||||
return [];
|
||||
}
|
||||
return ["Counterparty movement evidence is limited to confirmed 1C movement rows in the checked scope"];
|
||||
}
|
||||
|
||||
function buildValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerivedValueFlow | null): string[] {
|
||||
if (!derived) {
|
||||
return [];
|
||||
@@ -1449,6 +1495,14 @@ function buildDocumentUnknownFacts(periodScope: string | null): string[] {
|
||||
];
|
||||
}
|
||||
|
||||
function buildMovementUnknownFacts(periodScope: string | null): string[] {
|
||||
return [
|
||||
periodScope
|
||||
? "Full movement history outside the checked period is not proven by this MCP discovery pilot"
|
||||
: "Full movement history is not proven without an explicit checked period"
|
||||
];
|
||||
}
|
||||
|
||||
function buildValueFlowUnknownFacts(
|
||||
periodScope: string | null,
|
||||
direction: AssistantMcpDiscoveryDerivedValueFlow["value_flow_direction"],
|
||||
@@ -1511,6 +1565,9 @@ function pilotScopeForPlanner(planner: AssistantMcpDiscoveryPlannerContract): As
|
||||
if (isMetadataPilotEligible(planner)) {
|
||||
return "metadata_inspection_v1";
|
||||
}
|
||||
if (isMovementEvidencePilotEligible(planner)) {
|
||||
return "counterparty_movement_evidence_query_movements_v1";
|
||||
}
|
||||
if (isValueFlowPilotEligible(planner)) {
|
||||
return valueFlowPilotProfile(planner).scope;
|
||||
}
|
||||
@@ -1586,10 +1643,11 @@ export async function executeAssistantMcpDiscoveryPilot(
|
||||
|
||||
const metadataPilotEligible = isMetadataPilotEligible(planner);
|
||||
const documentPilotEligible = isDocumentEvidencePilotEligible(planner);
|
||||
const movementPilotEligible = isMovementEvidencePilotEligible(planner);
|
||||
const lifecyclePilotEligible = isLifecyclePilotEligible(planner);
|
||||
const valueFlowPilotEligible = isValueFlowPilotEligible(planner);
|
||||
|
||||
if (!metadataPilotEligible && !documentPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
||||
if (!metadataPilotEligible && !documentPilotEligible && !movementPilotEligible && !lifecyclePilotEligible && !valueFlowPilotEligible) {
|
||||
pushReason(reasonCodes, "pilot_scope_unsupported_for_live_execution");
|
||||
for (const step of dryRun.execution_steps) {
|
||||
skippedPrimitives.push(step.primitive_id);
|
||||
@@ -1767,6 +1825,89 @@ export async function executeAssistantMcpDiscoveryPilot(
|
||||
};
|
||||
}
|
||||
|
||||
if (movementPilotEligible) {
|
||||
let queryResult: AddressMcpQueryExecutorResult | null = null;
|
||||
const filters = buildValueFlowFilters(planner);
|
||||
const selection = selectAddressRecipe("bank_operations_by_counterparty", filters);
|
||||
if (!selection.selected_recipe) {
|
||||
pushReason(reasonCodes, "pilot_movement_recipe_not_available");
|
||||
const evidence = buildEmptyEvidence(planner, dryRun, probeResults, "Movement-evidence recipe is not available");
|
||||
return {
|
||||
schema_version: ASSISTANT_MCP_DISCOVERY_PILOT_EXECUTOR_SCHEMA_VERSION,
|
||||
policy_owner: "assistantMcpDiscoveryPilotExecutor",
|
||||
pilot_status: "unsupported",
|
||||
pilot_scope: "counterparty_movement_evidence_query_movements_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: ["Movement-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_movements") {
|
||||
skippedPrimitives.push(step.primitive_id);
|
||||
probeResults.push(skippedProbeResult(step, "pilot_only_executes_query_movements"));
|
||||
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_movements_mcp_error");
|
||||
} else {
|
||||
pushReason(reasonCodes, "pilot_query_movements_mcp_executed");
|
||||
}
|
||||
}
|
||||
|
||||
const sourceRowsSummary = queryResult ? summarizeMovementRows(queryResult) : null;
|
||||
const evidence = resolveAssistantMcpDiscoveryEvidence({
|
||||
plan: planner.discovery_plan,
|
||||
probeResults,
|
||||
confirmedFacts: queryResult ? buildMovementConfirmedFacts(queryResult, counterparty) : [],
|
||||
inferredFacts: queryResult ? buildMovementInferredFacts(queryResult) : [],
|
||||
unknownFacts: buildMovementUnknownFacts(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_movement_evidence_query_movements_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) {
|
||||
let queryResult: AssistantMcpDiscoveryCoverageAwareQueryResult | null = null;
|
||||
const filters = buildValueFlowFilters(planner);
|
||||
|
||||
Reference in New Issue
Block a user