Planner Autonomy: закрепить bounded inference и semantic bridges
This commit is contained in:
@@ -348,14 +348,14 @@ const CHAIN_TEMPLATES: AssistantMcpCatalogChainTemplateContract[] = [
|
||||
},
|
||||
{
|
||||
chain_id: "lifecycle",
|
||||
semantic_data_need: "counterparty lifecycle evidence",
|
||||
semantic_data_need: "counterparty lifecycle evidence with bounded activity-window inference",
|
||||
chain_summary:
|
||||
"Resolve the business entity, query supporting documents, probe coverage, then explain the evidence basis for the inferred activity window.",
|
||||
"Resolve the business entity, query supporting documents, probe coverage, then explain the evidence basis for the inferred activity window without presenting it as legal registration age.",
|
||||
fallback_primitives: ["resolve_entity_reference", "query_documents", "probe_coverage", "explain_evidence_basis"],
|
||||
base_required_axes: ["document_date", "coverage_target", "evidence_basis"],
|
||||
base_required_axes: ["document_date", "coverage_target", "evidence_basis", "activity_window", "legal_fact_boundary"],
|
||||
supported_fact_families: ["activity_lifecycle"],
|
||||
supported_action_families: ["activity_duration"],
|
||||
planning_tags: ["document", "explanation", "coverage"],
|
||||
planning_tags: ["document", "explanation", "coverage", "bounded_inference", "activity_window", "legal_fact_boundary"],
|
||||
safe_for_model_planning: true,
|
||||
requires_evidence_gate: true
|
||||
}
|
||||
|
||||
@@ -2127,8 +2127,8 @@ function buildLifecycleConfirmedFacts(result: AddressMcpQueryExecutorResult, cou
|
||||
}
|
||||
return [
|
||||
counterparty
|
||||
? `1C activity rows were found for counterparty ${counterparty}`
|
||||
: "1C activity rows were found for the requested counterparty scope"
|
||||
? `1C activity rows were found for counterparty ${counterparty}; matched_rows=${result.matched_rows}`
|
||||
: `1C activity rows were found for the requested counterparty scope; matched_rows=${result.matched_rows}`
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2222,7 +2222,15 @@ function buildLifecycleInferredFacts(result: AddressMcpQueryExecutorResult): str
|
||||
if (result.error || result.fetched_rows <= 0) {
|
||||
return [];
|
||||
}
|
||||
return ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"];
|
||||
const period = deriveActivityPeriod(result);
|
||||
if (!period) {
|
||||
return ["Business activity duration may be inferred only when confirmed 1C activity row dates are available"];
|
||||
}
|
||||
return [
|
||||
"Business activity duration may be inferred from first and latest confirmed 1C activity rows",
|
||||
`Activity window is bounded by first=${period.first_activity_date}, latest=${period.latest_activity_date}, matched_rows=${period.matched_rows}`,
|
||||
"Activity-window inference is not legal registration age"
|
||||
];
|
||||
}
|
||||
|
||||
function buildDocumentInferredFacts(
|
||||
@@ -2273,7 +2281,7 @@ function buildValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerivedValueF
|
||||
}
|
||||
if (derived.coverage_recovered_by_period_chunking && derived.period_chunking_granularity === "month") {
|
||||
facts.push(
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes after the broad probe hit the row limit"
|
||||
"Requested period coverage was recovered through monthly 1C value-flow probes"
|
||||
);
|
||||
}
|
||||
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
||||
@@ -2289,7 +2297,7 @@ function buildRankedValueFlowInferredFacts(derived: AssistantMcpDiscoveryDerived
|
||||
const facts = ["Counterparty ranking was calculated from confirmed 1C movement rows grouped by counterparty"];
|
||||
if (derived.coverage_recovered_by_period_chunking && derived.period_chunking_granularity === "month") {
|
||||
facts.push(
|
||||
"Requested period coverage for counterparty ranking was recovered through monthly 1C probes after a broad probe hit the row limit"
|
||||
"Requested period coverage for counterparty ranking was recovered through monthly 1C probes"
|
||||
);
|
||||
}
|
||||
return facts;
|
||||
@@ -2304,7 +2312,7 @@ function buildBidirectionalValueFlowInferredFacts(
|
||||
const facts = ["Counterparty net value-flow was calculated as incoming confirmed 1C rows minus outgoing confirmed 1C rows"];
|
||||
if (derived.coverage_recovered_by_period_chunking && derived.period_chunking_granularity === "month") {
|
||||
facts.push(
|
||||
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes after a broad probe hit the row limit"
|
||||
"Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes"
|
||||
);
|
||||
}
|
||||
if (derived.aggregation_axis === "month" && derived.monthly_breakdown.length > 0) {
|
||||
@@ -2314,7 +2322,10 @@ function buildBidirectionalValueFlowInferredFacts(
|
||||
}
|
||||
|
||||
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",
|
||||
"Business activity before the first confirmed 1C activity row is not proven by this MCP discovery pilot"
|
||||
];
|
||||
}
|
||||
|
||||
function buildDocumentUnknownFacts(periodScope: string | null, counterparty: string | null): string[] {
|
||||
@@ -2336,7 +2347,7 @@ function buildValueFlowUnknownFacts(
|
||||
): string[] {
|
||||
const unknownFacts: string[] = [];
|
||||
if (derived?.coverage_limited_by_probe_limit) {
|
||||
unknownFacts.push("Complete requested-period coverage is not proven because the MCP discovery probe row limit was reached");
|
||||
unknownFacts.push("Complete requested-period coverage is not proven by the available checked rows");
|
||||
}
|
||||
if (direction === "outgoing_supplier_payout") {
|
||||
unknownFacts.push(
|
||||
@@ -2360,7 +2371,7 @@ function buildRankedValueFlowUnknownFacts(
|
||||
): string[] {
|
||||
const unknownFacts: string[] = [];
|
||||
if (derived?.coverage_limited_by_probe_limit) {
|
||||
unknownFacts.push("Complete requested-period ranking coverage is not proven because the MCP discovery probe row limit was reached");
|
||||
unknownFacts.push("Complete requested-period ranking coverage is not proven by the available checked rows");
|
||||
}
|
||||
unknownFacts.push(
|
||||
periodScope
|
||||
@@ -2377,7 +2388,7 @@ function buildBidirectionalValueFlowUnknownFacts(
|
||||
const unknownFacts: string[] = [];
|
||||
if (derived?.coverage_limited_by_probe_limit) {
|
||||
unknownFacts.push(
|
||||
"Complete requested-period coverage for bidirectional value-flow is not proven because at least one MCP discovery probe row limit was reached"
|
||||
"Complete requested-period coverage for bidirectional value-flow is not proven by the available checked rows"
|
||||
);
|
||||
}
|
||||
unknownFacts.push(
|
||||
|
||||
@@ -127,6 +127,11 @@ function pushAllUnique(target: string[], values: string[]): void {
|
||||
}
|
||||
}
|
||||
|
||||
const LIFECYCLE_BOUNDED_INFERENCE_REASON_CODES = [
|
||||
"planner_lifecycle_bounded_activity_window_template",
|
||||
"planner_lifecycle_legal_fact_boundary_required"
|
||||
];
|
||||
|
||||
function recipeFromCatalogChainTemplate(input: {
|
||||
chainId: AssistantMcpCatalogChainTemplateId;
|
||||
axes: string[];
|
||||
@@ -711,7 +716,7 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||
axes,
|
||||
primitives: primitiveSelection.primitives,
|
||||
reason: "planner_selected_lifecycle_from_data_need_graph",
|
||||
extraReasons: primitiveSelection.reasonCodes
|
||||
extraReasons: [...primitiveSelection.reasonCodes, ...LIFECYCLE_BOUNDED_INFERENCE_REASON_CODES]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -874,7 +879,8 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||
return recipeFromCatalogChainTemplate({
|
||||
chainId: "lifecycle",
|
||||
axes,
|
||||
reason: "planner_selected_lifecycle_recipe"
|
||||
reason: "planner_selected_lifecycle_recipe",
|
||||
extraReasons: LIFECYCLE_BOUNDED_INFERENCE_REASON_CODES
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,24 @@ function localizeLine(value: string): string {
|
||||
) {
|
||||
return "Покрытие запрошенного периода по двустороннему денежному потоку восстановлено помесячными проверками 1С после того, как общая выборка уперлась в лимит строк хотя бы по одной стороне.";
|
||||
}
|
||||
if (/^Requested period coverage was recovered through monthly 1C value-flow probes$/i.test(value)) {
|
||||
return "Покрытие запрошенного периода восстановлено помесячными проверками 1С.";
|
||||
}
|
||||
if (/^Requested period coverage for counterparty ranking was recovered through monthly 1C probes$/i.test(value)) {
|
||||
return "Покрытие запрошенного периода для рейтинга контрагентов восстановлено помесячными проверками 1С.";
|
||||
}
|
||||
if (/^Requested period coverage for bidirectional value-flow was recovered through monthly 1C side probes$/i.test(value)) {
|
||||
return "Покрытие запрошенного периода по двустороннему денежному потоку восстановлено помесячными проверками 1С.";
|
||||
}
|
||||
if (/^Complete requested-period coverage is not proven by the available checked rows$/i.test(value)) {
|
||||
return "Полное покрытие запрошенного периода не подтверждено доступными проверенными строками.";
|
||||
}
|
||||
if (/^Complete requested-period ranking coverage is not proven by the available checked rows$/i.test(value)) {
|
||||
return "Полное покрытие рейтинга за запрошенный период не подтверждено доступными проверенными строками.";
|
||||
}
|
||||
if (/^Complete requested-period coverage for bidirectional value-flow is not proven by the available checked rows$/i.test(value)) {
|
||||
return "Полное покрытие запрошенного периода по двустороннему денежному потоку не подтверждено доступными проверенными строками.";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -688,6 +688,12 @@ function hasValueFlowSignal(text: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasValueFlowAggregateQuestionSignal(text: string): boolean {
|
||||
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e|\u0441\u0443\u043c\u043c|\u0438\u0442\u043e\u0433|\u0440\u0430\u0441\u0441\u0447\u0438\u0442|\u043d\u0435\u0442\u0442\u043e|\u0441\u0430\u043b\u044c\u0434\u043e|how\s+much|total|sum|net)/iu.test(
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
function hasPayoutSignal(text: string): boolean {
|
||||
return /(?:\bмы\s+(?:за)?плат|(?:за)?платил|оплатил|перечисл|списан|расход|поставщик|исходящ|supplier|payout|outflow|paid\s+to|payment\s+to)/iu.test(
|
||||
text
|
||||
@@ -1128,6 +1134,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
const rawEntityResolutionSignal =
|
||||
!rawLifecycleSignal && !rawValueFlowSignal && !rawMetadataSignal && hasEntityResolutionSignal(rawText);
|
||||
const rawPayoutSignal = rawValueFlowSignal && !rawBidirectionalValueFlowSignal && hasPayoutSignal(rawText);
|
||||
const rawValueFlowAggregateQuestionSignal =
|
||||
rawValueFlowSignal && hasValueFlowAggregateQuestionSignal(rawText);
|
||||
const monthlyAggregationSignal = hasMonthlyAggregationSignal(rawText);
|
||||
const rawAllTimeScopeSignal = hasAllTimeScopeHint(rawText);
|
||||
const explicitDateScopeLiteralDetected = hasExplicitDateScopeLiteral(rawText);
|
||||
@@ -1150,6 +1158,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
const rawAction = toNonEmptyString(assistantTurnMeaning?.asked_action_family);
|
||||
const rawAggregationAxis = toNonEmptyString(assistantTurnMeaning?.asked_aggregation_axis);
|
||||
const unsupported = toNonEmptyString(assistantTurnMeaning?.unsupported_but_understood_family);
|
||||
const broadBusinessEvaluationUnsupported = unsupported === "broad_business_evaluation";
|
||||
const explicitIntentCandidate = toNonEmptyString(assistantTurnMeaning?.explicit_intent_candidate);
|
||||
const currentTurnDocumentLaneSignal = rawAction === "list_documents";
|
||||
const currentTurnMovementLaneSignal = rawAction === "list_movements";
|
||||
@@ -1549,7 +1558,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
: semanticNeedFor({
|
||||
domain: rawDomain ?? seededDomain,
|
||||
action: rawAction ?? seededAction,
|
||||
unsupported: unsupported ?? seededUnsupported,
|
||||
unsupported: broadBusinessEvaluationUnsupported ? seededUnsupported : unsupported ?? seededUnsupported,
|
||||
lifecycleSignal,
|
||||
valueFlowSignal,
|
||||
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable,
|
||||
@@ -1856,8 +1865,16 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
cleanTurnMeaning.stale_replay_forbidden = true;
|
||||
}
|
||||
|
||||
const currentTurnValueFlowExactOverrideApplicable = Boolean(
|
||||
valueFlowSignal &&
|
||||
explicitIntentCandidate &&
|
||||
rawValueFlowAggregateQuestionSignal &&
|
||||
semanticDataNeed &&
|
||||
(entityCandidates.length > 0 || explicitOrganizationScope || openScopeValueFlowWithoutResolvedCounterparty)
|
||||
);
|
||||
|
||||
const runDiscovery = shouldRunDiscovery({
|
||||
unsupported: unsupported ?? seededUnsupported,
|
||||
unsupported: broadBusinessEvaluationUnsupported ? seededUnsupported : unsupported ?? seededUnsupported,
|
||||
lifecycleSignal,
|
||||
valueFlowSignal,
|
||||
metadataSignal: rawMetadataSignal || effectiveMetadataFollowupSeedApplicable,
|
||||
@@ -1879,7 +1896,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
metadataAmbiguityLaneClarificationApplicable ||
|
||||
metadataGroundedMovementLaneApplicable ||
|
||||
metadataGroundedDocumentLaneApplicable ||
|
||||
groundedValueFlowFollowupApplicable
|
||||
groundedValueFlowFollowupApplicable ||
|
||||
currentTurnValueFlowExactOverrideApplicable
|
||||
});
|
||||
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
||||
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = rawEntitySearchOverridesStaleScope
|
||||
@@ -1991,6 +2009,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
if (groundedValueFlowFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_grounded_value_flow_followup");
|
||||
}
|
||||
if (currentTurnValueFlowExactOverrideApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_current_turn_value_flow_overrides_supported_exact");
|
||||
}
|
||||
if (documentEvidenceGroundedMovementFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_document_evidence_grounded_movement_followup");
|
||||
}
|
||||
@@ -2021,6 +2042,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
if (unsupported) {
|
||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||
}
|
||||
if (broadBusinessEvaluationUnsupported) {
|
||||
pushReason(reasonCodes, "mcp_discovery_broad_business_evaluation_kept_in_living_chat");
|
||||
}
|
||||
if (
|
||||
!(valueFlowOrganizationStaysScope && normalizedPredecomposeCounterparty === explicitOrganizationScope) &&
|
||||
normalizedPredecomposeCounterparty
|
||||
|
||||
Reference in New Issue
Block a user