ARCH: закрепить open-scope continuity для org clarification
This commit is contained in:
@@ -174,6 +174,15 @@ function explicitDateScope(pilot: AssistantMcpDiscoveryPilotExecutionContract):
|
||||
return normalized.length > 0 ? normalized : null;
|
||||
}
|
||||
|
||||
function explicitOrganizationScope(pilot: AssistantMcpDiscoveryPilotExecutionContract): string | null {
|
||||
const value = pilot.evidence.query_plan.turn_meaning_ref?.explicit_organization_scope;
|
||||
if (typeof value !== "string") {
|
||||
return null;
|
||||
}
|
||||
const normalized = value.trim();
|
||||
return normalized.length > 0 ? normalized : null;
|
||||
}
|
||||
|
||||
function documentOrMovementScopeRu(pilot: AssistantMcpDiscoveryPilotExecutionContract): string {
|
||||
const entity = firstEntityCandidate(pilot);
|
||||
const period = explicitDateScope(pilot);
|
||||
@@ -210,6 +219,15 @@ function isBidirectionalValueFlowComparisonClarification(
|
||||
);
|
||||
}
|
||||
|
||||
function isOpenScopeValueFlowClarification(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
||||
return (
|
||||
pilot.reason_codes.includes("planner_selected_open_scope_value_flow_total_from_data_need_graph") ||
|
||||
pilot.reason_codes.includes("planner_selected_monthly_open_scope_value_flow_total_from_data_need_graph") ||
|
||||
pilot.dry_run.reason_codes.includes("planner_selected_open_scope_value_flow_total_from_data_need_graph") ||
|
||||
pilot.dry_run.reason_codes.includes("planner_selected_monthly_open_scope_value_flow_total_from_data_need_graph")
|
||||
);
|
||||
}
|
||||
|
||||
function isDocumentLaneClarification(pilot: AssistantMcpDiscoveryPilotExecutionContract): boolean {
|
||||
return (
|
||||
isDocumentPilot(pilot) ||
|
||||
@@ -241,6 +259,17 @@ function dryRunMissingAxis(pilot: AssistantMcpDiscoveryPilotExecutionContract, a
|
||||
function clarificationNeedRu(
|
||||
pilot: AssistantMcpDiscoveryPilotExecutionContract
|
||||
): { subject: string; verb: string } {
|
||||
const organizationScopedOpenTotal =
|
||||
pilot.reason_codes.includes("data_need_graph_open_scope_total_needs_organization") ||
|
||||
pilot.dry_run.reason_codes.includes("data_need_graph_open_scope_total_needs_organization") ||
|
||||
pilot.reason_codes.includes("planner_requires_organization_scope_from_data_need_graph") ||
|
||||
pilot.dry_run.reason_codes.includes("planner_requires_organization_scope_from_data_need_graph");
|
||||
if (organizationScopedOpenTotal) {
|
||||
return {
|
||||
subject: "\u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044e",
|
||||
verb: "\u043d\u0443\u0436\u043d\u043e"
|
||||
};
|
||||
}
|
||||
const hasCounterparty = dryRunHasAxis(pilot, "counterparty");
|
||||
const hasAccount = dryRunHasAxis(pilot, "account");
|
||||
const needsPeriod = dryRunMissingAxis(pilot, "period");
|
||||
@@ -261,9 +290,17 @@ function clarificationNextStepLine(
|
||||
pilot: AssistantMcpDiscoveryPilotExecutionContract,
|
||||
laneLabel: string
|
||||
): string {
|
||||
const organizationScopedOpenTotal =
|
||||
pilot.reason_codes.includes("data_need_graph_open_scope_total_needs_organization") ||
|
||||
pilot.dry_run.reason_codes.includes("data_need_graph_open_scope_total_needs_organization") ||
|
||||
pilot.reason_codes.includes("planner_requires_organization_scope_from_data_need_graph") ||
|
||||
pilot.dry_run.reason_codes.includes("planner_requires_organization_scope_from_data_need_graph");
|
||||
const needsPeriod = dryRunMissingAxis(pilot, "period");
|
||||
const needsOrganization = dryRunMissingAxis(pilot, "organization");
|
||||
const scopeSuffix = laneScopeSuffix(pilot);
|
||||
if (organizationScopedOpenTotal && !needsPeriod) {
|
||||
return `Уточните организацию, и я продолжу поиск по ${laneLabel}${scopeSuffix} в 1С.`;
|
||||
}
|
||||
if (needsPeriod && needsOrganization) {
|
||||
return `Уточните период и организацию, и я продолжу поиск по ${laneLabel}${scopeSuffix} в 1С.`;
|
||||
}
|
||||
@@ -378,6 +415,10 @@ function headlineFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
|
||||
const need = clarificationNeedRu(pilot);
|
||||
return `Могу посчитать ranking по денежному потоку между контрагентами, но для bounded поиска в 1С ${need.verb} ${need.subject}.`;
|
||||
}
|
||||
if (mode === "needs_clarification" && isOpenScopeValueFlowClarification(pilot)) {
|
||||
const need = clarificationNeedRu(pilot);
|
||||
return `Могу посчитать общий денежный поток в проверяемом окне, но для bounded поиска в 1С ${need.verb} ${need.subject}.`;
|
||||
}
|
||||
if (mode === "needs_clarification") {
|
||||
return "Нужно уточнить контекст перед поиском в 1С.";
|
||||
}
|
||||
@@ -422,6 +463,9 @@ function nextStepFor(mode: AssistantMcpDiscoveryAnswerMode, pilot: AssistantMcpD
|
||||
if (mode === "needs_clarification" && isRankedValueFlowClarification(pilot)) {
|
||||
return clarificationNextStepLine(pilot, "ranking-поиску между контрагентами");
|
||||
}
|
||||
if (mode === "needs_clarification" && isOpenScopeValueFlowClarification(pilot)) {
|
||||
return clarificationNextStepLine(pilot, "денежному потоку");
|
||||
}
|
||||
if (mode === "needs_clarification") {
|
||||
return "Уточните контрагента, период или организацию, и я смогу выполнить проверку по 1С.";
|
||||
}
|
||||
@@ -646,6 +690,8 @@ function derivedValueFlowConfirmedLine(pilot: AssistantMcpDiscoveryPilotExecutio
|
||||
if (!flow) {
|
||||
return null;
|
||||
}
|
||||
const organizationScope = explicitOrganizationScope(pilot);
|
||||
const organization = organizationScope ? ` по организации ${organizationScope}` : "";
|
||||
const counterparty = flow.counterparty ? ` по контрагенту ${flow.counterparty}` : "";
|
||||
const period = flow.period_scope ? ` за период ${flow.period_scope}` : " в проверенном окне";
|
||||
const movementLabel =
|
||||
|
||||
@@ -132,6 +132,40 @@ function comparisonNeedFor(action: string): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function hasOpenScopeOneSidedValueTotalHint(rawUtterance: string, action: string): boolean {
|
||||
if (!rawUtterance) {
|
||||
return false;
|
||||
}
|
||||
if (action === "turnover") {
|
||||
return /(?:\bсколько\s+(?:мы\s+)?(?:получили|получено|входящих(?:\s+денег)?|поступлений|денег\s+пришло)\b|(?:сумма|объем)\s+(?:входящих|поступлений)|поступлений\s+за\b)/iu.test(
|
||||
rawUtterance
|
||||
);
|
||||
}
|
||||
if (action === "payout") {
|
||||
return /(?:\bсколько\s+(?:мы\s+)?(?:заплатили|выплатили|потратили|исходящих(?:\s+денег)?|платежей|списаний)\b|(?:сумма|объем)\s+(?:исходящих|платежей|списаний)|(?:платежей|списаний)\s+за\b)/iu.test(
|
||||
rawUtterance
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance: string, action: string): boolean {
|
||||
if (!rawUtterance) {
|
||||
return false;
|
||||
}
|
||||
if (action === "turnover") {
|
||||
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:\u043c\u044b\s+)?(?:\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438|\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043e|\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439|\u0434\u0435\u043d\u0435\u0433\s+\u043f\u0440\u0438\u0448\u043b\u043e)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439)|\u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0439\s+\u0437\u0430)/u.test(
|
||||
rawUtterance
|
||||
);
|
||||
}
|
||||
if (action === "payout") {
|
||||
return /(?:\u0441\u043a\u043e\u043b\u044c\u043a\u043e\s+(?:\u043c\u044b\s+)?(?:\u0437\u0430\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u0432\u044b\u043f\u043b\u0430\u0442\u0438\u043b\u0438|\u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438|\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445(?:\s+\u0434\u0435\u043d\u0435\u0433)?|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)|(?:\u0441\u0443\u043c\u043c\u0430|\u043e\u0431\u044a\u0435\u043c)\s+(?:\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0445|\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)|(?:\u043f\u043b\u0430\u0442\u0435\u0436\u0435\u0439|\u0441\u043f\u0438\u0441\u0430\u043d\u0438\u0439)\s+\u0437\u0430)/u.test(
|
||||
rawUtterance
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function supportsOrganizationScopedOpenTotal(action: string): boolean {
|
||||
return action === "turnover" || action === "payout";
|
||||
}
|
||||
@@ -142,6 +176,7 @@ function allowsOpenScopeWithoutSubject(input: {
|
||||
organizationScope: string | null;
|
||||
comparisonNeed: string | null;
|
||||
rankingNeed: string | null;
|
||||
oneSidedOpenScopeTotalHint: boolean;
|
||||
}): boolean {
|
||||
if (input.family !== "value_flow") {
|
||||
return false;
|
||||
@@ -149,7 +184,9 @@ function allowsOpenScopeWithoutSubject(input: {
|
||||
if (input.rankingNeed || input.comparisonNeed === "incoming_vs_outgoing") {
|
||||
return true;
|
||||
}
|
||||
return Boolean(input.organizationScope && supportsOrganizationScopedOpenTotal(input.action));
|
||||
return Boolean(
|
||||
supportsOrganizationScopedOpenTotal(input.action) && (input.organizationScope || input.oneSidedOpenScopeTotalHint)
|
||||
);
|
||||
}
|
||||
|
||||
function rankingNeedFromRawUtterance(value: string): string | null {
|
||||
@@ -303,6 +340,7 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||
const aggregationNeed = aggregationNeedFor(aggregationAxis);
|
||||
const comparisonNeed = comparisonNeedFor(action);
|
||||
const rankingNeed = rankingNeedFromRawUtterance(rawUtterance);
|
||||
const oneSidedOpenScopeTotalHint = hasOpenScopeOneSidedValueTotalHintUtf8Safe(rawUtterance, action);
|
||||
const openScopeWithoutSubject =
|
||||
subjectCandidates.length === 0 &&
|
||||
allowsOpenScopeWithoutSubject({
|
||||
@@ -310,13 +348,24 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||
action,
|
||||
organizationScope: explicitOrganizationScope,
|
||||
comparisonNeed,
|
||||
rankingNeed
|
||||
rankingNeed,
|
||||
oneSidedOpenScopeTotalHint
|
||||
});
|
||||
const clarificationGaps: string[] = [];
|
||||
if (unsupported === "metadata_lane_choice_clarification" || action === "resolve_next_lane") {
|
||||
pushUnique(clarificationGaps, "lane_family_choice");
|
||||
}
|
||||
if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && !openScopeWithoutSubject) {
|
||||
if (
|
||||
subjectCandidates.length === 0 &&
|
||||
businessFactFamily === "value_flow" &&
|
||||
openScopeWithoutSubject &&
|
||||
!rankingNeed &&
|
||||
!comparisonNeed &&
|
||||
oneSidedOpenScopeTotalHint &&
|
||||
!explicitOrganizationScope
|
||||
) {
|
||||
pushUnique(clarificationGaps, "organization");
|
||||
} else if (subjectCandidates.length === 0 && businessFactFamily !== "schema_surface" && !openScopeWithoutSubject) {
|
||||
pushUnique(clarificationGaps, "subject");
|
||||
}
|
||||
const timeScopeNeed = timeScopeNeedFor({
|
||||
@@ -353,6 +402,9 @@ export function buildAssistantMcpDiscoveryDataNeedGraph(
|
||||
if (openScopeWithoutSubject && !rankingNeed && !comparisonNeed) {
|
||||
pushReason(reasonCodes, "data_need_graph_open_scope_total_without_subject");
|
||||
}
|
||||
if (clarificationGaps.includes("organization")) {
|
||||
pushReason(reasonCodes, "data_need_graph_open_scope_total_needs_organization");
|
||||
}
|
||||
if (clarificationGaps.length > 0) {
|
||||
pushReason(reasonCodes, "data_need_graph_has_clarification_gaps");
|
||||
}
|
||||
|
||||
@@ -102,6 +102,13 @@ function hasSubjectCandidates(graph: AssistantMcpDiscoveryDataNeedGraphContract
|
||||
return (graph?.subject_candidates.length ?? 0) > 0;
|
||||
}
|
||||
|
||||
function hasReasonCode(
|
||||
graph: AssistantMcpDiscoveryDataNeedGraphContract | null | undefined,
|
||||
reasonCode: string
|
||||
): boolean {
|
||||
return (graph?.reason_codes ?? []).includes(reasonCode);
|
||||
}
|
||||
|
||||
function aggregationAxis(meaning: AssistantMcpDiscoveryTurnMeaningRef | null | undefined): string | null {
|
||||
return toNonEmptyString(meaning?.asked_aggregation_axis)?.toLowerCase() ?? null;
|
||||
}
|
||||
@@ -154,6 +161,10 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||
const graphAggregation = lower(dataNeedGraph?.aggregation_need);
|
||||
const graphClarificationGaps = (dataNeedGraph?.clarification_gaps ?? []).map((item) => lower(item));
|
||||
const organizationScope = toNonEmptyString(meaning?.explicit_organization_scope);
|
||||
const openScopeTotalWithoutSubject =
|
||||
graphFactFamily === "value_flow" &&
|
||||
!hasSubjectCandidates(dataNeedGraph) &&
|
||||
hasReasonCode(dataNeedGraph, "data_need_graph_open_scope_total_without_subject");
|
||||
const combined = `${domain} ${action} ${unsupported}`.trim();
|
||||
const axes: string[] = [];
|
||||
const requestedAggregationAxis = aggregationAxis(meaning);
|
||||
@@ -205,7 +216,8 @@ function recipeFor(input: AssistantMcpDiscoveryPlannerInput): PlannerRecipe {
|
||||
: "planner_selected_top_ranked_value_flow_from_data_need_graph"
|
||||
};
|
||||
}
|
||||
if (!hasSubjectCandidates(dataNeedGraph) && organizationScope) {
|
||||
if (openScopeTotalWithoutSubject) {
|
||||
pushUnique(axes, "organization");
|
||||
pushUnique(axes, "aggregate_axis");
|
||||
pushUnique(axes, "amount");
|
||||
pushUnique(axes, "coverage_target");
|
||||
@@ -451,7 +463,30 @@ export function planAssistantMcpDiscovery(
|
||||
maxProbeCount: budgetOverride.maxProbeCount
|
||||
});
|
||||
const review = reviewAssistantMcpDiscoveryPlanAgainstCatalog(plan);
|
||||
const plannerStatus = statusFrom(plan, review);
|
||||
const organizationClarificationRequired =
|
||||
(dataNeedGraph?.clarification_gaps ?? []).includes("organization") &&
|
||||
!toNonEmptyString(input.turnMeaning?.explicit_organization_scope);
|
||||
const adjustedReview =
|
||||
organizationClarificationRequired && recipe.primitives.includes("query_movements")
|
||||
? {
|
||||
...review,
|
||||
review_status: "needs_more_axes" as const,
|
||||
missing_axes_by_primitive: {
|
||||
...review.missing_axes_by_primitive,
|
||||
query_movements: review.missing_axes_by_primitive.query_movements?.length
|
||||
? review.missing_axes_by_primitive.query_movements
|
||||
: [["organization"]]
|
||||
},
|
||||
reason_codes: review.reason_codes.includes("catalog_requires_organization_scope_from_data_need_graph")
|
||||
? review.reason_codes
|
||||
: [...review.reason_codes, "catalog_requires_organization_scope_from_data_need_graph"]
|
||||
}
|
||||
: review;
|
||||
const plannerStatus = organizationClarificationRequired ? "needs_clarification" : statusFrom(plan, adjustedReview);
|
||||
|
||||
if (organizationClarificationRequired) {
|
||||
pushReason(reasonCodes, "planner_requires_organization_scope_from_data_need_graph");
|
||||
}
|
||||
|
||||
if (plannerStatus === "ready_for_execution") {
|
||||
pushReason(reasonCodes, "planner_ready_for_guarded_mcp_execution");
|
||||
@@ -467,12 +502,12 @@ export function planAssistantMcpDiscovery(
|
||||
planner_status: plannerStatus,
|
||||
semantic_data_need: semanticDataNeed,
|
||||
data_need_graph: dataNeedGraph,
|
||||
selected_chain_id: recipe.chainId,
|
||||
selected_chain_summary: recipe.chainSummary,
|
||||
proposed_primitives: recipe.primitives,
|
||||
required_axes: recipe.axes,
|
||||
discovery_plan: plan,
|
||||
catalog_review: review,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
selected_chain_id: recipe.chainId,
|
||||
selected_chain_summary: recipe.chainSummary,
|
||||
proposed_primitives: recipe.primitives,
|
||||
required_axes: recipe.axes,
|
||||
discovery_plan: plan,
|
||||
catalog_review: adjustedReview,
|
||||
reason_codes: reasonCodes
|
||||
};
|
||||
}
|
||||
|
||||
@@ -214,6 +214,27 @@ function readDiscoveryTurnMeaning(
|
||||
return toRecordObject(turnInput?.turn_meaning_ref);
|
||||
}
|
||||
|
||||
function readDiscoveryDataNeedGraph(
|
||||
entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract | null
|
||||
): Record<string, unknown> | null {
|
||||
const turnInput = toRecordObject(entryPoint?.turn_input);
|
||||
return toRecordObject(turnInput?.data_need_graph);
|
||||
}
|
||||
|
||||
function isOpenScopeValueFlowWithoutSubject(
|
||||
entryPoint: AssistantMcpDiscoveryRuntimeEntryPointContract | null
|
||||
): boolean {
|
||||
const graph = readDiscoveryDataNeedGraph(entryPoint);
|
||||
const businessFactFamily = toNonEmptyString(graph?.business_fact_family);
|
||||
const subjectCandidates = Array.isArray(graph?.subject_candidates) ? graph.subject_candidates : [];
|
||||
const reasonCodes = Array.isArray(graph?.reason_codes) ? graph.reason_codes : [];
|
||||
return (
|
||||
businessFactFamily === "value_flow" &&
|
||||
subjectCandidates.length === 0 &&
|
||||
reasonCodes.some((reason) => toNonEmptyString(reason) === "data_need_graph_open_scope_total_without_subject")
|
||||
);
|
||||
}
|
||||
|
||||
function readTruthAnswerShape(input: ApplyAssistantMcpDiscoveryResponsePolicyInput): Record<string, unknown> | null {
|
||||
const directShape = toRecordObject(input.addressRuntimeMeta?.answer_shape_contract);
|
||||
if (directShape) {
|
||||
@@ -286,6 +307,9 @@ function hasAlignedFactualAddressReply(
|
||||
if (!hasEffectivelyFactualAddressReply(input)) {
|
||||
return false;
|
||||
}
|
||||
if (hasSemanticConflictWithDiscoveryTurnMeaning(input, entryPoint)) {
|
||||
return false;
|
||||
}
|
||||
const detectedIntent = toNonEmptyString(input.addressRuntimeMeta?.detected_intent);
|
||||
return isDetectedIntentAlignedWithTurnMeaning(detectedIntent, readDiscoveryTurnMeaning(entryPoint));
|
||||
}
|
||||
@@ -311,6 +335,12 @@ function hasSemanticConflictWithDiscoveryTurnMeaning(
|
||||
if (!detectedIntent || (!askedDomain && !askedAction && !unsupportedFamily)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
detectedIntent === "customer_revenue_and_payments" &&
|
||||
isOpenScopeValueFlowWithoutSubject(entryPoint)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return !isDetectedIntentAlignedWithTurnMeaning(detectedIntent, turnMeaning);
|
||||
}
|
||||
|
||||
|
||||
@@ -436,6 +436,20 @@ function hasOrganizationScopeSignalUtf8(text: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function extractOrganizationScopeFromRawText(value: unknown): string | null {
|
||||
const text = toNonEmptyString(value);
|
||||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
const match = text.match(
|
||||
/(?:^|[\s,;:])(?:\u043f\u043e|for|in|within)?\s*((?:\u041e\u041e\u041e|\u0418\u041f|\u0410\u041e|\u041f\u0410\u041e|\u0417\u0410\u041e|LLC|Inc|LTD|Corp)\s+[^\n,.;:!?]+)/u
|
||||
);
|
||||
if (!match?.[1]) {
|
||||
return null;
|
||||
}
|
||||
return toNonEmptyString(match[1]);
|
||||
}
|
||||
|
||||
function hasMonthlyAggregationSignal(text: string): boolean {
|
||||
return /(?:\u043f\u043e\s+\u043c\u0435\u0441\u044f\u0446\u0430\u043c|\u043f\u043e\u043c\u0435\u0441\u044f\u0447\u043d\u043e|\u0435\u0436\u0435\u043c\u0435\u0441\u044f\u0447\u043d\u043e|month\s+by\s+month|by\s+month|monthly)/iu.test(
|
||||
text
|
||||
@@ -803,18 +817,35 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
const explicitIntentCandidate = toNonEmptyString(assistantTurnMeaning?.explicit_intent_candidate);
|
||||
const assistantTurnMeaningDateScope = toNonEmptyString(assistantTurnMeaning?.explicit_date_scope);
|
||||
const assistantTurnMeaningOrganizationScope = toNonEmptyString(assistantTurnMeaning?.explicit_organization_scope);
|
||||
const rawOrganizationMentionSignal = hasOrganizationScopeSignalUtf8(rawText);
|
||||
const rawOrganizationScope = extractOrganizationScopeFromRawText(rawUserText ?? rawEffectiveText ?? rawSignalSourceText);
|
||||
const explicitOrganizationScopeSignal = Boolean(
|
||||
rawOrganizationMentionSignal &&
|
||||
(rawOrganizationScope ?? predecomposeEntities.organization ?? assistantTurnMeaningOrganizationScope)
|
||||
);
|
||||
const organizationClarificationFollowupApplicable = Boolean(
|
||||
followupSeed.domain === "counterparty_value" &&
|
||||
!followupSeed.counterparty &&
|
||||
rawOrganizationMentionSignal &&
|
||||
(rawOrganizationScope || followupSeed.organization) &&
|
||||
!rawLifecycleSignal &&
|
||||
!rawValueFlowSignal &&
|
||||
!rawMetadataSignal
|
||||
);
|
||||
const rawOpenScopeValueFlowOrganizationSignal = Boolean(
|
||||
rawValueFlowSignal &&
|
||||
!rawBidirectionalValueFlowSignal &&
|
||||
hasOrganizationScopeSignalUtf8(rawText) &&
|
||||
(predecomposeEntities.organization ?? assistantTurnMeaningOrganizationScope)
|
||||
explicitOrganizationScopeSignal
|
||||
);
|
||||
const predecomposeOrganizationMirrorsCounterparty = sameScopedName(
|
||||
predecomposeEntities.counterparty,
|
||||
predecomposeEntities.organization
|
||||
);
|
||||
const organizationMirrorsPredecomposeCounterparty = Boolean(
|
||||
(rawBidirectionalValueFlowSignal || hasValueRankingSignal(rawText) || rawOpenScopeValueFlowOrganizationSignal) &&
|
||||
(rawBidirectionalValueFlowSignal ||
|
||||
hasValueRankingSignal(rawText) ||
|
||||
rawOpenScopeValueFlowOrganizationSignal ||
|
||||
explicitOrganizationScopeSignal) &&
|
||||
(sameScopedName(predecomposeEntities.counterparty, assistantTurnMeaningOrganizationScope) ||
|
||||
predecomposeOrganizationMirrorsCounterparty)
|
||||
);
|
||||
@@ -826,7 +857,11 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
followupSeed.domain &&
|
||||
!rawLifecycleSignal &&
|
||||
!rawValueFlowSignal &&
|
||||
(monthlyAggregationSignal || explicitDateScopeLiteralDetected || predecomposeDateScope)
|
||||
(monthlyAggregationSignal ||
|
||||
explicitDateScopeLiteralDetected ||
|
||||
predecomposeDateScope ||
|
||||
explicitOrganizationScopeSignal ||
|
||||
organizationClarificationFollowupApplicable)
|
||||
);
|
||||
const metadataFollowupSeedApplicable = Boolean(
|
||||
followupSeed.domain === "metadata" &&
|
||||
@@ -1114,6 +1149,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
bidirectionalValueFlowSignal ||
|
||||
hasValueRankingSignal(rawText) ||
|
||||
rawOpenScopeValueFlowOrganizationSignal ||
|
||||
explicitOrganizationScopeSignal ||
|
||||
followupSeed.organization
|
||||
);
|
||||
if (openScopeValueFlowWithoutCounterparty && !valueFlowOrganizationStaysScope) {
|
||||
@@ -1122,7 +1158,10 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
}
|
||||
const explicitOrganizationScope =
|
||||
valueFlowOrganizationStaysScope || !openScopeValueFlowWithoutCounterparty
|
||||
? predecomposeEntities.organization ?? assistantTurnMeaningOrganizationScope ?? followupSeed.organization
|
||||
? rawOrganizationScope ??
|
||||
predecomposeEntities.organization ??
|
||||
assistantTurnMeaningOrganizationScope ??
|
||||
followupSeed.organization
|
||||
: null;
|
||||
if (valueFlowOrganizationStaysScope && explicitOrganizationScope) {
|
||||
for (let index = entityCandidates.length - 1; index >= 0; index -= 1) {
|
||||
@@ -1258,6 +1297,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
groundedValueFlowFollowupApplicable,
|
||||
forceDiscoveryOverExplicitIntent:
|
||||
Boolean(entityResolutionClarificationCandidate) ||
|
||||
organizationClarificationFollowupApplicable ||
|
||||
metadataAmbiguityLaneClarificationApplicable ||
|
||||
metadataGroundedMovementLaneApplicable ||
|
||||
metadataGroundedDocumentLaneApplicable ||
|
||||
@@ -1308,6 +1348,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
if (entityResolutionClarificationCandidate) {
|
||||
pushReason(reasonCodes, "mcp_discovery_entity_resolution_clarification_candidate_selected");
|
||||
}
|
||||
if (organizationClarificationFollowupApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_organization_clarification_followup_from_followup_context");
|
||||
}
|
||||
if (payoutSignal) {
|
||||
pushReason(reasonCodes, "mcp_discovery_payout_signal_detected");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user