ARCH: связать metadata grounding с document MCP lane
This commit is contained in:
@@ -89,6 +89,33 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
expect(draft.must_not_claim).toContain("Do not claim a confirmed business fact when confirmed_facts is empty.");
|
||||
});
|
||||
|
||||
it("turns generic document evidence into a bounded document answer draft", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "documents",
|
||||
asked_action_family: "list_documents",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "document_evidence"
|
||||
}
|
||||
});
|
||||
const pilot = await executeAssistantMcpDiscoveryPilot(
|
||||
planner,
|
||||
buildDeps([{ Period: "2020-01-15T00:00:00", Counterparty: "SVK", Registrar: "Doc1" }])
|
||||
);
|
||||
|
||||
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||
|
||||
expect(draft.answer_mode).toBe("confirmed_with_bounded_inference");
|
||||
expect(draft.headline).toContain("документ");
|
||||
expect(draft.confirmed_lines).toContain("1C document rows were found for counterparty SVK");
|
||||
expect(draft.inference_lines).toContain(
|
||||
"Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"
|
||||
);
|
||||
expect(draft.unknown_lines).toContain("Full document history outside the checked period is not proven by this MCP discovery pilot");
|
||||
expect(draft.must_not_claim).toContain("Do not claim full document history outside the checked period.");
|
||||
});
|
||||
|
||||
it("asks for clarification when discovery did not execute due to missing scope", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
|
||||
@@ -103,6 +103,36 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("executes generic document evidence through query_documents", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "documents",
|
||||
asked_action_family: "list_documents",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "document_evidence"
|
||||
}
|
||||
});
|
||||
const deps = buildDeps([
|
||||
{ Period: "2020-01-15T00:00:00", Counterparty: "SVK", Registrar: "Doc1" },
|
||||
{ Period: "2020-03-20T00:00:00", Counterparty: "SVK", Registrar: "Doc2" }
|
||||
]);
|
||||
|
||||
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||
expect(result.executed_primitives).toEqual(["query_documents"]);
|
||||
expect(result.evidence.confirmed_facts).toContain("1C document rows were found for counterparty SVK");
|
||||
expect(result.evidence.inferred_facts).toContain(
|
||||
"Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"
|
||||
);
|
||||
expect(result.evidence.unknown_facts).toContain(
|
||||
"Full document history outside the checked period is not proven by this MCP discovery pilot"
|
||||
);
|
||||
expect(result.source_rows_summary).toBe("2 MCP document rows fetched, 2 matched document scope");
|
||||
});
|
||||
|
||||
it("executes inspect_1c_metadata and derives a confirmed metadata surface", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
@@ -535,7 +565,7 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(14);
|
||||
});
|
||||
|
||||
it("keeps non-lifecycle ready plans unsupported until a dedicated pilot exists", async () => {
|
||||
it("executes document-ready plans through the dedicated document pilot", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "counterparty_documents",
|
||||
@@ -547,11 +577,12 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
|
||||
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||
|
||||
expect(result.pilot_status).toBe("unsupported");
|
||||
expect(result.mcp_execution_performed).toBe(false);
|
||||
expect(result.skipped_primitives).toEqual(["resolve_entity_reference", "query_documents", "probe_coverage"]);
|
||||
expect(result.reason_codes).toContain("pilot_scope_unsupported_for_live_execution");
|
||||
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||
expect(result.mcp_execution_performed).toBe(true);
|
||||
expect(result.executed_primitives).toEqual(["query_documents"]);
|
||||
expect(result.reason_codes).toContain("pilot_query_documents_mcp_executed");
|
||||
expect(deps.executeAddressMcpQuery).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("records MCP errors as limitations without converting them into facts", async () => {
|
||||
|
||||
@@ -209,6 +209,33 @@ describe("assistant MCP discovery response candidate", () => {
|
||||
expect(candidate.reply_text).not.toContain("broad probe hit the row limit");
|
||||
});
|
||||
|
||||
it("localizes document evidence without leaking raw English facts", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
bridge: {
|
||||
bridge_status: "answer_draft_ready",
|
||||
user_facing_response_allowed: true,
|
||||
business_fact_answer_allowed: true,
|
||||
requires_user_clarification: false,
|
||||
answer_draft: {
|
||||
answer_mode: "confirmed_with_bounded_inference",
|
||||
headline: "По данным 1С найдены строки документов; ответ ограничен проверенным периодом и найденными строками.",
|
||||
confirmed_lines: ["1C document rows were found for counterparty SVK"],
|
||||
inference_lines: ["Counterparty document evidence is limited to confirmed 1C document rows in the checked scope"],
|
||||
unknown_lines: ["Full document history outside the checked period is not proven by this MCP discovery pilot"],
|
||||
limitation_lines: [],
|
||||
next_step_line: null
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(candidate.reply_text).toContain("В 1С найдены строки документов по контрагенту SVK.");
|
||||
expect(candidate.reply_text).toContain("Срез документов ограничен только подтвержденными строками документов");
|
||||
expect(candidate.reply_text).toContain("Полный исторический срез документов вне проверенного периода этим поиском не подтвержден.");
|
||||
expect(candidate.reply_text).not.toContain("1C document rows were found");
|
||||
});
|
||||
|
||||
it("localizes metadata evidence without leaking raw MCP wording", () => {
|
||||
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
|
||||
entryPoint({
|
||||
|
||||
@@ -51,7 +51,7 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||
expect(result.answer_draft.next_step_line).toContain("Уточните контрагента");
|
||||
});
|
||||
|
||||
it("keeps unsupported ready plans outside the hot answer path", async () => {
|
||||
it("keeps document-ready plans bounded when the pilot finds no confirmed rows", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeBridge({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "document",
|
||||
@@ -61,11 +61,12 @@ describe("assistant MCP discovery runtime bridge", () => {
|
||||
deps: buildDeps([])
|
||||
});
|
||||
|
||||
expect(result.bridge_status).toBe("unsupported");
|
||||
expect(result.bridge_status).toBe("checked_sources_only");
|
||||
expect(result.hot_runtime_wired).toBe(false);
|
||||
expect(result.pilot.mcp_execution_performed).toBe(false);
|
||||
expect(result.pilot.pilot_scope).toBe("counterparty_document_evidence_query_documents_v1");
|
||||
expect(result.pilot.mcp_execution_performed).toBe(true);
|
||||
expect(result.business_fact_answer_allowed).toBe(false);
|
||||
expect(result.reason_codes).toContain("runtime_bridge_status_unsupported");
|
||||
expect(result.reason_codes).toContain("runtime_bridge_status_checked_sources_only");
|
||||
});
|
||||
|
||||
it("preserves the answer adapter boundary against internal mechanics leakage", async () => {
|
||||
|
||||
@@ -231,6 +231,39 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
||||
});
|
||||
|
||||
it("pivots grounded metadata follow-up into document evidence when the next lane is explicit", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "then documents",
|
||||
followupContext: {
|
||||
previous_discovery_pilot_scope: "metadata_inspection_v1",
|
||||
previous_discovery_metadata_route_family: "document_evidence",
|
||||
previous_discovery_metadata_selected_entity_set: "Документ",
|
||||
previous_filters: {
|
||||
counterparty: "SVK",
|
||||
period_from: "2020-01-01",
|
||||
period_to: "2020-12-31"
|
||||
},
|
||||
previous_anchor_type: "counterparty",
|
||||
previous_anchor_value: "SVK"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("followup_context");
|
||||
expect(result.semantic_data_need).toBe("document evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "documents",
|
||||
asked_action_family: "list_documents",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020",
|
||||
unsupported_but_understood_family: "document_evidence",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_metadata_grounded_document_followup");
|
||||
expect(result.reason_codes).toContain("mcp_discovery_counterparty_from_followup_context");
|
||||
});
|
||||
|
||||
it("switches the checked year on a short payout follow-up while keeping prior discovery counterparty", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "а теперь за 2021?",
|
||||
|
||||
@@ -1114,6 +1114,61 @@ describe("assistantTransitionPolicy", () => {
|
||||
period_to: "2020-12-31"
|
||||
});
|
||||
});
|
||||
it("carries grounded metadata downstream route hints into followup context", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => null,
|
||||
hasAddressFollowupContextSignal: () => true
|
||||
});
|
||||
|
||||
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||
"then documents",
|
||||
[
|
||||
{
|
||||
role: "assistant",
|
||||
text: "Metadata surface confirmed.",
|
||||
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: "inspect_documents",
|
||||
explicit_entity_candidates: ["SVK"],
|
||||
explicit_date_scope: "2020"
|
||||
}
|
||||
},
|
||||
bridge: {
|
||||
bridge_status: "answer_draft_ready",
|
||||
business_fact_answer_allowed: true,
|
||||
pilot: {
|
||||
pilot_scope: "metadata_inspection_v1",
|
||||
derived_metadata_surface: {
|
||||
selected_entity_set: "Документ",
|
||||
downstream_route_family: "document_evidence",
|
||||
ambiguity_detected: false
|
||||
}
|
||||
},
|
||||
answer_draft: {
|
||||
answer_mode: "confirmed_with_bounded_inference"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
expect(carryover?.followupContext?.previous_discovery_pilot_scope).toBe("metadata_inspection_v1");
|
||||
expect(carryover?.followupContext?.previous_discovery_metadata_route_family).toBe("document_evidence");
|
||||
expect(carryover?.followupContext?.previous_discovery_metadata_selected_entity_set).toBe("Документ");
|
||||
expect(carryover?.followupContext?.previous_discovery_metadata_ambiguity_detected).toBeUndefined();
|
||||
});
|
||||
it("switches to VAT tax-period intent while preserving carried period filters", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => ({
|
||||
|
||||
Reference in New Issue
Block a user