ARCH: перезапустить план на MCP bounded autonomy и добавить metadata pilot
This commit is contained in:
@@ -31,6 +31,17 @@ function buildSequentialDeps(results: Array<{ rows: Array<Record<string, unknown
|
||||
return { executeAddressMcpQuery };
|
||||
}
|
||||
|
||||
function buildMetadataDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
|
||||
return {
|
||||
executeAddressMcpMetadata: vi.fn(async () => ({
|
||||
fetched_rows: error ? 0 : rows.length,
|
||||
raw_rows: error ? [] : rows,
|
||||
rows: error ? [] : rows,
|
||||
error
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
describe("assistant MCP discovery answer adapter", () => {
|
||||
it("turns confirmed lifecycle evidence into a human-safe bounded answer draft", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
@@ -96,6 +107,36 @@ describe("assistant MCP discovery answer adapter", () => {
|
||||
expect(draft.must_not_claim).toContain("Do not claim rows were checked when mcp_execution_performed=false.");
|
||||
});
|
||||
|
||||
it("turns metadata surface evidence into a human-safe metadata answer draft", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "metadata",
|
||||
asked_action_family: "inspect_documents",
|
||||
explicit_entity_candidates: ["НДС"]
|
||||
}
|
||||
});
|
||||
const pilot = await executeAssistantMcpDiscoveryPilot(
|
||||
planner,
|
||||
buildMetadataDeps([
|
||||
{
|
||||
FullName: "Документ.СчетФактураВыданный",
|
||||
MetaType: "Документ",
|
||||
attributes: [{ Name: "Дата" }, { Name: "Организация" }]
|
||||
}
|
||||
])
|
||||
);
|
||||
|
||||
const draft = buildAssistantMcpDiscoveryAnswerDraft(pilot);
|
||||
const confirmedText = draft.confirmed_lines.join("\n");
|
||||
|
||||
expect(draft.answer_mode).toBe("confirmed_with_bounded_inference");
|
||||
expect(draft.headline).toContain("метаданным 1С");
|
||||
expect(confirmedText).toContain("Подтвержденная metadata-поверхность 1С");
|
||||
expect(confirmedText).toContain("Документ.СчетФактураВыданный");
|
||||
expect(confirmedText).toContain("Дата");
|
||||
expect(draft.must_not_claim).toContain("Do not present metadata surface as confirmed business data rows.");
|
||||
});
|
||||
|
||||
it("turns value-flow evidence into a bounded turnover answer draft", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
|
||||
@@ -30,6 +30,17 @@ function buildSequentialDeps(results: Array<{ rows: Array<Record<string, unknown
|
||||
return { executeAddressMcpQuery };
|
||||
}
|
||||
|
||||
function buildMetadataDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
|
||||
return {
|
||||
executeAddressMcpMetadata: vi.fn(async () => ({
|
||||
fetched_rows: error ? 0 : rows.length,
|
||||
raw_rows: error ? [] : rows,
|
||||
rows: error ? [] : rows,
|
||||
error
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
describe("assistant MCP discovery pilot executor", () => {
|
||||
it("executes only the lifecycle query_documents primitive through injected MCP deps", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
@@ -92,6 +103,53 @@ describe("assistant MCP discovery pilot executor", () => {
|
||||
expect(deps.executeAddressMcpQuery).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("executes inspect_1c_metadata and derives a confirmed metadata surface", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "metadata",
|
||||
asked_action_family: "inspect_documents",
|
||||
explicit_entity_candidates: ["НДС"]
|
||||
}
|
||||
});
|
||||
const deps = buildMetadataDeps([
|
||||
{
|
||||
FullName: "Документ.СчетФактураВыданный",
|
||||
MetaType: "Документ",
|
||||
attributes: [{ Name: "Дата" }, { Name: "Организация" }]
|
||||
},
|
||||
{
|
||||
FullName: "Документ.СчетФактураПолученный",
|
||||
MetaType: "Документ",
|
||||
attributes: [{ Name: "Контрагент" }]
|
||||
}
|
||||
]);
|
||||
|
||||
const result = await executeAssistantMcpDiscoveryPilot(planner, deps);
|
||||
|
||||
expect(result.pilot_status).toBe("executed");
|
||||
expect(result.pilot_scope).toBe("metadata_inspection_v1");
|
||||
expect(result.mcp_execution_performed).toBe(true);
|
||||
expect(result.executed_primitives).toEqual(["inspect_1c_metadata"]);
|
||||
expect(result.evidence.evidence_status).toBe("confirmed");
|
||||
expect(result.source_rows_summary).toBe("2 MCP metadata rows fetched");
|
||||
expect(result.derived_metadata_surface).toMatchObject({
|
||||
metadata_scope: "НДС",
|
||||
requested_meta_types: ["Документ"],
|
||||
matched_rows: 2,
|
||||
available_entity_sets: ["Документ"],
|
||||
matched_objects: ["Документ.СчетФактураВыданный", "Документ.СчетФактураПолученный"],
|
||||
available_fields: ["Дата", "Организация", "Контрагент"],
|
||||
inference_basis: "confirmed_1c_metadata_surface_rows"
|
||||
});
|
||||
expect(result.reason_codes).toContain("pilot_inspect_1c_metadata_mcp_executed");
|
||||
expect(result.reason_codes).toContain("pilot_derived_metadata_surface_from_confirmed_rows");
|
||||
expect(deps.executeAddressMcpMetadata).toHaveBeenCalledTimes(1);
|
||||
expect(deps.executeAddressMcpMetadata.mock.calls[0]?.[0]).toMatchObject({
|
||||
meta_type: ["Документ"],
|
||||
name_mask: "НДС"
|
||||
});
|
||||
});
|
||||
|
||||
it("executes value-flow query_movements and derives a guarded turnover sum", async () => {
|
||||
const planner = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
|
||||
@@ -120,6 +120,19 @@ describe("assistant MCP discovery planner", () => {
|
||||
expect(result.catalog_review.evidence_floors.inspect_1c_metadata).toBe("source_summary");
|
||||
});
|
||||
|
||||
it("keeps metadata document inspection on inspect_1c_metadata instead of query_documents", () => {
|
||||
const result = planAssistantMcpDiscovery({
|
||||
turnMeaning: {
|
||||
asked_domain_family: "metadata",
|
||||
asked_action_family: "inspect_documents"
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.planner_status).toBe("ready_for_execution");
|
||||
expect(result.proposed_primitives).toEqual(["inspect_1c_metadata"]);
|
||||
expect(result.proposed_primitives).not.toContain("query_documents");
|
||||
});
|
||||
|
||||
it("does not mark an unclassified turn as executable without turn meaning context", () => {
|
||||
const result = planAssistantMcpDiscovery({});
|
||||
|
||||
|
||||
@@ -13,6 +13,17 @@ function buildDeps(rows: Array<Record<string, unknown>>, error: string | null =
|
||||
};
|
||||
}
|
||||
|
||||
function buildMetadataDeps(rows: Array<Record<string, unknown>>, error: string | null = null) {
|
||||
return {
|
||||
executeAddressMcpMetadata: vi.fn(async () => ({
|
||||
fetched_rows: error ? 0 : rows.length,
|
||||
raw_rows: error ? [] : rows,
|
||||
rows: error ? [] : rows,
|
||||
error
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
describe("assistant MCP discovery runtime entry point", () => {
|
||||
it("runs the bridge for discovery-eligible lifecycle turn context", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
@@ -78,4 +89,27 @@ describe("assistant MCP discovery runtime entry point", () => {
|
||||
expect(result.bridge?.hot_runtime_wired).toBe(false);
|
||||
expect(result.reason_codes).toContain("mcp_discovery_unsupported_but_understood_turn");
|
||||
});
|
||||
|
||||
it("runs the bridge for raw metadata wording without an exact route owner", async () => {
|
||||
const result = await runAssistantMcpDiscoveryRuntimeEntryPoint({
|
||||
userMessage: "какие документы и поля есть в 1С по НДС?",
|
||||
deps: buildMetadataDeps([
|
||||
{
|
||||
FullName: "Документ.СчетФактураВыданный",
|
||||
MetaType: "Документ",
|
||||
attributes: [{ Name: "Дата" }]
|
||||
}
|
||||
])
|
||||
});
|
||||
|
||||
expect(result.entry_status).toBe("bridge_executed");
|
||||
expect(result.discovery_attempted).toBe(true);
|
||||
expect(result.turn_input.semantic_data_need).toBe("1C metadata evidence");
|
||||
expect(result.turn_input.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "metadata",
|
||||
asked_action_family: "inspect_fields"
|
||||
});
|
||||
expect(result.bridge?.pilot.pilot_scope).toBe("metadata_inspection_v1");
|
||||
expect(result.bridge?.answer_draft.headline).toContain("метаданным 1С");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -151,6 +151,24 @@ describe("assistant MCP discovery turn input adapter", () => {
|
||||
expect(result.reason_codes).toContain("mcp_discovery_monthly_aggregation_signal_detected");
|
||||
});
|
||||
|
||||
it("bootstraps metadata discovery from raw schema wording", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "какие регистры и поля есть в 1С по НДС?"
|
||||
});
|
||||
|
||||
expect(result.adapter_status).toBe("ready");
|
||||
expect(result.should_run_discovery).toBe(true);
|
||||
expect(result.source_signal).toBe("raw_text");
|
||||
expect(result.semantic_data_need).toBe("1C metadata evidence");
|
||||
expect(result.turn_meaning_ref).toMatchObject({
|
||||
asked_domain_family: "metadata",
|
||||
asked_action_family: "inspect_fields",
|
||||
unsupported_but_understood_family: "1c_metadata_surface",
|
||||
stale_replay_forbidden: true
|
||||
});
|
||||
expect(result.reason_codes).toContain("mcp_discovery_metadata_signal_detected");
|
||||
});
|
||||
|
||||
it("seeds short monthly follow-up from prior bidirectional discovery context", () => {
|
||||
const result = buildAssistantMcpDiscoveryTurnInput({
|
||||
userMessage: "а по месяцам?",
|
||||
|
||||
Reference in New Issue
Block a user