ARCH: замкнуть metadata-scoped clarification recovery loops
This commit is contained in:
parent
c96c9bab86
commit
cddd6667fb
|
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"schema_version": "domain_truth_harness_spec_v1",
|
||||||
|
"scenario_id": "address_truth_harness_phase50_metadata_movement_org_period_clarification_loop",
|
||||||
|
"domain": "address_phase50_metadata_movement_org_period_clarification_loop",
|
||||||
|
"title": "Phase 50 metadata movement organization and period clarification loop",
|
||||||
|
"description": "Targeted AGENT replay for Big Block F where a metadata-born movement lane must keep both remaining gaps visible, then preserve the same loop after an organization-only clarification and ask only for the period.",
|
||||||
|
"bindings": {},
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"step_id": "step_01_metadata_ambiguity_surface",
|
||||||
|
"title": "Metadata ambiguity is surfaced honestly for VAT",
|
||||||
|
"question": "какие объекты 1С есть по НДС?",
|
||||||
|
"allowed_reply_types": ["partial_coverage", "factual_with_explanation"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)metadata|метадан",
|
||||||
|
"(?i)ндс",
|
||||||
|
"(?i)документ|регистр"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)получили",
|
||||||
|
"(?i)заплатили",
|
||||||
|
"(?i)нетто"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["metadata_surface", "mixed_ambiguity"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_02_neutral_followup_requires_lane_choice",
|
||||||
|
"title": "Neutral follow-up still requires lane choice",
|
||||||
|
"question": "давай дальше",
|
||||||
|
"allowed_reply_types": ["clarification_required", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)документ",
|
||||||
|
"(?i)движени|регистр",
|
||||||
|
"(?i)уточн|выб(ери|рать)|какой контур"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["metadata_lane_choice_clarification", "neutral_followup"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_03_movement_lane_requires_org_and_period",
|
||||||
|
"title": "Movement lane keeps both remaining gaps visible",
|
||||||
|
"question": "по движениям",
|
||||||
|
"allowed_reply_types": ["clarification_required", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)движени|регистр",
|
||||||
|
"(?i)организац",
|
||||||
|
"(?i)период"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)уточните контрагента",
|
||||||
|
"(?i)не найден контрагент"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["movement_lane_after_clarification", "remaining_gaps", "organization_scope", "period_scope"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_04_org_only_clarification_keeps_same_movement_loop",
|
||||||
|
"title": "Organization-only clarification preserves the same movement loop and asks only for the period",
|
||||||
|
"question": "по ООО Альтернатива Плюс",
|
||||||
|
"allowed_reply_types": ["clarification_required", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)движени|регистр",
|
||||||
|
"(?i)период"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)организац",
|
||||||
|
"(?i)уточните контрагента",
|
||||||
|
"(?i)не найден контрагент"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["movement_lane_after_clarification", "organization_followup_reuse", "period_scope"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"schema_version": "domain_truth_harness_spec_v1",
|
||||||
|
"scenario_id": "address_truth_harness_phase51_metadata_lane_choice_with_org_inline",
|
||||||
|
"domain": "address_phase51_metadata_lane_choice_with_org_inline",
|
||||||
|
"title": "Phase 51 metadata lane choice with inline organization clarification",
|
||||||
|
"description": "Targeted AGENT replay for Big Block F where the user resolves metadata ambiguity and supplies the organization in the same follow-up, so the movement loop should keep only the period gap alive.",
|
||||||
|
"bindings": {},
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"step_id": "step_01_metadata_ambiguity_surface",
|
||||||
|
"title": "Metadata ambiguity is surfaced honestly for VAT",
|
||||||
|
"question": "какие объекты 1С есть по НДС?",
|
||||||
|
"allowed_reply_types": ["partial_coverage", "factual_with_explanation"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)metadata|метадан",
|
||||||
|
"(?i)ндс",
|
||||||
|
"(?i)документ|регистр"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)получили",
|
||||||
|
"(?i)заплатили",
|
||||||
|
"(?i)нетто"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["metadata_surface", "mixed_ambiguity"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_02_neutral_followup_requires_lane_choice",
|
||||||
|
"title": "Neutral follow-up still requires lane choice",
|
||||||
|
"question": "давай дальше",
|
||||||
|
"allowed_reply_types": ["clarification_required", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)документ",
|
||||||
|
"(?i)движени|регистр",
|
||||||
|
"(?i)уточн|выб(ери|рать)|какой контур"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": ["metadata_lane_choice_clarification", "neutral_followup"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"step_id": "step_03_inline_lane_choice_with_org_keeps_only_period_gap",
|
||||||
|
"title": "Movement lane plus organization in one follow-up leaves only the period gap",
|
||||||
|
"question": "по движениям по ООО Альтернатива Плюс",
|
||||||
|
"allowed_reply_types": ["clarification_required", "partial_coverage"],
|
||||||
|
"required_answer_patterns_all": [
|
||||||
|
"(?i)движени|регистр",
|
||||||
|
"(?i)период"
|
||||||
|
],
|
||||||
|
"forbidden_answer_patterns": [
|
||||||
|
"(?i)уточните .*организац",
|
||||||
|
"(?i)нужн[ао].*организац",
|
||||||
|
"(?i)уточните .*контрагента",
|
||||||
|
"(?i)не найден контрагент"
|
||||||
|
],
|
||||||
|
"criticality": "critical",
|
||||||
|
"semantic_tags": [
|
||||||
|
"movement_lane_after_clarification",
|
||||||
|
"inline_organization_clarification",
|
||||||
|
"remaining_period_gap_only"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,8 @@ exports.readAssistantMcpDiscoveryLoopProvidedAxes = readAssistantMcpDiscoveryLoo
|
||||||
exports.readAssistantMcpDiscoveryLoopAskedDomainFamily = readAssistantMcpDiscoveryLoopAskedDomainFamily;
|
exports.readAssistantMcpDiscoveryLoopAskedDomainFamily = readAssistantMcpDiscoveryLoopAskedDomainFamily;
|
||||||
exports.readAssistantMcpDiscoveryLoopAskedActionFamily = readAssistantMcpDiscoveryLoopAskedActionFamily;
|
exports.readAssistantMcpDiscoveryLoopAskedActionFamily = readAssistantMcpDiscoveryLoopAskedActionFamily;
|
||||||
exports.readAssistantMcpDiscoveryLoopUnsupportedFamily = readAssistantMcpDiscoveryLoopUnsupportedFamily;
|
exports.readAssistantMcpDiscoveryLoopUnsupportedFamily = readAssistantMcpDiscoveryLoopUnsupportedFamily;
|
||||||
|
exports.readAssistantMcpDiscoveryLoopMetadataScopeHint = readAssistantMcpDiscoveryLoopMetadataScopeHint;
|
||||||
|
exports.readAssistantMcpDiscoveryLoopSubjectResolutionOptional = readAssistantMcpDiscoveryLoopSubjectResolutionOptional;
|
||||||
exports.readAssistantMcpDiscoveryMetadataRouteFamily = readAssistantMcpDiscoveryMetadataRouteFamily;
|
exports.readAssistantMcpDiscoveryMetadataRouteFamily = readAssistantMcpDiscoveryMetadataRouteFamily;
|
||||||
exports.readAssistantMcpDiscoveryMetadataRouteFamilySelectionBasis = readAssistantMcpDiscoveryMetadataRouteFamilySelectionBasis;
|
exports.readAssistantMcpDiscoveryMetadataRouteFamilySelectionBasis = readAssistantMcpDiscoveryMetadataRouteFamilySelectionBasis;
|
||||||
exports.readAssistantMcpDiscoveryMetadataSelectedEntitySet = readAssistantMcpDiscoveryMetadataSelectedEntitySet;
|
exports.readAssistantMcpDiscoveryMetadataSelectedEntitySet = readAssistantMcpDiscoveryMetadataSelectedEntitySet;
|
||||||
|
|
@ -194,6 +196,16 @@ function readAssistantMcpDiscoveryLoopAskedActionFamily(debug, toNonEmptyString
|
||||||
function readAssistantMcpDiscoveryLoopUnsupportedFamily(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
function readAssistantMcpDiscoveryLoopUnsupportedFamily(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
return toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.unsupported_but_understood_family);
|
return toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.unsupported_but_understood_family);
|
||||||
}
|
}
|
||||||
|
function readAssistantMcpDiscoveryLoopMetadataScopeHint(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
|
return (toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.metadata_scope_hint) ??
|
||||||
|
toNonEmptyString(readAssistantMcpDiscoveryTurnMeaning(debug)?.metadata_scope_hint) ??
|
||||||
|
toNonEmptyString(readAssistantMcpDiscoveryDataNeedGraph(debug)?.metadata_scope_hint));
|
||||||
|
}
|
||||||
|
function readAssistantMcpDiscoveryLoopSubjectResolutionOptional(debug) {
|
||||||
|
return (readAssistantMcpDiscoveryLoopState(debug)?.subject_resolution_optional === true ||
|
||||||
|
readAssistantMcpDiscoveryTurnMeaning(debug)?.subject_resolution_optional === true ||
|
||||||
|
readAssistantMcpDiscoveryDataNeedGraph(debug)?.subject_resolution_optional === true);
|
||||||
|
}
|
||||||
function readAssistantMcpDiscoveryMetadataRouteFamily(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
function readAssistantMcpDiscoveryMetadataRouteFamily(debug, toNonEmptyString = fallbackToNonEmptyString) {
|
||||||
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.downstream_route_family);
|
return toNonEmptyString(readAssistantMcpDiscoveryDerivedMetadataSurface(debug)?.downstream_route_family);
|
||||||
}
|
}
|
||||||
|
|
@ -361,6 +373,12 @@ function readAddressDebugCounterparty(debug, toNonEmptyString = fallbackToNonEmp
|
||||||
if (String(debug?.anchor_type ?? "") === "counterparty") {
|
if (String(debug?.anchor_type ?? "") === "counterparty") {
|
||||||
return toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
|
return toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
|
||||||
}
|
}
|
||||||
|
const discoveryPilotScope = readAssistantMcpDiscoveryPilotScope(debug, toNonEmptyString);
|
||||||
|
const suppressDiscoveryEntityCarryover = discoveryPilotScope === "metadata_inspection_v1" ||
|
||||||
|
readAssistantMcpDiscoveryLoopSubjectResolutionOptional(debug);
|
||||||
|
if (suppressDiscoveryEntityCarryover) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const discoveryEntities = collectAssistantMcpDiscoveryEntityCandidates(debug, toNonEmptyString);
|
const discoveryEntities = collectAssistantMcpDiscoveryEntityCandidates(debug, toNonEmptyString);
|
||||||
for (const entity of discoveryEntities) {
|
for (const entity of discoveryEntities) {
|
||||||
const text = toNonEmptyString(entity);
|
const text = toNonEmptyString(entity);
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,10 @@ function allowsOpenScopeWithoutSubject(input) {
|
||||||
}
|
}
|
||||||
return Boolean(supportsOrganizationScopedOpenTotal(input.action) && (input.organizationScope || input.oneSidedOpenScopeTotalHint));
|
return Boolean(supportsOrganizationScopedOpenTotal(input.action) && (input.organizationScope || input.oneSidedOpenScopeTotalHint));
|
||||||
}
|
}
|
||||||
|
function allowsMetadataScopedOpenLaneWithoutSubject(input) {
|
||||||
|
return Boolean(input.subjectResolutionOptional &&
|
||||||
|
(input.family === "movement_evidence" || input.family === "document_evidence"));
|
||||||
|
}
|
||||||
function rankingNeedFromRawUtterance(value) {
|
function rankingNeedFromRawUtterance(value) {
|
||||||
const text = lower(value);
|
const text = lower(value);
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
|
@ -206,13 +210,17 @@ function decompositionCandidatesFor(input) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (input.family === "movement_evidence") {
|
if (input.family === "movement_evidence") {
|
||||||
pushUnique(result, "resolve_entity_reference");
|
if (!input.metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushUnique(result, "resolve_entity_reference");
|
||||||
|
}
|
||||||
pushUnique(result, "fetch_scoped_movements");
|
pushUnique(result, "fetch_scoped_movements");
|
||||||
pushUnique(result, "probe_coverage");
|
pushUnique(result, "probe_coverage");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (input.family === "document_evidence") {
|
if (input.family === "document_evidence") {
|
||||||
pushUnique(result, "resolve_entity_reference");
|
if (!input.metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushUnique(result, "resolve_entity_reference");
|
||||||
|
}
|
||||||
pushUnique(result, "fetch_scoped_documents");
|
pushUnique(result, "fetch_scoped_documents");
|
||||||
pushUnique(result, "probe_coverage");
|
pushUnique(result, "probe_coverage");
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -252,6 +260,8 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
const seededRankingNeed = toNonEmptyString(turnMeaning?.seeded_ranking_need);
|
const seededRankingNeed = toNonEmptyString(turnMeaning?.seeded_ranking_need);
|
||||||
const explicitDateScope = toNonEmptyString(turnMeaning?.explicit_date_scope);
|
const explicitDateScope = toNonEmptyString(turnMeaning?.explicit_date_scope);
|
||||||
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
||||||
|
const metadataScopeHint = toNonEmptyString(turnMeaning?.metadata_scope_hint);
|
||||||
|
const subjectResolutionOptional = turnMeaning?.subject_resolution_optional === true;
|
||||||
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
||||||
.map((item) => toNonEmptyString(item))
|
.map((item) => toNonEmptyString(item))
|
||||||
.filter((item) => Boolean(item));
|
.filter((item) => Boolean(item));
|
||||||
|
|
@ -275,6 +285,11 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
rankingNeed,
|
rankingNeed,
|
||||||
oneSidedOpenScopeTotalHint
|
oneSidedOpenScopeTotalHint
|
||||||
});
|
});
|
||||||
|
const metadataScopedOpenLaneWithoutSubject = subjectCandidates.length === 0 &&
|
||||||
|
allowsMetadataScopedOpenLaneWithoutSubject({
|
||||||
|
family: businessFactFamily,
|
||||||
|
subjectResolutionOptional
|
||||||
|
});
|
||||||
const clarificationGaps = [];
|
const clarificationGaps = [];
|
||||||
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
|
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
|
||||||
pushUnique(clarificationGaps, "lane_family_choice");
|
pushUnique(clarificationGaps, "lane_family_choice");
|
||||||
|
|
@ -285,7 +300,15 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
!explicitOrganizationScope) {
|
!explicitOrganizationScope) {
|
||||||
pushUnique(clarificationGaps, "organization");
|
pushUnique(clarificationGaps, "organization");
|
||||||
}
|
}
|
||||||
else if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && !openScopeWithoutSubject) {
|
else if (subjectCandidates.length === 0 &&
|
||||||
|
metadataScopedOpenLaneWithoutSubject &&
|
||||||
|
!explicitOrganizationScope) {
|
||||||
|
pushUnique(clarificationGaps, "organization");
|
||||||
|
}
|
||||||
|
else if (subjectCandidates.length === 0 &&
|
||||||
|
businessFactFamily !== "schema_surface" &&
|
||||||
|
!openScopeWithoutSubject &&
|
||||||
|
!metadataScopedOpenLaneWithoutSubject) {
|
||||||
pushUnique(clarificationGaps, "subject");
|
pushUnique(clarificationGaps, "subject");
|
||||||
}
|
}
|
||||||
const timeScopeNeed = timeScopeNeedFor({
|
const timeScopeNeed = timeScopeNeedFor({
|
||||||
|
|
@ -302,7 +325,8 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
aggregationNeed,
|
aggregationNeed,
|
||||||
comparisonNeed,
|
comparisonNeed,
|
||||||
rankingNeed,
|
rankingNeed,
|
||||||
openScopeWithoutSubject
|
openScopeWithoutSubject,
|
||||||
|
metadataScopedOpenLaneWithoutSubject
|
||||||
});
|
});
|
||||||
const reasonCodes = [];
|
const reasonCodes = [];
|
||||||
pushReason(reasonCodes, "data_need_graph_built");
|
pushReason(reasonCodes, "data_need_graph_built");
|
||||||
|
|
@ -324,6 +348,9 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
|
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
|
||||||
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
|
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
|
||||||
}
|
}
|
||||||
|
if (metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushReason(reasonCodes, "data_need_graph_metadata_scoped_open_lane_without_subject");
|
||||||
|
}
|
||||||
if (allTimeScopeHint) {
|
if (allTimeScopeHint) {
|
||||||
pushReason(reasonCodes, "data_need_graph_all_time_scope_hint");
|
pushReason(reasonCodes, "data_need_graph_all_time_scope_hint");
|
||||||
}
|
}
|
||||||
|
|
@ -337,6 +364,8 @@ function buildAssistantMcpDiscoveryDataNeedGraph(input) {
|
||||||
schema_version: exports.ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
|
schema_version: exports.ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
|
||||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||||
subject_candidates: subjectCandidates,
|
subject_candidates: subjectCandidates,
|
||||||
|
metadata_scope_hint: metadataScopeHint,
|
||||||
|
subject_resolution_optional: subjectResolutionOptional || undefined,
|
||||||
business_fact_family: businessFactFamily,
|
business_fact_family: businessFactFamily,
|
||||||
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
|
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
|
||||||
aggregation_need: aggregationNeed,
|
aggregation_need: aggregationNeed,
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ function hasEntity(meaning) {
|
||||||
function hasSubjectCandidates(graph) {
|
function hasSubjectCandidates(graph) {
|
||||||
return (graph?.subject_candidates.length ?? 0) > 0;
|
return (graph?.subject_candidates.length ?? 0) > 0;
|
||||||
}
|
}
|
||||||
|
function hasMetadataScopedOpenLane(graph, meaning) {
|
||||||
|
return Boolean(graph?.subject_resolution_optional === true ||
|
||||||
|
meaning?.subject_resolution_optional === true);
|
||||||
|
}
|
||||||
function hasReasonCode(graph, reasonCode) {
|
function hasReasonCode(graph, reasonCode) {
|
||||||
return (graph?.reason_codes ?? []).includes(reasonCode);
|
return (graph?.reason_codes ?? []).includes(reasonCode);
|
||||||
}
|
}
|
||||||
|
|
@ -58,6 +62,11 @@ function addScopeAxes(axes, meaning) {
|
||||||
pushUnique(axes, "period");
|
pushUnique(axes, "period");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function addMetadataScopeAxis(axes, meaning) {
|
||||||
|
if (toNonEmptyString(meaning?.metadata_scope_hint)) {
|
||||||
|
pushUnique(axes, "metadata_scope");
|
||||||
|
}
|
||||||
|
}
|
||||||
function addTimeScopeAxes(axes, dataNeedGraph) {
|
function addTimeScopeAxes(axes, dataNeedGraph) {
|
||||||
if (dataNeedGraph?.time_scope_need === "all_time_scope") {
|
if (dataNeedGraph?.time_scope_need === "all_time_scope") {
|
||||||
pushUnique(axes, "all_time_scope");
|
pushUnique(axes, "all_time_scope");
|
||||||
|
|
@ -273,7 +282,7 @@ function recipeFor(input) {
|
||||||
const graphAction = lower(dataNeedGraph?.action_family);
|
const graphAction = lower(dataNeedGraph?.action_family);
|
||||||
const graphAggregation = lower(dataNeedGraph?.aggregation_need);
|
const graphAggregation = lower(dataNeedGraph?.aggregation_need);
|
||||||
const graphClarificationGaps = (dataNeedGraph?.clarification_gaps ?? []).map((item) => lower(item));
|
const graphClarificationGaps = (dataNeedGraph?.clarification_gaps ?? []).map((item) => lower(item));
|
||||||
const organizationScope = toNonEmptyString(meaning?.explicit_organization_scope);
|
const metadataScopedOpenLane = hasMetadataScopedOpenLane(dataNeedGraph, meaning);
|
||||||
const openScopeTotalWithoutSubject = graphFactFamily === "value_flow" &&
|
const openScopeTotalWithoutSubject = graphFactFamily === "value_flow" &&
|
||||||
!hasSubjectCandidates(dataNeedGraph) &&
|
!hasSubjectCandidates(dataNeedGraph) &&
|
||||||
hasReasonCode(dataNeedGraph, "data_need_graph_open_scope_total_without_subject");
|
hasReasonCode(dataNeedGraph, "data_need_graph_open_scope_total_without_subject");
|
||||||
|
|
@ -281,6 +290,7 @@ function recipeFor(input) {
|
||||||
const axes = [];
|
const axes = [];
|
||||||
const requestedAggregationAxis = aggregationAxis(meaning);
|
const requestedAggregationAxis = aggregationAxis(meaning);
|
||||||
addScopeAxes(axes, meaning);
|
addScopeAxes(axes, meaning);
|
||||||
|
addMetadataScopeAxis(axes, meaning);
|
||||||
addTimeScopeAxes(axes, dataNeedGraph);
|
addTimeScopeAxes(axes, dataNeedGraph);
|
||||||
if (graphClarificationGaps.includes("lane_family_choice")) {
|
if (graphClarificationGaps.includes("lane_family_choice")) {
|
||||||
pushUnique(axes, "lane_family_choice");
|
pushUnique(axes, "lane_family_choice");
|
||||||
|
|
@ -494,6 +504,26 @@ function recipeFor(input) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (graphFactFamily === "movement_evidence") {
|
if (graphFactFamily === "movement_evidence") {
|
||||||
|
if (metadataScopedOpenLane) {
|
||||||
|
pushUnique(axes, "organization");
|
||||||
|
pushUnique(axes, "coverage_target");
|
||||||
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
|
dataNeedGraph,
|
||||||
|
fallbackPrimitives: ["query_movements", "probe_coverage"],
|
||||||
|
requiredAxes: axes,
|
||||||
|
metadataSurface: input.metadataSurface,
|
||||||
|
actionFamily: action
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
semanticDataNeed: "movement evidence",
|
||||||
|
chainId: "movement_evidence",
|
||||||
|
chainSummary: "Keep the metadata-scoped movement lane, ask only for the remaining business scope, then fetch scoped movement rows and probe coverage without pretending there is a grounded counterparty.",
|
||||||
|
primitives: primitiveSelection.primitives,
|
||||||
|
axes,
|
||||||
|
reason: "planner_selected_metadata_scoped_movement_from_data_need_graph",
|
||||||
|
extraReasons: primitiveSelection.reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
pushUnique(axes, "coverage_target");
|
pushUnique(axes, "coverage_target");
|
||||||
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
dataNeedGraph,
|
dataNeedGraph,
|
||||||
|
|
@ -513,6 +543,26 @@ function recipeFor(input) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (graphFactFamily === "document_evidence") {
|
if (graphFactFamily === "document_evidence") {
|
||||||
|
if (metadataScopedOpenLane) {
|
||||||
|
pushUnique(axes, "organization");
|
||||||
|
pushUnique(axes, "coverage_target");
|
||||||
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
|
dataNeedGraph,
|
||||||
|
fallbackPrimitives: ["query_documents", "probe_coverage"],
|
||||||
|
requiredAxes: axes,
|
||||||
|
metadataSurface: input.metadataSurface,
|
||||||
|
actionFamily: action
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
semanticDataNeed: "document evidence",
|
||||||
|
chainId: "document_evidence",
|
||||||
|
chainSummary: "Keep the metadata-scoped document lane, ask only for the remaining business scope, then fetch scoped document rows and probe coverage without pretending there is a grounded counterparty.",
|
||||||
|
primitives: primitiveSelection.primitives,
|
||||||
|
axes,
|
||||||
|
reason: "planner_selected_metadata_scoped_document_from_data_need_graph",
|
||||||
|
extraReasons: primitiveSelection.reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
pushUnique(axes, "coverage_target");
|
pushUnique(axes, "coverage_target");
|
||||||
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
dataNeedGraph,
|
dataNeedGraph,
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,11 @@ function buildLoopState(planner, pilot, bridgeStatus) {
|
||||||
pending_axes: plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options"),
|
pending_axes: plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options"),
|
||||||
provided_axes: flattenAxes(pilot, "provided_axes"),
|
provided_axes: flattenAxes(pilot, "provided_axes"),
|
||||||
explicit_entity_candidates: entityCandidatesFromPlanner(planner),
|
explicit_entity_candidates: entityCandidatesFromPlanner(planner),
|
||||||
|
metadata_scope_hint: planner.discovery_plan.turn_meaning_ref?.metadata_scope_hint ??
|
||||||
|
planner.data_need_graph?.metadata_scope_hint ??
|
||||||
|
null,
|
||||||
|
subject_resolution_optional: planner.discovery_plan.turn_meaning_ref?.subject_resolution_optional === true ||
|
||||||
|
planner.data_need_graph?.subject_resolution_optional === true,
|
||||||
explicit_organization_scope: planner.discovery_plan.turn_meaning_ref?.explicit_organization_scope ?? null,
|
explicit_organization_scope: planner.discovery_plan.turn_meaning_ref?.explicit_organization_scope ?? null,
|
||||||
explicit_date_scope: planner.discovery_plan.turn_meaning_ref?.explicit_date_scope ?? null
|
explicit_date_scope: planner.discovery_plan.turn_meaning_ref?.explicit_date_scope ?? null
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,8 @@ function collectFollowupDiscoverySeed(followupContext) {
|
||||||
const loopAskedDomainFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_domain_family);
|
const loopAskedDomainFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_domain_family);
|
||||||
const loopAskedActionFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_action_family);
|
const loopAskedActionFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_action_family);
|
||||||
const loopUnsupportedFamily = toNonEmptyString(followupContext?.previous_discovery_loop_unsupported_family);
|
const loopUnsupportedFamily = toNonEmptyString(followupContext?.previous_discovery_loop_unsupported_family);
|
||||||
|
const loopMetadataScopeHint = toNonEmptyString(followupContext?.previous_discovery_loop_metadata_scope_hint);
|
||||||
|
const loopSubjectResolutionOptional = followupContext?.previous_discovery_loop_subject_resolution_optional === true;
|
||||||
const previousIntent = toNonEmptyString(followupContext?.target_intent) ?? toNonEmptyString(followupContext?.previous_intent);
|
const previousIntent = toNonEmptyString(followupContext?.target_intent) ?? toNonEmptyString(followupContext?.previous_intent);
|
||||||
const loopMapped = loopStatus === "awaiting_clarification"
|
const loopMapped = loopStatus === "awaiting_clarification"
|
||||||
? mapLoopClarificationSeedToFollowupMeaning({
|
? mapLoopClarificationSeedToFollowupMeaning({
|
||||||
|
|
@ -343,13 +345,16 @@ function collectFollowupDiscoverySeed(followupContext) {
|
||||||
const discoveryEntities = collectEntityCandidates(followupContext?.previous_discovery_entity_candidates);
|
const discoveryEntities = collectEntityCandidates(followupContext?.previous_discovery_entity_candidates);
|
||||||
const entityResolutionStatus = toNonEmptyString(followupContext?.previous_discovery_entity_resolution_status);
|
const entityResolutionStatus = toNonEmptyString(followupContext?.previous_discovery_entity_resolution_status);
|
||||||
const entityResolutionAmbiguityCandidates = collectEntityCandidates(followupContext?.previous_discovery_entity_ambiguity_candidates);
|
const entityResolutionAmbiguityCandidates = collectEntityCandidates(followupContext?.previous_discovery_entity_ambiguity_candidates);
|
||||||
const ambiguityBlocksImplicitGrounding = pilotScope === "entity_resolution_search_v1" && entityResolutionStatus === "ambiguous";
|
const ambiguityBlocksImplicitGrounding = effectivePilotScope === "entity_resolution_search_v1" && entityResolutionStatus === "ambiguous";
|
||||||
|
const metadataPilotCarriesScopeOnly = effectivePilotScope === "metadata_inspection_v1" || loopSubjectResolutionOptional;
|
||||||
|
const metadataScopeHint = loopMetadataScopeHint ??
|
||||||
|
(loopSubjectResolutionOptional ? discoveryEntities[0] ?? null : null);
|
||||||
const counterparty = toNonEmptyString(previousFilters?.counterparty) ??
|
const counterparty = toNonEmptyString(previousFilters?.counterparty) ??
|
||||||
toNonEmptyString(rootFilters?.counterparty) ??
|
toNonEmptyString(rootFilters?.counterparty) ??
|
||||||
(toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
|
(toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
|
||||||
? toNonEmptyString(followupContext?.previous_anchor_value)
|
? toNonEmptyString(followupContext?.previous_anchor_value)
|
||||||
: null) ??
|
: null) ??
|
||||||
(ambiguityBlocksImplicitGrounding ? null : discoveryEntities[0] ?? null);
|
(ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly ? null : discoveryEntities[0] ?? null);
|
||||||
const organization = toNonEmptyString(previousFilters?.organization) ??
|
const organization = toNonEmptyString(previousFilters?.organization) ??
|
||||||
toNonEmptyString(rootFilters?.organization) ??
|
toNonEmptyString(rootFilters?.organization) ??
|
||||||
(toNonEmptyString(followupContext?.previous_anchor_type) === "organization"
|
(toNonEmptyString(followupContext?.previous_anchor_type) === "organization"
|
||||||
|
|
@ -367,12 +372,14 @@ function collectFollowupDiscoverySeed(followupContext) {
|
||||||
loopPendingAxes,
|
loopPendingAxes,
|
||||||
loopProvidedAxes,
|
loopProvidedAxes,
|
||||||
counterparty,
|
counterparty,
|
||||||
discoveryEntity: ambiguityBlocksImplicitGrounding ? null : discoveryEntities[0] ?? null,
|
discoveryEntity: ambiguityBlocksImplicitGrounding || loopSubjectResolutionOptional ? null : discoveryEntities[0] ?? null,
|
||||||
entityResolutionStatus,
|
entityResolutionStatus,
|
||||||
entityResolutionAmbiguityCandidates,
|
entityResolutionAmbiguityCandidates,
|
||||||
rankingNeed: toNonEmptyString(followupContext?.previous_discovery_ranking_need),
|
rankingNeed: toNonEmptyString(followupContext?.previous_discovery_ranking_need),
|
||||||
organization,
|
organization,
|
||||||
dateScope,
|
dateScope,
|
||||||
|
metadataScopeHint,
|
||||||
|
subjectResolutionOptional: loopSubjectResolutionOptional,
|
||||||
metadataRouteFamily: normalizeMetadataRouteFamily(followupContext?.previous_discovery_metadata_route_family),
|
metadataRouteFamily: normalizeMetadataRouteFamily(followupContext?.previous_discovery_metadata_route_family),
|
||||||
metadataRouteFamilySelectionBasis: normalizeMetadataRouteFamilySelectionBasis(followupContext?.previous_discovery_metadata_route_family_selection_basis),
|
metadataRouteFamilySelectionBasis: normalizeMetadataRouteFamilySelectionBasis(followupContext?.previous_discovery_metadata_route_family_selection_basis),
|
||||||
metadataSelectedEntitySet: toNonEmptyString(followupContext?.previous_discovery_metadata_selected_entity_set),
|
metadataSelectedEntitySet: toNonEmptyString(followupContext?.previous_discovery_metadata_selected_entity_set),
|
||||||
|
|
@ -793,10 +800,15 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
hasMetadataObjectHint(rawText));
|
hasMetadataObjectHint(rawText));
|
||||||
|
const metadataLaneCarryoverAvailable = Boolean(followupSeed.counterparty ||
|
||||||
|
followupSeed.discoveryEntity ||
|
||||||
|
followupSeed.metadataScopeHint ||
|
||||||
|
followupSeed.metadataSelectedEntitySet ||
|
||||||
|
followupSeed.metadataSelectedSurfaceObjects.length > 0);
|
||||||
const metadataGroundedDocumentFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
const metadataGroundedDocumentFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataRouteFamily === "document_evidence" &&
|
followupSeed.metadataRouteFamily === "document_evidence" &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
metadataDocumentHintSignal);
|
metadataDocumentHintSignal);
|
||||||
|
|
@ -804,21 +816,21 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
||||||
metadataEntitySetsSuggestDocumentLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
metadataEntitySetsSuggestDocumentLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
metadataDocumentHintSignal);
|
metadataDocumentHintSignal);
|
||||||
const metadataGroundedMovementFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
const metadataGroundedMovementFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataRouteFamily === "movement_evidence" &&
|
followupSeed.metadataRouteFamily === "movement_evidence" &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
metadataMovementHintSignal);
|
metadataMovementHintSignal);
|
||||||
const metadataAmbiguityResolvedMovementFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
const metadataAmbiguityResolvedMovementFollowupApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
||||||
metadataEntitySetsSuggestMovementLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
metadataEntitySetsSuggestMovementLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
metadataMovementHintSignal);
|
metadataMovementHintSignal);
|
||||||
const entityResolutionGroundedDocumentFollowupApplicable = Boolean(followupSeed.pilotScope === "entity_resolution_search_v1" &&
|
const entityResolutionGroundedDocumentFollowupApplicable = Boolean(followupSeed.pilotScope === "entity_resolution_search_v1" &&
|
||||||
|
|
@ -886,7 +898,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
(followupSeed.metadataRouteFamily === "document_evidence" ||
|
(followupSeed.metadataRouteFamily === "document_evidence" ||
|
||||||
followupSeed.metadataRouteFamily === "movement_evidence") &&
|
followupSeed.metadataRouteFamily === "movement_evidence") &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -905,7 +917,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
const metadataAmbiguityCollapsedDocumentLaneContinuationApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
const metadataAmbiguityCollapsedDocumentLaneContinuationApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -915,7 +927,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
const metadataAmbiguityCollapsedMovementLaneContinuationApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
const metadataAmbiguityCollapsedMovementLaneContinuationApplicable = Boolean(followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -926,7 +938,7 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
!metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
!metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
!metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
!metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -935,6 +947,14 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
hasMetadataDownstreamContinuationSignal(rawText));
|
hasMetadataDownstreamContinuationSignal(rawText));
|
||||||
const metadataGroundedDocumentLaneApplicable = metadataGroundedDocumentFollowupApplicable ||
|
const metadataGroundedDocumentLaneApplicable = metadataGroundedDocumentFollowupApplicable ||
|
||||||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
||||||
|
(followupSeed.subjectResolutionOptional &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
!rawMetadataSignal &&
|
||||||
|
followupSeed.domain === "documents" &&
|
||||||
|
followupSeed.action === "list_documents") ||
|
||||||
entityResolutionGroundedDocumentFollowupApplicable ||
|
entityResolutionGroundedDocumentFollowupApplicable ||
|
||||||
entityResolutionClarifiedDocumentFollowupApplicable ||
|
entityResolutionClarifiedDocumentFollowupApplicable ||
|
||||||
valueFlowGroundedDocumentFollowupApplicable ||
|
valueFlowGroundedDocumentFollowupApplicable ||
|
||||||
|
|
@ -943,6 +963,14 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
metadataAmbiguityCollapsedDocumentLaneContinuationApplicable;
|
metadataAmbiguityCollapsedDocumentLaneContinuationApplicable;
|
||||||
const metadataGroundedMovementLaneApplicable = metadataGroundedMovementFollowupApplicable ||
|
const metadataGroundedMovementLaneApplicable = metadataGroundedMovementFollowupApplicable ||
|
||||||
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
||||||
|
(followupSeed.subjectResolutionOptional &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
!rawMetadataSignal &&
|
||||||
|
followupSeed.domain === "movements" &&
|
||||||
|
followupSeed.action === "list_movements") ||
|
||||||
entityResolutionGroundedMovementFollowupApplicable ||
|
entityResolutionGroundedMovementFollowupApplicable ||
|
||||||
entityResolutionClarifiedMovementFollowupApplicable ||
|
entityResolutionClarifiedMovementFollowupApplicable ||
|
||||||
valueFlowGroundedMovementFollowupApplicable ||
|
valueFlowGroundedMovementFollowupApplicable ||
|
||||||
|
|
@ -1009,7 +1037,17 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
!metadataGroundedDocumentLaneApplicable &&
|
!metadataGroundedDocumentLaneApplicable &&
|
||||||
!metadataGroundedMovementLaneApplicable
|
!metadataGroundedMovementLaneApplicable
|
||||||
});
|
});
|
||||||
const groundedFollowupEntity = followupSeed.counterparty ?? followupSeed.discoveryEntity;
|
const metadataLaneScopeHint = rawMetadataScopeHint ??
|
||||||
|
followupSeed.metadataScopeHint ??
|
||||||
|
followupSeed.discoveryEntity ??
|
||||||
|
followupSeed.metadataSelectedEntitySet ??
|
||||||
|
null;
|
||||||
|
const metadataScopedLaneWithoutSubject = Boolean((metadataGroundedMovementLaneApplicable || metadataGroundedDocumentLaneApplicable) &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable);
|
||||||
|
const groundedFollowupEntity = metadataScopedLaneWithoutSubject
|
||||||
|
? null
|
||||||
|
: followupSeed.counterparty ?? followupSeed.discoveryEntity;
|
||||||
const entityCandidates = entityResolutionSignal ? [] : [];
|
const entityCandidates = entityResolutionSignal ? [] : [];
|
||||||
if (entityResolutionSignal) {
|
if (entityResolutionSignal) {
|
||||||
pushNormalizedEntityResolutionCandidate(entityCandidates, entityResolutionClarificationCandidate);
|
pushNormalizedEntityResolutionCandidate(entityCandidates, entityResolutionClarificationCandidate);
|
||||||
|
|
@ -1030,11 +1068,15 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
pushScopedEntityCandidate(entityCandidates, normalizedPredecomposeCounterparty, groundedFollowupEntity);
|
pushScopedEntityCandidate(entityCandidates, normalizedPredecomposeCounterparty, groundedFollowupEntity);
|
||||||
if (!groundedFollowupEntity) {
|
if (!groundedFollowupEntity) {
|
||||||
pushScopedEntityCandidate(entityCandidates, followupSeed.counterparty, null);
|
pushScopedEntityCandidate(entityCandidates, followupSeed.counterparty, null);
|
||||||
pushScopedEntityCandidate(entityCandidates, followupSeed.discoveryEntity, null);
|
if (!metadataScopedLaneWithoutSubject) {
|
||||||
|
pushScopedEntityCandidate(entityCandidates, followupSeed.discoveryEntity, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity);
|
pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity);
|
||||||
}
|
}
|
||||||
if ((rawMetadataSignal || metadataFollowupSeedApplicable) && !groundedFollowupEntity) {
|
if ((rawMetadataSignal || metadataFollowupSeedApplicable) &&
|
||||||
|
!groundedFollowupEntity &&
|
||||||
|
!metadataScopedLaneWithoutSubject) {
|
||||||
pushUnique(entityCandidates, followupSeed.discoveryEntity);
|
pushUnique(entityCandidates, followupSeed.discoveryEntity);
|
||||||
pushUnique(entityCandidates, rawMetadataScopeHint);
|
pushUnique(entityCandidates, rawMetadataScopeHint);
|
||||||
}
|
}
|
||||||
|
|
@ -1126,8 +1168,10 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
metadata_ambiguity_entity_sets: metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0
|
metadata_ambiguity_entity_sets: metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0
|
||||||
? followupSeed.metadataAmbiguityEntitySets
|
? followupSeed.metadataAmbiguityEntitySets
|
||||||
: undefined,
|
: undefined,
|
||||||
|
metadata_scope_hint: metadataLaneScopeHint,
|
||||||
explicit_organization_scope: explicitOrganizationScope,
|
explicit_organization_scope: explicitOrganizationScope,
|
||||||
explicit_date_scope: explicitDateScope,
|
explicit_date_scope: explicitDateScope,
|
||||||
|
subject_resolution_optional: metadataScopedLaneWithoutSubject || undefined,
|
||||||
unsupported_but_understood_family: unsupported ??
|
unsupported_but_understood_family: unsupported ??
|
||||||
(lifecycleSignal
|
(lifecycleSignal
|
||||||
? "counterparty_lifecycle"
|
? "counterparty_lifecycle"
|
||||||
|
|
@ -1181,12 +1225,18 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
if ((turnMeaning.metadata_ambiguity_entity_sets?.length ?? 0) > 0) {
|
if ((turnMeaning.metadata_ambiguity_entity_sets?.length ?? 0) > 0) {
|
||||||
cleanTurnMeaning.metadata_ambiguity_entity_sets = turnMeaning.metadata_ambiguity_entity_sets;
|
cleanTurnMeaning.metadata_ambiguity_entity_sets = turnMeaning.metadata_ambiguity_entity_sets;
|
||||||
}
|
}
|
||||||
|
if (toNonEmptyString(turnMeaning.metadata_scope_hint)) {
|
||||||
|
cleanTurnMeaning.metadata_scope_hint = turnMeaning.metadata_scope_hint;
|
||||||
|
}
|
||||||
if (toNonEmptyString(turnMeaning.explicit_organization_scope)) {
|
if (toNonEmptyString(turnMeaning.explicit_organization_scope)) {
|
||||||
cleanTurnMeaning.explicit_organization_scope = turnMeaning.explicit_organization_scope;
|
cleanTurnMeaning.explicit_organization_scope = turnMeaning.explicit_organization_scope;
|
||||||
}
|
}
|
||||||
if (toNonEmptyString(turnMeaning.explicit_date_scope)) {
|
if (toNonEmptyString(turnMeaning.explicit_date_scope)) {
|
||||||
cleanTurnMeaning.explicit_date_scope = turnMeaning.explicit_date_scope;
|
cleanTurnMeaning.explicit_date_scope = turnMeaning.explicit_date_scope;
|
||||||
}
|
}
|
||||||
|
if (turnMeaning.subject_resolution_optional) {
|
||||||
|
cleanTurnMeaning.subject_resolution_optional = true;
|
||||||
|
}
|
||||||
if (toNonEmptyString(turnMeaning.unsupported_but_understood_family)) {
|
if (toNonEmptyString(turnMeaning.unsupported_but_understood_family)) {
|
||||||
cleanTurnMeaning.unsupported_but_understood_family = turnMeaning.unsupported_but_understood_family;
|
cleanTurnMeaning.unsupported_but_understood_family = turnMeaning.unsupported_but_understood_family;
|
||||||
}
|
}
|
||||||
|
|
@ -1299,6 +1349,9 @@ function buildAssistantMcpDiscoveryTurnInput(input) {
|
||||||
if (metadataAmbiguityResolvedMovementFollowupApplicable) {
|
if (metadataAmbiguityResolvedMovementFollowupApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
||||||
}
|
}
|
||||||
|
if (metadataScopedLaneWithoutSubject) {
|
||||||
|
pushReason(reasonCodes, "mcp_discovery_metadata_scoped_lane_without_subject");
|
||||||
|
}
|
||||||
if (entityResolutionGroundedDocumentFollowupApplicable) {
|
if (entityResolutionGroundedDocumentFollowupApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_document_followup");
|
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_document_followup");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -515,6 +515,8 @@ function createAssistantTransitionPolicy(deps) {
|
||||||
const sourceDiscoveryLoopAskedDomainFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopAskedDomainFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryLoopAskedDomainFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopAskedDomainFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const sourceDiscoveryLoopAskedActionFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopAskedActionFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryLoopAskedActionFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopAskedActionFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const sourceDiscoveryLoopUnsupportedFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopUnsupportedFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryLoopUnsupportedFamily = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopUnsupportedFamily)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryLoopMetadataScopeHint = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopMetadataScopeHint)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
|
const sourceDiscoveryLoopSubjectResolutionOptional = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryLoopSubjectResolutionOptional)(carryoverSourceDebug);
|
||||||
const sourceDiscoveryRankingNeed = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryRankingNeed)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryRankingNeed = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryRankingNeed)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const sourceDiscoveryEntityAmbiguityCandidates = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryEntityAmbiguityCandidates)(carryoverSourceDebug, deps.toNonEmptyString);
|
const sourceDiscoveryEntityAmbiguityCandidates = (0, assistantContinuityPolicy_1.readAssistantMcpDiscoveryEntityAmbiguityCandidates)(carryoverSourceDebug, deps.toNonEmptyString);
|
||||||
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
const llmExplicitIntent = deps.toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
|
||||||
|
|
@ -760,6 +762,8 @@ function createAssistantTransitionPolicy(deps) {
|
||||||
previous_discovery_loop_asked_domain_family: sourceDiscoveryLoopAskedDomainFamily ?? undefined,
|
previous_discovery_loop_asked_domain_family: sourceDiscoveryLoopAskedDomainFamily ?? undefined,
|
||||||
previous_discovery_loop_asked_action_family: sourceDiscoveryLoopAskedActionFamily ?? undefined,
|
previous_discovery_loop_asked_action_family: sourceDiscoveryLoopAskedActionFamily ?? undefined,
|
||||||
previous_discovery_loop_unsupported_family: sourceDiscoveryLoopUnsupportedFamily ?? undefined,
|
previous_discovery_loop_unsupported_family: sourceDiscoveryLoopUnsupportedFamily ?? undefined,
|
||||||
|
previous_discovery_loop_metadata_scope_hint: sourceDiscoveryLoopMetadataScopeHint ?? undefined,
|
||||||
|
previous_discovery_loop_subject_resolution_optional: sourceDiscoveryLoopSubjectResolutionOptional || undefined,
|
||||||
previous_discovery_ranking_need: sourceDiscoveryRankingNeed ?? undefined,
|
previous_discovery_ranking_need: sourceDiscoveryRankingNeed ?? undefined,
|
||||||
previous_discovery_entity_ambiguity_candidates: sourceDiscoveryEntityAmbiguityCandidates.length > 0
|
previous_discovery_entity_ambiguity_candidates: sourceDiscoveryEntityAmbiguityCandidates.length > 0
|
||||||
? sourceDiscoveryEntityAmbiguityCandidates
|
? sourceDiscoveryEntityAmbiguityCandidates
|
||||||
|
|
|
||||||
|
|
@ -329,6 +329,27 @@ export function readAssistantMcpDiscoveryLoopUnsupportedFamily(
|
||||||
return toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.unsupported_but_understood_family);
|
return toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.unsupported_but_understood_family);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readAssistantMcpDiscoveryLoopMetadataScopeHint(
|
||||||
|
debug: Record<string, unknown> | null,
|
||||||
|
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||||
|
): string | null {
|
||||||
|
return (
|
||||||
|
toNonEmptyString(readAssistantMcpDiscoveryLoopState(debug)?.metadata_scope_hint) ??
|
||||||
|
toNonEmptyString(readAssistantMcpDiscoveryTurnMeaning(debug)?.metadata_scope_hint) ??
|
||||||
|
toNonEmptyString(readAssistantMcpDiscoveryDataNeedGraph(debug)?.metadata_scope_hint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readAssistantMcpDiscoveryLoopSubjectResolutionOptional(
|
||||||
|
debug: Record<string, unknown> | null
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
readAssistantMcpDiscoveryLoopState(debug)?.subject_resolution_optional === true ||
|
||||||
|
readAssistantMcpDiscoveryTurnMeaning(debug)?.subject_resolution_optional === true ||
|
||||||
|
readAssistantMcpDiscoveryDataNeedGraph(debug)?.subject_resolution_optional === true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function readAssistantMcpDiscoveryMetadataRouteFamily(
|
export function readAssistantMcpDiscoveryMetadataRouteFamily(
|
||||||
debug: Record<string, unknown> | null,
|
debug: Record<string, unknown> | null,
|
||||||
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
toNonEmptyString: (value: unknown) => string | null = fallbackToNonEmptyString
|
||||||
|
|
@ -557,6 +578,13 @@ export function readAddressDebugCounterparty(
|
||||||
if (String(debug?.anchor_type ?? "") === "counterparty") {
|
if (String(debug?.anchor_type ?? "") === "counterparty") {
|
||||||
return toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
|
return toNonEmptyString(debug?.anchor_value_resolved) ?? toNonEmptyString(debug?.anchor_value_raw);
|
||||||
}
|
}
|
||||||
|
const discoveryPilotScope = readAssistantMcpDiscoveryPilotScope(debug, toNonEmptyString);
|
||||||
|
const suppressDiscoveryEntityCarryover =
|
||||||
|
discoveryPilotScope === "metadata_inspection_v1" ||
|
||||||
|
readAssistantMcpDiscoveryLoopSubjectResolutionOptional(debug);
|
||||||
|
if (suppressDiscoveryEntityCarryover) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const discoveryEntities = collectAssistantMcpDiscoveryEntityCandidates(debug, toNonEmptyString);
|
const discoveryEntities = collectAssistantMcpDiscoveryEntityCandidates(debug, toNonEmptyString);
|
||||||
for (const entity of discoveryEntities) {
|
for (const entity of discoveryEntities) {
|
||||||
const text = toNonEmptyString(entity);
|
const text = toNonEmptyString(entity);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ export interface AssistantMcpDiscoveryDataNeedGraphContract {
|
||||||
schema_version: typeof ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION;
|
schema_version: typeof ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION;
|
||||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph";
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph";
|
||||||
subject_candidates: string[];
|
subject_candidates: string[];
|
||||||
|
metadata_scope_hint?: string | null;
|
||||||
|
subject_resolution_optional?: boolean;
|
||||||
business_fact_family: string | null;
|
business_fact_family: string | null;
|
||||||
action_family: string | null;
|
action_family: string | null;
|
||||||
aggregation_need: string | null;
|
aggregation_need: string | null;
|
||||||
|
|
@ -205,6 +207,16 @@ function allowsOpenScopeWithoutSubject(input: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function allowsMetadataScopedOpenLaneWithoutSubject(input: {
|
||||||
|
family: string | null;
|
||||||
|
subjectResolutionOptional: boolean;
|
||||||
|
}): boolean {
|
||||||
|
return Boolean(
|
||||||
|
input.subjectResolutionOptional &&
|
||||||
|
(input.family === "movement_evidence" || input.family === "document_evidence")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function rankingNeedFromRawUtterance(value: string): string | null {
|
function rankingNeedFromRawUtterance(value: string): string | null {
|
||||||
const text = lower(value);
|
const text = lower(value);
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
|
@ -249,6 +261,7 @@ function decompositionCandidatesFor(input: {
|
||||||
comparisonNeed: string | null;
|
comparisonNeed: string | null;
|
||||||
rankingNeed: string | null;
|
rankingNeed: string | null;
|
||||||
openScopeWithoutSubject: boolean;
|
openScopeWithoutSubject: boolean;
|
||||||
|
metadataScopedOpenLaneWithoutSubject: boolean;
|
||||||
}): string[] {
|
}): string[] {
|
||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
if (input.family === "schema_surface") {
|
if (input.family === "schema_surface") {
|
||||||
|
|
@ -295,13 +308,17 @@ function decompositionCandidatesFor(input: {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (input.family === "movement_evidence") {
|
if (input.family === "movement_evidence") {
|
||||||
pushUnique(result, "resolve_entity_reference");
|
if (!input.metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushUnique(result, "resolve_entity_reference");
|
||||||
|
}
|
||||||
pushUnique(result, "fetch_scoped_movements");
|
pushUnique(result, "fetch_scoped_movements");
|
||||||
pushUnique(result, "probe_coverage");
|
pushUnique(result, "probe_coverage");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (input.family === "document_evidence") {
|
if (input.family === "document_evidence") {
|
||||||
pushUnique(result, "resolve_entity_reference");
|
if (!input.metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushUnique(result, "resolve_entity_reference");
|
||||||
|
}
|
||||||
pushUnique(result, "fetch_scoped_documents");
|
pushUnique(result, "fetch_scoped_documents");
|
||||||
pushUnique(result, "probe_coverage");
|
pushUnique(result, "probe_coverage");
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -345,6 +362,8 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
const seededRankingNeed = toNonEmptyString(turnMeaning?.seeded_ranking_need);
|
const seededRankingNeed = toNonEmptyString(turnMeaning?.seeded_ranking_need);
|
||||||
const explicitDateScope = toNonEmptyString(turnMeaning?.explicit_date_scope);
|
const explicitDateScope = toNonEmptyString(turnMeaning?.explicit_date_scope);
|
||||||
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
const explicitOrganizationScope = toNonEmptyString(turnMeaning?.explicit_organization_scope);
|
||||||
|
const metadataScopeHint = toNonEmptyString(turnMeaning?.metadata_scope_hint);
|
||||||
|
const subjectResolutionOptional = turnMeaning?.subject_resolution_optional === true;
|
||||||
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
const subjectCandidates = (turnMeaning?.explicit_entity_candidates ?? [])
|
||||||
.map((item) => toNonEmptyString(item))
|
.map((item) => toNonEmptyString(item))
|
||||||
.filter((item): item is string => Boolean(item));
|
.filter((item): item is string => Boolean(item));
|
||||||
|
|
@ -369,6 +388,12 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
rankingNeed,
|
rankingNeed,
|
||||||
oneSidedOpenScopeTotalHint
|
oneSidedOpenScopeTotalHint
|
||||||
});
|
});
|
||||||
|
const metadataScopedOpenLaneWithoutSubject =
|
||||||
|
subjectCandidates.length === 0 &&
|
||||||
|
allowsMetadataScopedOpenLaneWithoutSubject({
|
||||||
|
family: businessFactFamily,
|
||||||
|
subjectResolutionOptional
|
||||||
|
});
|
||||||
const clarificationGaps: string[] = [];
|
const clarificationGaps: string[] = [];
|
||||||
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
|
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
|
||||||
pushUnique(clarificationGaps, "lane_family_choice");
|
pushUnique(clarificationGaps, "lane_family_choice");
|
||||||
|
|
@ -380,7 +405,18 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
!explicitOrganizationScope
|
!explicitOrganizationScope
|
||||||
) {
|
) {
|
||||||
pushUnique(clarificationGaps, "organization");
|
pushUnique(clarificationGaps, "organization");
|
||||||
} else if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && !openScopeWithoutSubject) {
|
} else if (
|
||||||
|
subjectCandidates.length === 0 &&
|
||||||
|
metadataScopedOpenLaneWithoutSubject &&
|
||||||
|
!explicitOrganizationScope
|
||||||
|
) {
|
||||||
|
pushUnique(clarificationGaps, "organization");
|
||||||
|
} else if (
|
||||||
|
subjectCandidates.length === 0 &&
|
||||||
|
businessFactFamily !== "schema_surface" &&
|
||||||
|
!openScopeWithoutSubject &&
|
||||||
|
!metadataScopedOpenLaneWithoutSubject
|
||||||
|
) {
|
||||||
pushUnique(clarificationGaps, "subject");
|
pushUnique(clarificationGaps, "subject");
|
||||||
}
|
}
|
||||||
const timeScopeNeed = timeScopeNeedFor({
|
const timeScopeNeed = timeScopeNeedFor({
|
||||||
|
|
@ -393,12 +429,13 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
}
|
}
|
||||||
const decompositionCandidates = decompositionCandidatesFor({
|
const decompositionCandidates = decompositionCandidatesFor({
|
||||||
family: businessFactFamily,
|
family: businessFactFamily,
|
||||||
action,
|
action,
|
||||||
aggregationNeed,
|
aggregationNeed,
|
||||||
comparisonNeed,
|
comparisonNeed,
|
||||||
rankingNeed,
|
rankingNeed,
|
||||||
openScopeWithoutSubject
|
openScopeWithoutSubject,
|
||||||
});
|
metadataScopedOpenLaneWithoutSubject
|
||||||
|
});
|
||||||
const reasonCodes: string[] = [];
|
const reasonCodes: string[] = [];
|
||||||
pushReason(reasonCodes, "data_need_graph_built");
|
pushReason(reasonCodes, "data_need_graph_built");
|
||||||
if (businessFactFamily) {
|
if (businessFactFamily) {
|
||||||
|
|
@ -418,6 +455,9 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
|
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
|
||||||
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
|
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
|
||||||
}
|
}
|
||||||
|
if (metadataScopedOpenLaneWithoutSubject) {
|
||||||
|
pushReason(reasonCodes, "data_need_graph_metadata_scoped_open_lane_without_subject");
|
||||||
|
}
|
||||||
if (allTimeScopeHint) {
|
if (allTimeScopeHint) {
|
||||||
pushReason(reasonCodes, "data_need_graph_all_time_scope_hint");
|
pushReason(reasonCodes, "data_need_graph_all_time_scope_hint");
|
||||||
}
|
}
|
||||||
|
|
@ -432,6 +472,8 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||||
schema_version: ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
|
schema_version: ASSISTANT_MCP_DISCOVERY_DATA_NEED_GRAPH_SCHEMA_VERSION,
|
||||||
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||||
subject_candidates: subjectCandidates,
|
subject_candidates: subjectCandidates,
|
||||||
|
metadata_scope_hint: metadataScopeHint,
|
||||||
|
subject_resolution_optional: subjectResolutionOptional || undefined,
|
||||||
business_fact_family: businessFactFamily,
|
business_fact_family: businessFactFamily,
|
||||||
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
|
action_family: toNonEmptyString(turnMeaning?.asked_action_family),
|
||||||
aggregation_need: aggregationNeed,
|
aggregation_need: aggregationNeed,
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,16 @@ function hasSubjectCandidates(graph: AssistantMcpDiscoveryDataNeedGraphContract
|
||||||
return (graph?.subject_candidates.length ?? 0) > 0;
|
return (graph?.subject_candidates.length ?? 0) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasMetadataScopedOpenLane(
|
||||||
|
graph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined,
|
||||||
|
meaning: AssistantMcpDiscoveryTurnMeaningRef | null | undefined
|
||||||
|
): boolean {
|
||||||
|
return Boolean(
|
||||||
|
graph?.subject_resolution_optional === true ||
|
||||||
|
meaning?.subject_resolution_optional === true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function hasReasonCode(
|
function hasReasonCode(
|
||||||
graph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined,
|
graph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined,
|
||||||
reasonCode: string
|
reasonCode: string
|
||||||
|
|
@ -150,6 +160,12 @@ function addScopeAxes(axes: string[], meaning: AssistantMcpDiscoveryTurnMeaningR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addMetadataScopeAxis(axes: string[], meaning: AssistantMcpDiscoveryTurnMeaningRef | null | undefined): void {
|
||||||
|
if (toNonEmptyString(meaning?.metadata_scope_hint)) {
|
||||||
|
pushUnique(axes, "metadata_scope");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function addTimeScopeAxes(
|
function addTimeScopeAxes(
|
||||||
axes: string[],
|
axes: string[],
|
||||||
dataNeedGraph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined
|
dataNeedGraph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined
|
||||||
|
|
@ -417,7 +433,7 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||||
const graphAction = lower(dataNeedGraph?.action_family);
|
const graphAction = lower(dataNeedGraph?.action_family);
|
||||||
const graphAggregation = lower(dataNeedGraph?.aggregation_need);
|
const graphAggregation = lower(dataNeedGraph?.aggregation_need);
|
||||||
const graphClarificationGaps = (dataNeedGraph?.clarification_gaps ?? []).map((item) => lower(item));
|
const graphClarificationGaps = (dataNeedGraph?.clarification_gaps ?? []).map((item) => lower(item));
|
||||||
const organizationScope = toNonEmptyString(meaning?.explicit_organization_scope);
|
const metadataScopedOpenLane = hasMetadataScopedOpenLane(dataNeedGraph, meaning);
|
||||||
const openScopeTotalWithoutSubject =
|
const openScopeTotalWithoutSubject =
|
||||||
graphFactFamily === "value_flow" &&
|
graphFactFamily === "value_flow" &&
|
||||||
!hasSubjectCandidates(dataNeedGraph) &&
|
!hasSubjectCandidates(dataNeedGraph) &&
|
||||||
|
|
@ -426,6 +442,7 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||||
const axes: string[] = [];
|
const axes: string[] = [];
|
||||||
const requestedAggregationAxis = aggregationAxis(meaning);
|
const requestedAggregationAxis = aggregationAxis(meaning);
|
||||||
addScopeAxes(axes, meaning);
|
addScopeAxes(axes, meaning);
|
||||||
|
addMetadataScopeAxis(axes, meaning);
|
||||||
addTimeScopeAxes(axes, dataNeedGraph);
|
addTimeScopeAxes(axes, dataNeedGraph);
|
||||||
|
|
||||||
if (graphClarificationGaps.includes("lane_family_choice")) {
|
if (graphClarificationGaps.includes("lane_family_choice")) {
|
||||||
|
|
@ -654,6 +671,27 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graphFactFamily === "movement_evidence") {
|
if (graphFactFamily === "movement_evidence") {
|
||||||
|
if (metadataScopedOpenLane) {
|
||||||
|
pushUnique(axes, "organization");
|
||||||
|
pushUnique(axes, "coverage_target");
|
||||||
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
|
dataNeedGraph,
|
||||||
|
fallbackPrimitives: ["query_movements", "probe_coverage"],
|
||||||
|
requiredAxes: axes,
|
||||||
|
metadataSurface: input.metadataSurface,
|
||||||
|
actionFamily: action
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
semanticDataNeed: "movement evidence",
|
||||||
|
chainId: "movement_evidence",
|
||||||
|
chainSummary:
|
||||||
|
"Keep the metadata-scoped movement lane, ask only for the remaining business scope, then fetch scoped movement rows and probe coverage without pretending there is a grounded counterparty.",
|
||||||
|
primitives: primitiveSelection.primitives,
|
||||||
|
axes,
|
||||||
|
reason: "planner_selected_metadata_scoped_movement_from_data_need_graph",
|
||||||
|
extraReasons: primitiveSelection.reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
pushUnique(axes, "coverage_target");
|
pushUnique(axes, "coverage_target");
|
||||||
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
dataNeedGraph,
|
dataNeedGraph,
|
||||||
|
|
@ -674,6 +712,27 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graphFactFamily === "document_evidence") {
|
if (graphFactFamily === "document_evidence") {
|
||||||
|
if (metadataScopedOpenLane) {
|
||||||
|
pushUnique(axes, "organization");
|
||||||
|
pushUnique(axes, "coverage_target");
|
||||||
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
|
dataNeedGraph,
|
||||||
|
fallbackPrimitives: ["query_documents", "probe_coverage"],
|
||||||
|
requiredAxes: axes,
|
||||||
|
metadataSurface: input.metadataSurface,
|
||||||
|
actionFamily: action
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
semanticDataNeed: "document evidence",
|
||||||
|
chainId: "document_evidence",
|
||||||
|
chainSummary:
|
||||||
|
"Keep the metadata-scoped document lane, ask only for the remaining business scope, then fetch scoped document rows and probe coverage without pretending there is a grounded counterparty.",
|
||||||
|
primitives: primitiveSelection.primitives,
|
||||||
|
axes,
|
||||||
|
reason: "planner_selected_metadata_scoped_document_from_data_need_graph",
|
||||||
|
extraReasons: primitiveSelection.reasonCodes
|
||||||
|
};
|
||||||
|
}
|
||||||
pushUnique(axes, "coverage_target");
|
pushUnique(axes, "coverage_target");
|
||||||
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
const primitiveSelection = selectPrimitivesFromGraphAndCatalog({
|
||||||
dataNeedGraph,
|
dataNeedGraph,
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,10 @@ export interface AssistantMcpDiscoveryTurnMeaningRef {
|
||||||
seeded_ranking_need?: string | null;
|
seeded_ranking_need?: string | null;
|
||||||
explicit_entity_candidates?: string[];
|
explicit_entity_candidates?: string[];
|
||||||
metadata_ambiguity_entity_sets?: string[];
|
metadata_ambiguity_entity_sets?: string[];
|
||||||
|
metadata_scope_hint?: string | null;
|
||||||
explicit_organization_scope?: string | null;
|
explicit_organization_scope?: string | null;
|
||||||
explicit_date_scope?: string | null;
|
explicit_date_scope?: string | null;
|
||||||
|
subject_resolution_optional?: boolean | null;
|
||||||
meaning_confidence?: number | null;
|
meaning_confidence?: number | null;
|
||||||
unsupported_but_understood_family?: string | null;
|
unsupported_but_understood_family?: string | null;
|
||||||
stale_replay_forbidden?: boolean | null;
|
stale_replay_forbidden?: boolean | null;
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ export interface AssistantMcpDiscoveryLoopStateContract {
|
||||||
pending_axes: string[];
|
pending_axes: string[];
|
||||||
provided_axes: string[];
|
provided_axes: string[];
|
||||||
explicit_entity_candidates: string[];
|
explicit_entity_candidates: string[];
|
||||||
|
metadata_scope_hint: string | null;
|
||||||
|
subject_resolution_optional: boolean;
|
||||||
explicit_organization_scope: string | null;
|
explicit_organization_scope: string | null;
|
||||||
explicit_date_scope: string | null;
|
explicit_date_scope: string | null;
|
||||||
}
|
}
|
||||||
|
|
@ -184,6 +186,13 @@ function buildLoopState(
|
||||||
pending_axes: plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options"),
|
pending_axes: plannerClarificationGaps.length > 0 ? plannerClarificationGaps : flattenAxes(pilot, "missing_axis_options"),
|
||||||
provided_axes: flattenAxes(pilot, "provided_axes"),
|
provided_axes: flattenAxes(pilot, "provided_axes"),
|
||||||
explicit_entity_candidates: entityCandidatesFromPlanner(planner),
|
explicit_entity_candidates: entityCandidatesFromPlanner(planner),
|
||||||
|
metadata_scope_hint:
|
||||||
|
planner.discovery_plan.turn_meaning_ref?.metadata_scope_hint ??
|
||||||
|
planner.data_need_graph?.metadata_scope_hint ??
|
||||||
|
null,
|
||||||
|
subject_resolution_optional:
|
||||||
|
planner.discovery_plan.turn_meaning_ref?.subject_resolution_optional === true ||
|
||||||
|
planner.data_need_graph?.subject_resolution_optional === true,
|
||||||
explicit_organization_scope: planner.discovery_plan.turn_meaning_ref?.explicit_organization_scope ?? null,
|
explicit_organization_scope: planner.discovery_plan.turn_meaning_ref?.explicit_organization_scope ?? null,
|
||||||
explicit_date_scope: planner.discovery_plan.turn_meaning_ref?.explicit_date_scope ?? null
|
explicit_date_scope: planner.discovery_plan.turn_meaning_ref?.explicit_date_scope ?? null
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -427,6 +427,8 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
rankingNeed: string | null;
|
rankingNeed: string | null;
|
||||||
organization: string | null;
|
organization: string | null;
|
||||||
dateScope: string | null;
|
dateScope: string | null;
|
||||||
|
metadataScopeHint: string | null;
|
||||||
|
subjectResolutionOptional: boolean;
|
||||||
metadataRouteFamily: AssistantMcpDiscoveryMetadataRouteFamily | null;
|
metadataRouteFamily: AssistantMcpDiscoveryMetadataRouteFamily | null;
|
||||||
metadataRouteFamilySelectionBasis: AssistantMcpDiscoveryMetadataSurfaceRef["route_family_selection_basis"];
|
metadataRouteFamilySelectionBasis: AssistantMcpDiscoveryMetadataSurfaceRef["route_family_selection_basis"];
|
||||||
metadataSelectedEntitySet: string | null;
|
metadataSelectedEntitySet: string | null;
|
||||||
|
|
@ -445,6 +447,9 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
const loopAskedDomainFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_domain_family);
|
const loopAskedDomainFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_domain_family);
|
||||||
const loopAskedActionFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_action_family);
|
const loopAskedActionFamily = toNonEmptyString(followupContext?.previous_discovery_loop_asked_action_family);
|
||||||
const loopUnsupportedFamily = toNonEmptyString(followupContext?.previous_discovery_loop_unsupported_family);
|
const loopUnsupportedFamily = toNonEmptyString(followupContext?.previous_discovery_loop_unsupported_family);
|
||||||
|
const loopMetadataScopeHint = toNonEmptyString(followupContext?.previous_discovery_loop_metadata_scope_hint);
|
||||||
|
const loopSubjectResolutionOptional =
|
||||||
|
followupContext?.previous_discovery_loop_subject_resolution_optional === true;
|
||||||
const previousIntent =
|
const previousIntent =
|
||||||
toNonEmptyString(followupContext?.target_intent) ?? toNonEmptyString(followupContext?.previous_intent);
|
toNonEmptyString(followupContext?.target_intent) ?? toNonEmptyString(followupContext?.previous_intent);
|
||||||
const loopMapped =
|
const loopMapped =
|
||||||
|
|
@ -474,14 +479,19 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
followupContext?.previous_discovery_entity_ambiguity_candidates
|
followupContext?.previous_discovery_entity_ambiguity_candidates
|
||||||
);
|
);
|
||||||
const ambiguityBlocksImplicitGrounding =
|
const ambiguityBlocksImplicitGrounding =
|
||||||
pilotScope === "entity_resolution_search_v1" && entityResolutionStatus === "ambiguous";
|
effectivePilotScope === "entity_resolution_search_v1" && entityResolutionStatus === "ambiguous";
|
||||||
|
const metadataPilotCarriesScopeOnly =
|
||||||
|
effectivePilotScope === "metadata_inspection_v1" || loopSubjectResolutionOptional;
|
||||||
|
const metadataScopeHint =
|
||||||
|
loopMetadataScopeHint ??
|
||||||
|
(loopSubjectResolutionOptional ? discoveryEntities[0] ?? null : null);
|
||||||
const counterparty =
|
const counterparty =
|
||||||
toNonEmptyString(previousFilters?.counterparty) ??
|
toNonEmptyString(previousFilters?.counterparty) ??
|
||||||
toNonEmptyString(rootFilters?.counterparty) ??
|
toNonEmptyString(rootFilters?.counterparty) ??
|
||||||
(toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
|
(toNonEmptyString(followupContext?.previous_anchor_type) === "counterparty"
|
||||||
? toNonEmptyString(followupContext?.previous_anchor_value)
|
? toNonEmptyString(followupContext?.previous_anchor_value)
|
||||||
: null) ??
|
: null) ??
|
||||||
(ambiguityBlocksImplicitGrounding ? null : discoveryEntities[0] ?? null);
|
(ambiguityBlocksImplicitGrounding || metadataPilotCarriesScopeOnly ? null : discoveryEntities[0] ?? null);
|
||||||
const organization =
|
const organization =
|
||||||
toNonEmptyString(previousFilters?.organization) ??
|
toNonEmptyString(previousFilters?.organization) ??
|
||||||
toNonEmptyString(rootFilters?.organization) ??
|
toNonEmptyString(rootFilters?.organization) ??
|
||||||
|
|
@ -501,12 +511,15 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||||
loopPendingAxes,
|
loopPendingAxes,
|
||||||
loopProvidedAxes,
|
loopProvidedAxes,
|
||||||
counterparty,
|
counterparty,
|
||||||
discoveryEntity: ambiguityBlocksImplicitGrounding ? null : discoveryEntities[0] ?? null,
|
discoveryEntity:
|
||||||
|
ambiguityBlocksImplicitGrounding || loopSubjectResolutionOptional ? null : discoveryEntities[0] ?? null,
|
||||||
entityResolutionStatus,
|
entityResolutionStatus,
|
||||||
entityResolutionAmbiguityCandidates,
|
entityResolutionAmbiguityCandidates,
|
||||||
rankingNeed: toNonEmptyString(followupContext?.previous_discovery_ranking_need),
|
rankingNeed: toNonEmptyString(followupContext?.previous_discovery_ranking_need),
|
||||||
organization,
|
organization,
|
||||||
dateScope,
|
dateScope,
|
||||||
|
metadataScopeHint,
|
||||||
|
subjectResolutionOptional: loopSubjectResolutionOptional,
|
||||||
metadataRouteFamily: normalizeMetadataRouteFamily(followupContext?.previous_discovery_metadata_route_family),
|
metadataRouteFamily: normalizeMetadataRouteFamily(followupContext?.previous_discovery_metadata_route_family),
|
||||||
metadataRouteFamilySelectionBasis: normalizeMetadataRouteFamilySelectionBasis(
|
metadataRouteFamilySelectionBasis: normalizeMetadataRouteFamilySelectionBasis(
|
||||||
followupContext?.previous_discovery_metadata_route_family_selection_basis
|
followupContext?.previous_discovery_metadata_route_family_selection_basis
|
||||||
|
|
@ -1084,11 +1097,18 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
hasMetadataObjectHint(rawText)
|
hasMetadataObjectHint(rawText)
|
||||||
);
|
);
|
||||||
|
const metadataLaneCarryoverAvailable = Boolean(
|
||||||
|
followupSeed.counterparty ||
|
||||||
|
followupSeed.discoveryEntity ||
|
||||||
|
followupSeed.metadataScopeHint ||
|
||||||
|
followupSeed.metadataSelectedEntitySet ||
|
||||||
|
followupSeed.metadataSelectedSurfaceObjects.length > 0
|
||||||
|
);
|
||||||
const metadataGroundedDocumentFollowupApplicable = Boolean(
|
const metadataGroundedDocumentFollowupApplicable = Boolean(
|
||||||
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataRouteFamily === "document_evidence" &&
|
followupSeed.metadataRouteFamily === "document_evidence" &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
metadataDocumentHintSignal
|
metadataDocumentHintSignal
|
||||||
|
|
@ -1098,7 +1118,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
||||||
metadataEntitySetsSuggestDocumentLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
metadataEntitySetsSuggestDocumentLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
metadataDocumentHintSignal
|
metadataDocumentHintSignal
|
||||||
|
|
@ -1107,7 +1127,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataRouteFamily === "movement_evidence" &&
|
followupSeed.metadataRouteFamily === "movement_evidence" &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
metadataMovementHintSignal
|
metadataMovementHintSignal
|
||||||
);
|
);
|
||||||
|
|
@ -1116,7 +1136,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
(followupSeed.metadataAmbiguityEntitySets.length === 0 ||
|
||||||
metadataEntitySetsSuggestMovementLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
metadataEntitySetsSuggestMovementLane(followupSeed.metadataAmbiguityEntitySets)) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
metadataMovementHintSignal
|
metadataMovementHintSignal
|
||||||
);
|
);
|
||||||
|
|
@ -1206,7 +1226,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
(followupSeed.metadataRouteFamily === "document_evidence" ||
|
(followupSeed.metadataRouteFamily === "document_evidence" ||
|
||||||
followupSeed.metadataRouteFamily === "movement_evidence") &&
|
followupSeed.metadataRouteFamily === "movement_evidence") &&
|
||||||
!followupSeed.metadataAmbiguityDetected &&
|
!followupSeed.metadataAmbiguityDetected &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -1229,7 +1249,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -1241,7 +1261,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
followupSeed.pilotScope === "metadata_inspection_v1" &&
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -1254,7 +1274,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
followupSeed.metadataAmbiguityDetected &&
|
followupSeed.metadataAmbiguityDetected &&
|
||||||
!metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
!metadataAmbiguityCollapsesToDocumentLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
!metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
!metadataAmbiguityCollapsesToMovementLane(followupSeed.metadataAmbiguityEntitySets) &&
|
||||||
followupSeed.counterparty &&
|
metadataLaneCarryoverAvailable &&
|
||||||
!rawLifecycleSignal &&
|
!rawLifecycleSignal &&
|
||||||
!rawValueFlowSignal &&
|
!rawValueFlowSignal &&
|
||||||
!rawMetadataSignal &&
|
!rawMetadataSignal &&
|
||||||
|
|
@ -1265,6 +1285,14 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
const metadataGroundedDocumentLaneApplicable =
|
const metadataGroundedDocumentLaneApplicable =
|
||||||
metadataGroundedDocumentFollowupApplicable ||
|
metadataGroundedDocumentFollowupApplicable ||
|
||||||
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
metadataAmbiguityResolvedDocumentFollowupApplicable ||
|
||||||
|
(followupSeed.subjectResolutionOptional &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
!rawMetadataSignal &&
|
||||||
|
followupSeed.domain === "documents" &&
|
||||||
|
followupSeed.action === "list_documents") ||
|
||||||
entityResolutionGroundedDocumentFollowupApplicable ||
|
entityResolutionGroundedDocumentFollowupApplicable ||
|
||||||
entityResolutionClarifiedDocumentFollowupApplicable ||
|
entityResolutionClarifiedDocumentFollowupApplicable ||
|
||||||
valueFlowGroundedDocumentFollowupApplicable ||
|
valueFlowGroundedDocumentFollowupApplicable ||
|
||||||
|
|
@ -1274,6 +1302,14 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
const metadataGroundedMovementLaneApplicable =
|
const metadataGroundedMovementLaneApplicable =
|
||||||
metadataGroundedMovementFollowupApplicable ||
|
metadataGroundedMovementFollowupApplicable ||
|
||||||
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
metadataAmbiguityResolvedMovementFollowupApplicable ||
|
||||||
|
(followupSeed.subjectResolutionOptional &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable &&
|
||||||
|
!rawLifecycleSignal &&
|
||||||
|
!rawValueFlowSignal &&
|
||||||
|
!rawMetadataSignal &&
|
||||||
|
followupSeed.domain === "movements" &&
|
||||||
|
followupSeed.action === "list_movements") ||
|
||||||
entityResolutionGroundedMovementFollowupApplicable ||
|
entityResolutionGroundedMovementFollowupApplicable ||
|
||||||
entityResolutionClarifiedMovementFollowupApplicable ||
|
entityResolutionClarifiedMovementFollowupApplicable ||
|
||||||
valueFlowGroundedMovementFollowupApplicable ||
|
valueFlowGroundedMovementFollowupApplicable ||
|
||||||
|
|
@ -1346,7 +1382,20 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
!metadataGroundedDocumentLaneApplicable &&
|
!metadataGroundedDocumentLaneApplicable &&
|
||||||
!metadataGroundedMovementLaneApplicable
|
!metadataGroundedMovementLaneApplicable
|
||||||
});
|
});
|
||||||
const groundedFollowupEntity = followupSeed.counterparty ?? followupSeed.discoveryEntity;
|
const metadataLaneScopeHint =
|
||||||
|
rawMetadataScopeHint ??
|
||||||
|
followupSeed.metadataScopeHint ??
|
||||||
|
followupSeed.discoveryEntity ??
|
||||||
|
followupSeed.metadataSelectedEntitySet ??
|
||||||
|
null;
|
||||||
|
const metadataScopedLaneWithoutSubject = Boolean(
|
||||||
|
(metadataGroundedMovementLaneApplicable || metadataGroundedDocumentLaneApplicable) &&
|
||||||
|
!followupSeed.counterparty &&
|
||||||
|
metadataLaneCarryoverAvailable
|
||||||
|
);
|
||||||
|
const groundedFollowupEntity = metadataScopedLaneWithoutSubject
|
||||||
|
? null
|
||||||
|
: followupSeed.counterparty ?? followupSeed.discoveryEntity;
|
||||||
const entityCandidates = entityResolutionSignal ? [] : [];
|
const entityCandidates = entityResolutionSignal ? [] : [];
|
||||||
if (entityResolutionSignal) {
|
if (entityResolutionSignal) {
|
||||||
pushNormalizedEntityResolutionCandidate(entityCandidates, entityResolutionClarificationCandidate);
|
pushNormalizedEntityResolutionCandidate(entityCandidates, entityResolutionClarificationCandidate);
|
||||||
|
|
@ -1366,11 +1415,17 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
pushScopedEntityCandidate(entityCandidates, normalizedPredecomposeCounterparty, groundedFollowupEntity);
|
pushScopedEntityCandidate(entityCandidates, normalizedPredecomposeCounterparty, groundedFollowupEntity);
|
||||||
if (!groundedFollowupEntity) {
|
if (!groundedFollowupEntity) {
|
||||||
pushScopedEntityCandidate(entityCandidates, followupSeed.counterparty, null);
|
pushScopedEntityCandidate(entityCandidates, followupSeed.counterparty, null);
|
||||||
pushScopedEntityCandidate(entityCandidates, followupSeed.discoveryEntity, null);
|
if (!metadataScopedLaneWithoutSubject) {
|
||||||
|
pushScopedEntityCandidate(entityCandidates, followupSeed.discoveryEntity, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity);
|
pushScopedEntityCandidate(entityCandidates, rawEntityCandidate, groundedFollowupEntity);
|
||||||
}
|
}
|
||||||
if ((rawMetadataSignal || metadataFollowupSeedApplicable) && !groundedFollowupEntity) {
|
if (
|
||||||
|
(rawMetadataSignal || metadataFollowupSeedApplicable) &&
|
||||||
|
!groundedFollowupEntity &&
|
||||||
|
!metadataScopedLaneWithoutSubject
|
||||||
|
) {
|
||||||
pushUnique(entityCandidates, followupSeed.discoveryEntity);
|
pushUnique(entityCandidates, followupSeed.discoveryEntity);
|
||||||
pushUnique(entityCandidates, rawMetadataScopeHint);
|
pushUnique(entityCandidates, rawMetadataScopeHint);
|
||||||
}
|
}
|
||||||
|
|
@ -1487,8 +1542,10 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0
|
metadataAmbiguityLaneClarificationApplicable && followupSeed.metadataAmbiguityEntitySets.length > 0
|
||||||
? followupSeed.metadataAmbiguityEntitySets
|
? followupSeed.metadataAmbiguityEntitySets
|
||||||
: undefined,
|
: undefined,
|
||||||
|
metadata_scope_hint: metadataLaneScopeHint,
|
||||||
explicit_organization_scope: explicitOrganizationScope,
|
explicit_organization_scope: explicitOrganizationScope,
|
||||||
explicit_date_scope: explicitDateScope,
|
explicit_date_scope: explicitDateScope,
|
||||||
|
subject_resolution_optional: metadataScopedLaneWithoutSubject || undefined,
|
||||||
unsupported_but_understood_family:
|
unsupported_but_understood_family:
|
||||||
unsupported ??
|
unsupported ??
|
||||||
(lifecycleSignal
|
(lifecycleSignal
|
||||||
|
|
@ -1546,12 +1603,18 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
if ((turnMeaning.metadata_ambiguity_entity_sets?.length ?? 0) > 0) {
|
if ((turnMeaning.metadata_ambiguity_entity_sets?.length ?? 0) > 0) {
|
||||||
cleanTurnMeaning.metadata_ambiguity_entity_sets = turnMeaning.metadata_ambiguity_entity_sets;
|
cleanTurnMeaning.metadata_ambiguity_entity_sets = turnMeaning.metadata_ambiguity_entity_sets;
|
||||||
}
|
}
|
||||||
|
if (toNonEmptyString(turnMeaning.metadata_scope_hint)) {
|
||||||
|
cleanTurnMeaning.metadata_scope_hint = turnMeaning.metadata_scope_hint;
|
||||||
|
}
|
||||||
if (toNonEmptyString(turnMeaning.explicit_organization_scope)) {
|
if (toNonEmptyString(turnMeaning.explicit_organization_scope)) {
|
||||||
cleanTurnMeaning.explicit_organization_scope = turnMeaning.explicit_organization_scope;
|
cleanTurnMeaning.explicit_organization_scope = turnMeaning.explicit_organization_scope;
|
||||||
}
|
}
|
||||||
if (toNonEmptyString(turnMeaning.explicit_date_scope)) {
|
if (toNonEmptyString(turnMeaning.explicit_date_scope)) {
|
||||||
cleanTurnMeaning.explicit_date_scope = turnMeaning.explicit_date_scope;
|
cleanTurnMeaning.explicit_date_scope = turnMeaning.explicit_date_scope;
|
||||||
}
|
}
|
||||||
|
if (turnMeaning.subject_resolution_optional) {
|
||||||
|
cleanTurnMeaning.subject_resolution_optional = true;
|
||||||
|
}
|
||||||
if (toNonEmptyString(turnMeaning.unsupported_but_understood_family)) {
|
if (toNonEmptyString(turnMeaning.unsupported_but_understood_family)) {
|
||||||
cleanTurnMeaning.unsupported_but_understood_family = turnMeaning.unsupported_but_understood_family;
|
cleanTurnMeaning.unsupported_but_understood_family = turnMeaning.unsupported_but_understood_family;
|
||||||
}
|
}
|
||||||
|
|
@ -1668,6 +1731,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||||
if (metadataAmbiguityResolvedMovementFollowupApplicable) {
|
if (metadataAmbiguityResolvedMovementFollowupApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
pushReason(reasonCodes, "mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
||||||
}
|
}
|
||||||
|
if (metadataScopedLaneWithoutSubject) {
|
||||||
|
pushReason(reasonCodes, "mcp_discovery_metadata_scoped_lane_without_subject");
|
||||||
|
}
|
||||||
if (entityResolutionGroundedDocumentFollowupApplicable) {
|
if (entityResolutionGroundedDocumentFollowupApplicable) {
|
||||||
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_document_followup");
|
pushReason(reasonCodes, "mcp_discovery_entity_resolution_grounded_document_followup");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ import {
|
||||||
readAssistantMcpDiscoveryLoopAskedDomainFamily,
|
readAssistantMcpDiscoveryLoopAskedDomainFamily,
|
||||||
readAssistantMcpDiscoveryLoopAskedActionFamily,
|
readAssistantMcpDiscoveryLoopAskedActionFamily,
|
||||||
readAssistantMcpDiscoveryLoopUnsupportedFamily,
|
readAssistantMcpDiscoveryLoopUnsupportedFamily,
|
||||||
|
readAssistantMcpDiscoveryLoopMetadataScopeHint,
|
||||||
|
readAssistantMcpDiscoveryLoopSubjectResolutionOptional,
|
||||||
readAddressDebugTemporalScope,
|
readAddressDebugTemporalScope,
|
||||||
readAssistantMcpDiscoveryPilotScope,
|
readAssistantMcpDiscoveryPilotScope,
|
||||||
resolveOrganizationClarificationContinuation,
|
resolveOrganizationClarificationContinuation,
|
||||||
|
|
@ -727,6 +729,12 @@ export function createAssistantTransitionPolicy(deps) {
|
||||||
carryoverSourceDebug,
|
carryoverSourceDebug,
|
||||||
deps.toNonEmptyString
|
deps.toNonEmptyString
|
||||||
);
|
);
|
||||||
|
const sourceDiscoveryLoopMetadataScopeHint = readAssistantMcpDiscoveryLoopMetadataScopeHint(
|
||||||
|
carryoverSourceDebug,
|
||||||
|
deps.toNonEmptyString
|
||||||
|
);
|
||||||
|
const sourceDiscoveryLoopSubjectResolutionOptional =
|
||||||
|
readAssistantMcpDiscoveryLoopSubjectResolutionOptional(carryoverSourceDebug);
|
||||||
const sourceDiscoveryRankingNeed = readAssistantMcpDiscoveryRankingNeed(
|
const sourceDiscoveryRankingNeed = readAssistantMcpDiscoveryRankingNeed(
|
||||||
carryoverSourceDebug,
|
carryoverSourceDebug,
|
||||||
deps.toNonEmptyString
|
deps.toNonEmptyString
|
||||||
|
|
@ -1083,6 +1091,9 @@ export function createAssistantTransitionPolicy(deps) {
|
||||||
previous_discovery_loop_asked_domain_family: sourceDiscoveryLoopAskedDomainFamily ?? undefined,
|
previous_discovery_loop_asked_domain_family: sourceDiscoveryLoopAskedDomainFamily ?? undefined,
|
||||||
previous_discovery_loop_asked_action_family: sourceDiscoveryLoopAskedActionFamily ?? undefined,
|
previous_discovery_loop_asked_action_family: sourceDiscoveryLoopAskedActionFamily ?? undefined,
|
||||||
previous_discovery_loop_unsupported_family: sourceDiscoveryLoopUnsupportedFamily ?? undefined,
|
previous_discovery_loop_unsupported_family: sourceDiscoveryLoopUnsupportedFamily ?? undefined,
|
||||||
|
previous_discovery_loop_metadata_scope_hint: sourceDiscoveryLoopMetadataScopeHint ?? undefined,
|
||||||
|
previous_discovery_loop_subject_resolution_optional:
|
||||||
|
sourceDiscoveryLoopSubjectResolutionOptional || undefined,
|
||||||
previous_discovery_ranking_need: sourceDiscoveryRankingNeed ?? undefined,
|
previous_discovery_ranking_need: sourceDiscoveryRankingNeed ?? undefined,
|
||||||
previous_discovery_entity_ambiguity_candidates:
|
previous_discovery_entity_ambiguity_candidates:
|
||||||
sourceDiscoveryEntityAmbiguityCandidates.length > 0
|
sourceDiscoveryEntityAmbiguityCandidates.length > 0
|
||||||
|
|
|
||||||
|
|
@ -229,4 +229,26 @@ describe("assistant MCP discovery data need graph", () => {
|
||||||
expect(result.reason_codes).toContain("data_need_graph_open_scope_total_without_subject");
|
expect(result.reason_codes).toContain("data_need_graph_open_scope_total_without_subject");
|
||||||
expect(result.reason_codes).toContain("data_need_graph_all_time_scope_hint");
|
expect(result.reason_codes).toContain("data_need_graph_all_time_scope_hint");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("treats metadata-scoped movement evidence as subjectless and asks only for organization plus period", () => {
|
||||||
|
const result = buildAssistantMcpDiscoveryDataNeedGraph({
|
||||||
|
semanticDataNeed: "movement evidence",
|
||||||
|
rawUtterance: "по движениям",
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.business_fact_family).toBe("movement_evidence");
|
||||||
|
expect(result.subject_candidates).toEqual([]);
|
||||||
|
expect(result.metadata_scope_hint).toBe("НДС");
|
||||||
|
expect(result.subject_resolution_optional).toBe(true);
|
||||||
|
expect(result.clarification_gaps).toEqual(["organization", "period"]);
|
||||||
|
expect(result.decomposition_candidates).toEqual(["fetch_scoped_movements", "probe_coverage"]);
|
||||||
|
expect(result.reason_codes).toContain("data_need_graph_metadata_scoped_open_lane_without_subject");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -823,4 +823,86 @@ describe("assistant MCP discovery planner", () => {
|
||||||
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||||
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
expect(result.reason_codes).toContain("planner_selected_open_scope_value_flow_total_from_data_need_graph");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps metadata-scoped movement evidence in clarification instead of forcing entity resolution", () => {
|
||||||
|
const result = planAssistantMcpDiscovery({
|
||||||
|
dataNeedGraph: {
|
||||||
|
schema_version: "assistant_data_need_graph_v1",
|
||||||
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||||
|
subject_candidates: [],
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
business_fact_family: "movement_evidence",
|
||||||
|
action_family: "list_movements",
|
||||||
|
aggregation_need: null,
|
||||||
|
time_scope_need: "period_required",
|
||||||
|
comparison_need: null,
|
||||||
|
ranking_need: null,
|
||||||
|
proof_expectation: "clarification_required",
|
||||||
|
clarification_gaps: ["organization", "period"],
|
||||||
|
decomposition_candidates: ["fetch_scoped_movements", "probe_coverage"],
|
||||||
|
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||||
|
reason_codes: [
|
||||||
|
"data_need_graph_built",
|
||||||
|
"data_need_graph_metadata_scoped_open_lane_without_subject"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.planner_status).toBe("needs_clarification");
|
||||||
|
expect(result.selected_chain_id).toBe("movement_evidence");
|
||||||
|
expect(result.proposed_primitives).toEqual(["query_movements", "probe_coverage"]);
|
||||||
|
expect(result.required_axes).toEqual(["metadata_scope", "organization", "coverage_target"]);
|
||||||
|
expect(result.reason_codes).toContain("planner_selected_metadata_scoped_movement_from_data_need_graph");
|
||||||
|
expect(result.selected_chain_id).not.toBe("entity_resolution");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps metadata-scoped movement evidence execution-ready once organization and period are known", () => {
|
||||||
|
const result = planAssistantMcpDiscovery({
|
||||||
|
dataNeedGraph: {
|
||||||
|
schema_version: "assistant_data_need_graph_v1",
|
||||||
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||||
|
subject_candidates: [],
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
business_fact_family: "movement_evidence",
|
||||||
|
action_family: "list_movements",
|
||||||
|
aggregation_need: null,
|
||||||
|
time_scope_need: "explicit_period",
|
||||||
|
comparison_need: null,
|
||||||
|
ranking_need: null,
|
||||||
|
proof_expectation: "coverage_checked_fact",
|
||||||
|
clarification_gaps: [],
|
||||||
|
decomposition_candidates: ["fetch_scoped_movements", "probe_coverage"],
|
||||||
|
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||||
|
reason_codes: [
|
||||||
|
"data_need_graph_built",
|
||||||
|
"data_need_graph_metadata_scoped_open_lane_without_subject"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
explicit_organization_scope: "ООО Альтернатива Плюс",
|
||||||
|
explicit_date_scope: "2020",
|
||||||
|
unsupported_but_understood_family: "movement_evidence"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.planner_status).toBe("ready_for_execution");
|
||||||
|
expect(result.selected_chain_id).toBe("movement_evidence");
|
||||||
|
expect(result.proposed_primitives).toEqual(["query_movements", "probe_coverage"]);
|
||||||
|
expect(result.required_axes).toEqual(["organization", "period", "metadata_scope", "coverage_target"]);
|
||||||
|
expect(result.catalog_review.review_status).toBe("catalog_compatible");
|
||||||
|
expect(result.reason_codes).toContain("planner_selected_metadata_scoped_movement_from_data_need_graph");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -429,4 +429,44 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||||
"\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430"
|
"\u043a\u043e\u043d\u0442\u0440\u0430\u0433\u0435\u043d\u0442\u0430"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it("persists metadata scope and subject-optional flags in the resumable loop state", async () => {
|
||||||
|
const result = await runAssistantMcpDiscoveryRuntimeBridge({
|
||||||
|
dataNeedGraph: {
|
||||||
|
schema_version: "assistant_data_need_graph_v1",
|
||||||
|
policy_owner: "assistantMcpDiscoveryDataNeedGraph",
|
||||||
|
subject_candidates: [],
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
business_fact_family: "movement_evidence",
|
||||||
|
action_family: "list_movements",
|
||||||
|
aggregation_need: null,
|
||||||
|
time_scope_need: "period_required",
|
||||||
|
comparison_need: null,
|
||||||
|
ranking_need: null,
|
||||||
|
proof_expectation: "clarification_required",
|
||||||
|
clarification_gaps: ["organization", "period"],
|
||||||
|
decomposition_candidates: ["fetch_scoped_movements", "probe_coverage"],
|
||||||
|
forbidden_overclaim_flags: ["no_raw_model_claims", "no_unchecked_fact_totals"],
|
||||||
|
reason_codes: ["data_need_graph_built", "data_need_graph_metadata_scoped_open_lane_without_subject"]
|
||||||
|
},
|
||||||
|
turnMeaning: {
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence"
|
||||||
|
},
|
||||||
|
deps: buildDeps([])
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.bridge_status).toBe("needs_clarification");
|
||||||
|
expect(result.loop_state).toMatchObject({
|
||||||
|
loop_status: "awaiting_clarification",
|
||||||
|
selected_chain_id: "movement_evidence",
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true
|
||||||
|
});
|
||||||
|
expect(result.loop_state.pending_axes).toEqual(["organization", "period"]);
|
||||||
|
expect(result.loop_state.explicit_entity_candidates).toEqual([]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1877,4 +1877,144 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||||
);
|
);
|
||||||
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
expect(result.reason_codes).not.toContain("mcp_discovery_not_applicable_for_supported_exact_turn");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.skip("keeps metadata-born movement lane subjectless and asks for organization plus period", () => {
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage: "по движениям",
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_loop_status: "awaiting_clarification",
|
||||||
|
previous_discovery_loop_selected_chain_id: "metadata_lane_clarification",
|
||||||
|
previous_discovery_loop_pending_axes: ["lane_family_choice"],
|
||||||
|
previous_discovery_loop_asked_domain_family: "metadata",
|
||||||
|
previous_discovery_loop_asked_action_family: "resolve_next_lane",
|
||||||
|
previous_discovery_loop_unsupported_family: "metadata_lane_choice_clarification",
|
||||||
|
previous_discovery_entity_candidates: ["НДС"],
|
||||||
|
previous_discovery_metadata_ambiguity_detected: true,
|
||||||
|
previous_discovery_metadata_ambiguity_entity_sets: ["Документ", "РегистрНакопления"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.semantic_data_need).toBe("movement evidence");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||||
|
expect(result.data_need_graph?.clarification_gaps).toEqual(["organization", "period"]);
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_scoped_lane_without_subject");
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip("keeps metadata scope through organization-only clarification and leaves only period pending", () => {
|
||||||
|
const orgName = "ООО Альтернатива Плюс";
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage: "по ООО Альтернатива Плюс",
|
||||||
|
predecomposeContract: {
|
||||||
|
entities: { organization: orgName }
|
||||||
|
},
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_loop_status: "awaiting_clarification",
|
||||||
|
previous_discovery_loop_selected_chain_id: "movement_evidence",
|
||||||
|
previous_discovery_loop_pending_axes: ["organization", "period"],
|
||||||
|
previous_discovery_loop_asked_domain_family: "movements",
|
||||||
|
previous_discovery_loop_asked_action_family: "list_movements",
|
||||||
|
previous_discovery_loop_unsupported_family: "movement_evidence",
|
||||||
|
previous_discovery_entity_candidates: ["НДС"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.semantic_data_need).toBe("movement evidence");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "НДС",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
explicit_organization_scope: orgName,
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||||
|
expect(result.data_need_graph?.clarification_gaps).toEqual(["period"]);
|
||||||
|
});
|
||||||
|
it("keeps metadata-born movement lane subjectless and asks for organization plus period (utf8-safe)", () => {
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage: "\u043f\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f\u043c",
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_loop_status: "awaiting_clarification",
|
||||||
|
previous_discovery_loop_selected_chain_id: "metadata_lane_clarification",
|
||||||
|
previous_discovery_loop_pending_axes: ["lane_family_choice"],
|
||||||
|
previous_discovery_loop_asked_domain_family: "metadata",
|
||||||
|
previous_discovery_loop_asked_action_family: "resolve_next_lane",
|
||||||
|
previous_discovery_loop_unsupported_family: "metadata_lane_choice_clarification",
|
||||||
|
previous_discovery_entity_candidates: ["\u041d\u0414\u0421"],
|
||||||
|
previous_discovery_metadata_ambiguity_detected: true,
|
||||||
|
previous_discovery_metadata_ambiguity_entity_sets: [
|
||||||
|
"\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
|
||||||
|
"\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u041d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u0438\u044f"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.semantic_data_need).toBe("movement evidence");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||||
|
expect(result.data_need_graph?.clarification_gaps).toEqual(["organization", "period"]);
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_ambiguity_resolved_to_movement_lane");
|
||||||
|
expect(result.reason_codes).toContain("mcp_discovery_metadata_scoped_lane_without_subject");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps metadata scope through organization-only clarification and leaves only period pending (utf8-safe)", () => {
|
||||||
|
const orgName =
|
||||||
|
"\u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441";
|
||||||
|
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||||
|
userMessage:
|
||||||
|
"\u043f\u043e \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441",
|
||||||
|
predecomposeContract: {
|
||||||
|
entities: { organization: orgName }
|
||||||
|
},
|
||||||
|
followupContext: {
|
||||||
|
previous_discovery_loop_status: "awaiting_clarification",
|
||||||
|
previous_discovery_loop_selected_chain_id: "movement_evidence",
|
||||||
|
previous_discovery_loop_pending_axes: ["organization", "period"],
|
||||||
|
previous_discovery_loop_asked_domain_family: "movements",
|
||||||
|
previous_discovery_loop_asked_action_family: "list_movements",
|
||||||
|
previous_discovery_loop_unsupported_family: "movement_evidence",
|
||||||
|
previous_discovery_loop_metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
previous_discovery_loop_subject_resolution_optional: true,
|
||||||
|
previous_discovery_entity_candidates: ["\u041d\u0414\u0421"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.adapter_status).toBe("ready");
|
||||||
|
expect(result.should_run_discovery).toBe(true);
|
||||||
|
expect(result.semantic_data_need).toBe("movement evidence");
|
||||||
|
expect(result.turn_meaning_ref).toMatchObject({
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
explicit_organization_scope: orgName,
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
});
|
||||||
|
expect(result.turn_meaning_ref?.explicit_entity_candidates).toBeUndefined();
|
||||||
|
expect(result.data_need_graph?.clarification_gaps).toEqual(["period"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1647,4 +1647,156 @@ describe("assistantTransitionPolicy", () => {
|
||||||
period_to: "2017-05-31"
|
period_to: "2017-05-31"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("carries metadata-scoped subjectless loop state through follow-up context", () => {
|
||||||
|
const policy = buildPolicy({
|
||||||
|
findLastAddressAssistantItem: () => ({
|
||||||
|
text: "\u043d\u0443\u0436\u043d\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043f\u0435\u0440\u0438\u043e\u0434",
|
||||||
|
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: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bridge: {
|
||||||
|
bridge_status: "needs_clarification",
|
||||||
|
business_fact_answer_allowed: false,
|
||||||
|
pilot: {
|
||||||
|
pilot_scope: "counterparty_movement_evidence_query_movements_v1"
|
||||||
|
},
|
||||||
|
loop_state: {
|
||||||
|
schema_version: "assistant_mcp_discovery_loop_state_v1",
|
||||||
|
policy_owner: "assistantMcpDiscoveryRuntimeBridge",
|
||||||
|
loop_status: "awaiting_clarification",
|
||||||
|
selected_chain_id: "movement_evidence",
|
||||||
|
pilot_scope: "counterparty_movement_evidence_query_movements_v1",
|
||||||
|
asked_domain_family: "movements",
|
||||||
|
asked_action_family: "list_movements",
|
||||||
|
unsupported_but_understood_family: "movement_evidence",
|
||||||
|
ranking_need: null,
|
||||||
|
pending_axes: ["organization", "period"],
|
||||||
|
provided_axes: [],
|
||||||
|
explicit_entity_candidates: [],
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: true,
|
||||||
|
explicit_organization_scope: null,
|
||||||
|
explicit_date_scope: null
|
||||||
|
},
|
||||||
|
answer_draft: {
|
||||||
|
answer_mode: "needs_clarification"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
hasAddressFollowupContextSignal: () => true,
|
||||||
|
hasReferentialPointer: () => false,
|
||||||
|
resolveAddressIntent: () => ({ intent: "unknown" }),
|
||||||
|
resolveAddressIntentFamily: () => null,
|
||||||
|
resolveAssistantTurnMeaning: () => null
|
||||||
|
});
|
||||||
|
|
||||||
|
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||||
|
"\u043f\u043e \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441",
|
||||||
|
[{ kind: "assistant", text: "\u043d\u0443\u0436\u043d\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u043f\u0435\u0440\u0438\u043e\u0434" }],
|
||||||
|
"\u043f\u043e \u041e\u041e\u041e \u0410\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u0430 \u041f\u043b\u044e\u0441",
|
||||||
|
{ predecomposeContract: { intent: "unknown" } },
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_loop_selected_chain_id).toBe("movement_evidence");
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_loop_pending_axes).toEqual([
|
||||||
|
"organization",
|
||||||
|
"period"
|
||||||
|
]);
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_loop_metadata_scope_hint).toBe(
|
||||||
|
"\u041d\u0414\u0421"
|
||||||
|
);
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_loop_subject_resolution_optional).toBe(true);
|
||||||
|
});
|
||||||
|
it("does not backfill metadata scope into counterparty carryover during lane choice follow-up", () => {
|
||||||
|
const policy = buildPolicy({
|
||||||
|
findLastAddressAssistantItem: () => ({
|
||||||
|
text: "\u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435: \u043f\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0438\u043b\u0438 \u043f\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f\u043c?",
|
||||||
|
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: "resolve_next_lane",
|
||||||
|
explicit_entity_candidates: ["\u041d\u0414\u0421"],
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
metadata_ambiguity_entity_sets: [
|
||||||
|
"\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442",
|
||||||
|
"\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u041d\u0430\u043a\u043e\u043f\u043b\u0435\u043d\u0438\u044f"
|
||||||
|
],
|
||||||
|
unsupported_but_understood_family: "metadata_lane_choice_clarification",
|
||||||
|
stale_replay_forbidden: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bridge: {
|
||||||
|
bridge_status: "needs_clarification",
|
||||||
|
business_fact_answer_allowed: false,
|
||||||
|
pilot: {
|
||||||
|
pilot_scope: "metadata_inspection_v1"
|
||||||
|
},
|
||||||
|
loop_state: {
|
||||||
|
schema_version: "assistant_mcp_discovery_loop_state_v1",
|
||||||
|
policy_owner: "assistantMcpDiscoveryRuntimeBridge",
|
||||||
|
loop_status: "awaiting_clarification",
|
||||||
|
selected_chain_id: "metadata_lane_clarification",
|
||||||
|
pilot_scope: "metadata_inspection_v1",
|
||||||
|
asked_domain_family: "metadata",
|
||||||
|
asked_action_family: "resolve_next_lane",
|
||||||
|
unsupported_but_understood_family: "metadata_lane_choice_clarification",
|
||||||
|
ranking_need: null,
|
||||||
|
pending_axes: ["lane_family_choice"],
|
||||||
|
provided_axes: [],
|
||||||
|
explicit_entity_candidates: ["\u041d\u0414\u0421"],
|
||||||
|
metadata_scope_hint: "\u041d\u0414\u0421",
|
||||||
|
subject_resolution_optional: false,
|
||||||
|
explicit_organization_scope: null,
|
||||||
|
explicit_date_scope: null
|
||||||
|
},
|
||||||
|
answer_draft: {
|
||||||
|
answer_mode: "needs_clarification"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
hasAddressFollowupContextSignal: () => true,
|
||||||
|
hasReferentialPointer: () => false,
|
||||||
|
resolveAddressIntent: () => ({ intent: "unknown" }),
|
||||||
|
resolveAddressIntentFamily: () => null,
|
||||||
|
resolveAssistantTurnMeaning: () => null
|
||||||
|
});
|
||||||
|
|
||||||
|
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||||
|
"\u043f\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f\u043c",
|
||||||
|
[{ kind: "assistant", text: "\u0443\u0442\u043e\u0447\u043d\u0438\u0442\u0435: \u043f\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u0438\u043b\u0438 \u043f\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f\u043c?" }],
|
||||||
|
"\u043f\u043e \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044f\u043c",
|
||||||
|
{ predecomposeContract: { intent: "unknown" } },
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(carryover?.followupContext?.previous_filters?.counterparty).toBeUndefined();
|
||||||
|
expect(carryover?.followupContext?.previous_anchor_type).toBeUndefined();
|
||||||
|
expect(carryover?.followupContext?.previous_anchor_value).toBeNull();
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_entity_candidates).toEqual(["\u041d\u0414\u0421"]);
|
||||||
|
expect(carryover?.followupContext?.previous_discovery_pilot_scope).toBe("metadata_inspection_v1");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue