ARCH: продолжить metadata continuity для MCP discovery
This commit is contained in:
@@ -146,6 +146,31 @@ function localizeLine(value: string): string {
|
||||
if (/^Counterparty monthly net value-flow breakdown was grouped by month over confirmed incoming and outgoing 1C rows$/i.test(value)) {
|
||||
return "Помесячная нетто-раскладка сгруппирована только по подтвержденным входящим и исходящим строкам 1С.";
|
||||
}
|
||||
const metadataSurfaceMatch = value.match(
|
||||
/^Confirmed 1C metadata surface(?: for scope "([^"]+)")?: (\d+) rows and (\d+) matching objects$/i
|
||||
);
|
||||
if (metadataSurfaceMatch) {
|
||||
const scopePart = metadataSurfaceMatch[1] ? ` по области "${metadataSurfaceMatch[1]}"` : "";
|
||||
return `В 1С подтверждена metadata-поверхность${scopePart}: ${metadataSurfaceMatch[2]} строк metadata-ответа и ${metadataSurfaceMatch[3]} совпавших объекта(ов).`;
|
||||
}
|
||||
const metadataObjectSetsMatch = value.match(/^Available metadata object sets: (.+)$/i);
|
||||
if (metadataObjectSetsMatch) {
|
||||
return `Доступные типы metadata-объектов: ${metadataObjectSetsMatch[1]}.`;
|
||||
}
|
||||
const metadataFieldsMatch = value.match(/^Available metadata fields\/sections: (.+)$/i);
|
||||
if (metadataFieldsMatch) {
|
||||
return `Доступные metadata-поля/секции: ${metadataFieldsMatch[1]}.`;
|
||||
}
|
||||
if (/^Detailed metadata fields were not returned by this MCP metadata probe$/i.test(value)) {
|
||||
return "Эта MCP-проверка metadata не вернула детальный список полей.";
|
||||
}
|
||||
const noMatchingMetadataScopeMatch = value.match(/^No matching 1C metadata objects were confirmed for scope "([^"]+)"$/i);
|
||||
if (noMatchingMetadataScopeMatch) {
|
||||
return `В 1С не подтверждены metadata-объекты по области "${noMatchingMetadataScopeMatch[1]}".`;
|
||||
}
|
||||
if (/^No matching 1C metadata objects were confirmed by this MCP metadata probe$/i.test(value)) {
|
||||
return "В 1С эта MCP-проверка не подтвердила подходящих metadata-объектов.";
|
||||
}
|
||||
if (/^Legal registration date is not proven by this MCP discovery pilot$/i.test(value)) {
|
||||
return "Юридическая дата регистрации этим поиском не подтверждена.";
|
||||
}
|
||||
|
||||
@@ -190,6 +190,13 @@ function mapPilotScopeToFollowupMeaning(
|
||||
unsupported: "counterparty_bidirectional_value_flow_or_netting"
|
||||
};
|
||||
}
|
||||
if (pilotScope === "metadata_inspection_v1") {
|
||||
return {
|
||||
domain: "metadata",
|
||||
action: "inspect_catalog",
|
||||
unsupported: "1c_metadata_surface"
|
||||
};
|
||||
}
|
||||
return {
|
||||
domain: null,
|
||||
action: null,
|
||||
@@ -238,6 +245,7 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||
action: string | null;
|
||||
unsupported: string | null;
|
||||
counterparty: string | null;
|
||||
discoveryEntity: string | null;
|
||||
organization: string | null;
|
||||
dateScope: string | null;
|
||||
} {
|
||||
@@ -250,6 +258,7 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||
mapPilotScopeToFollowupMeaning(pilotScope).domain !== null
|
||||
? mapPilotScopeToFollowupMeaning(pilotScope)
|
||||
: mapAddressIntentToFollowupMeaning(previousIntent);
|
||||
const discoveryEntities = collectEntityCandidates(followupContext?.previous_discovery_entity_candidates);
|
||||
const counterparty =
|
||||
toNonEmptyString(previousFilters?.counterparty) ??
|
||||
toNonEmptyString(rootFilters?.counterparty) ??
|
||||
@@ -271,6 +280,7 @@ function collectFollowupDiscoverySeed(followupContext: Record<string, unknown> |
|
||||
action: mapped.action,
|
||||
unsupported: mapped.unsupported,
|
||||
counterparty,
|
||||
discoveryEntity: discoveryEntities[0] ?? null,
|
||||
organization,
|
||||
dateScope
|
||||
};
|
||||
@@ -322,6 +332,12 @@ function hasMetadataSignal(text: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function hasMetadataObjectHint(text: string): boolean {
|
||||
return /(?:\u0440\u0435\u0433\u0438\u0441\u0442\u0440(?:\u044b)?|\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442(?:\u044b)?|\u0441\u043f\u0440\u0430\u0432\u043e\u0447\u043d\u0438\u043a(?:\u0438)?|\u043f\u043e\u043b(?:\u0435|\u044f)|registers?|documents?|catalogs?|fields?)/iu.test(
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
function metadataActionFromRawText(text: string): string {
|
||||
if (/(?:\u043f\u043e\u043b(?:\u0435|\u044f)|field)/iu.test(text)) {
|
||||
return "inspect_fields";
|
||||
@@ -443,9 +459,15 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
!rawValueFlowSignal &&
|
||||
(monthlyAggregationSignal || explicitDateScopeLiteralDetected || predecomposeDateScope)
|
||||
);
|
||||
const seededDomain = followupDiscoverySeedApplicable ? followupSeed.domain : null;
|
||||
const seededAction = followupDiscoverySeedApplicable ? followupSeed.action : null;
|
||||
const seededUnsupported = followupDiscoverySeedApplicable ? followupSeed.unsupported : null;
|
||||
const metadataFollowupSeedApplicable = Boolean(
|
||||
followupSeed.domain === "metadata" &&
|
||||
!rawLifecycleSignal &&
|
||||
!rawValueFlowSignal &&
|
||||
hasMetadataObjectHint(rawText)
|
||||
);
|
||||
const seededDomain = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.domain : null;
|
||||
const seededAction = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.action : null;
|
||||
const seededUnsupported = followupDiscoverySeedApplicable || metadataFollowupSeedApplicable ? followupSeed.unsupported : null;
|
||||
const lifecycleSignal =
|
||||
rawLifecycleSignal || seededDomain === "counterparty_lifecycle";
|
||||
const bidirectionalValueFlowSignal =
|
||||
@@ -463,11 +485,14 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
unsupported: unsupported ?? seededUnsupported,
|
||||
lifecycleSignal,
|
||||
valueFlowSignal,
|
||||
metadataSignal: rawMetadataSignal
|
||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable
|
||||
});
|
||||
const entityCandidates = collectEntityCandidates(assistantTurnMeaning?.explicit_entity_candidates);
|
||||
pushUnique(entityCandidates, predecomposeEntities.counterparty);
|
||||
pushUnique(entityCandidates, followupSeed.counterparty);
|
||||
if ((rawMetadataSignal || metadataFollowupSeedApplicable) && !followupSeed.counterparty) {
|
||||
pushUnique(entityCandidates, followupSeed.discoveryEntity);
|
||||
}
|
||||
if (valueFlowSignal && !predecomposeEntities.counterparty && !followupSeed.counterparty) {
|
||||
pushUnique(entityCandidates, predecomposeEntities.organization);
|
||||
pushUnique(entityCandidates, followupSeed.organization);
|
||||
@@ -484,7 +509,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
? "counterparty_lifecycle"
|
||||
: valueFlowSignal
|
||||
? "counterparty_value"
|
||||
: rawMetadataSignal
|
||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
||||
? "metadata"
|
||||
: rawDomain ?? seededDomain,
|
||||
asked_action_family: lifecycleSignal
|
||||
@@ -495,8 +520,8 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
: payoutSignal
|
||||
? "payout"
|
||||
: rawAction ?? seededAction ?? "turnover"
|
||||
: rawMetadataSignal
|
||||
? metadataActionFromRawText(rawText)
|
||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
||||
? metadataActionFromRawText(rawText) ?? seededAction
|
||||
: rawAction ?? seededAction,
|
||||
asked_aggregation_axis: monthlyAggregationSignal ? "month" : rawAggregationAxis,
|
||||
explicit_entity_candidates: entityCandidates,
|
||||
@@ -512,7 +537,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
: payoutSignal
|
||||
? "counterparty_payouts_or_outflow"
|
||||
: seededUnsupported ?? "counterparty_value_or_turnover"
|
||||
: rawMetadataSignal
|
||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
||||
? "1c_metadata_surface"
|
||||
: followupDiscoverySeedApplicable
|
||||
? seededUnsupported
|
||||
@@ -523,6 +548,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
lifecycleSignal ||
|
||||
valueFlowSignal ||
|
||||
rawMetadataSignal ||
|
||||
metadataFollowupSeedApplicable ||
|
||||
followupDiscoverySeedApplicable
|
||||
)
|
||||
};
|
||||
@@ -557,15 +583,15 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
unsupported: unsupported ?? seededUnsupported,
|
||||
lifecycleSignal,
|
||||
valueFlowSignal,
|
||||
metadataSignal: rawMetadataSignal,
|
||||
metadataSignal: rawMetadataSignal || metadataFollowupSeedApplicable,
|
||||
semanticDataNeed,
|
||||
explicitIntentCandidate,
|
||||
followupDiscoverySeedApplicable
|
||||
followupDiscoverySeedApplicable: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
||||
});
|
||||
const hasTurnMeaning = Object.keys(cleanTurnMeaning).length > 0;
|
||||
const sourceSignal: AssistantMcpDiscoveryTurnInputSource = assistantTurnMeaning
|
||||
? "assistant_turn_meaning"
|
||||
: followupDiscoverySeedApplicable
|
||||
: followupDiscoverySeedApplicable || metadataFollowupSeedApplicable
|
||||
? "followup_context"
|
||||
: predecomposeContract
|
||||
? "predecompose_contract"
|
||||
@@ -573,7 +599,7 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
? "raw_text"
|
||||
: valueFlowSignal
|
||||
? "raw_text"
|
||||
: rawMetadataSignal
|
||||
: rawMetadataSignal || metadataFollowupSeedApplicable
|
||||
? "raw_text"
|
||||
: "none";
|
||||
|
||||
@@ -598,6 +624,9 @@ export function buildAssistantMcpDiscoveryTurnInput(
|
||||
if (followupDiscoverySeedApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_seeded_from_followup_context");
|
||||
}
|
||||
if (metadataFollowupSeedApplicable) {
|
||||
pushReason(reasonCodes, "mcp_discovery_metadata_seeded_from_followup_context");
|
||||
}
|
||||
if (unsupported) {
|
||||
pushReason(reasonCodes, "mcp_discovery_unsupported_but_understood_turn");
|
||||
}
|
||||
|
||||
@@ -77,12 +77,35 @@ function periodPartForRecap(scopedDate: string | null): string {
|
||||
return /^\d{2}\.\d{2}\.\d{4}$/.test(scopedDate) ? ` на ${scopedDate}` : ` за период ${scopedDate}`;
|
||||
}
|
||||
|
||||
function readDiscoveryMetadataScope(debug: Record<string, unknown> | null): string | null {
|
||||
const discoveryEntry = toRecordObject(debug?.assistant_mcp_discovery_entry_point_v1);
|
||||
const bridge = toRecordObject(discoveryEntry?.bridge);
|
||||
const pilot = toRecordObject(bridge?.pilot);
|
||||
const surface = toRecordObject(pilot?.derived_metadata_surface);
|
||||
const surfaceScope = toNonEmptyString(surface?.metadata_scope);
|
||||
if (surfaceScope) {
|
||||
return surfaceScope;
|
||||
}
|
||||
const turnInput = toRecordObject(discoveryEntry?.turn_input);
|
||||
const turnMeaningRef = toRecordObject(turnInput?.turn_meaning_ref);
|
||||
const entityCandidates = Array.isArray(turnMeaningRef?.explicit_entity_candidates)
|
||||
? turnMeaningRef.explicit_entity_candidates
|
||||
: [];
|
||||
for (const candidate of entityCandidates) {
|
||||
const text = toNonEmptyString(candidate);
|
||||
if (text) {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildDiscoveryRecapFactLine(input: {
|
||||
debug: Record<string, unknown> | null;
|
||||
counterparty: string | null;
|
||||
scopedDate: string | null;
|
||||
}): string | null {
|
||||
if (!input.debug || !input.counterparty) {
|
||||
if (!input.debug) {
|
||||
return null;
|
||||
}
|
||||
const pilotScope = readAssistantMcpDiscoveryPilotScope(input.debug, toNonEmptyString);
|
||||
@@ -90,6 +113,36 @@ function buildDiscoveryRecapFactLine(input: {
|
||||
const bridge = toRecordObject(discoveryEntry?.bridge);
|
||||
const pilot = toRecordObject(bridge?.pilot);
|
||||
const periodPart = periodPartForRecap(input.scopedDate);
|
||||
if (pilotScope === "metadata_inspection_v1") {
|
||||
const metadataScope = readDiscoveryMetadataScope(input.debug);
|
||||
const surface = toRecordObject(pilot?.derived_metadata_surface);
|
||||
const entitySets = Array.isArray(surface?.available_entity_sets)
|
||||
? surface.available_entity_sets
|
||||
.map((item) => toNonEmptyString(item))
|
||||
.filter((item): item is string => Boolean(item))
|
||||
: [];
|
||||
const fields = Array.isArray(surface?.available_fields)
|
||||
? surface.available_fields
|
||||
.map((item) => toNonEmptyString(item))
|
||||
.filter((item): item is string => Boolean(item))
|
||||
: [];
|
||||
const objects = Array.isArray(surface?.matched_objects)
|
||||
? surface.matched_objects
|
||||
.map((item) => toNonEmptyString(item))
|
||||
.filter((item): item is string => Boolean(item))
|
||||
: [];
|
||||
const rows = Number(surface?.matched_rows ?? 0);
|
||||
const scopePart = metadataScope ? ` по области «${metadataScope}»` : "";
|
||||
const objectsPart = objects.length > 0 ? `, нашли объекты ${objects.slice(0, 4).join(", ")}` : "";
|
||||
const entitySetsPart =
|
||||
entitySets.length > 0 ? `, видны типы ${entitySets.slice(0, 4).join(", ")}` : "";
|
||||
const fieldsPart =
|
||||
fields.length > 0 ? `, доступны поля/секции ${fields.slice(0, 5).join(", ")}` : "";
|
||||
return `смотрели metadata-поверхность 1С${scopePart}${periodPart}: ${rows} подтвержденных строк${objectsPart}${entitySetsPart}${fieldsPart}`.trim();
|
||||
}
|
||||
if (!input.counterparty) {
|
||||
return null;
|
||||
}
|
||||
if (pilotScope === "counterparty_lifecycle_query_documents_v1") {
|
||||
const activityPeriod = toRecordObject(pilot?.derived_activity_period);
|
||||
const duration = toNonEmptyString(activityPeriod?.duration_human_ru);
|
||||
|
||||
Reference in New Issue
Block a user