NODEDC_1C/llm_normalizer/backend/tests/assistantMcpDiscoveryRespon...

110 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it } from "vitest";
import { buildAssistantMcpDiscoveryResponseCandidate } from "../src/services/assistantMcpDiscoveryResponseCandidate";
function entryPoint(overrides: Record<string, unknown> = {}) {
return {
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
entry_status: "bridge_executed",
hot_runtime_wired: false,
discovery_attempted: true,
turn_input: { adapter_status: "ready" },
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 activity rows were found for counterparty SVK"],
inference_lines: ["Business activity duration may be inferred from first and latest confirmed 1C activity rows"],
unknown_lines: ["Legal registration date is not proven by this MCP discovery pilot"],
limitation_lines: ["query_documents was skipped internally", "MCP fetch window was limited"],
next_step_line: null
}
},
reason_codes: ["runtime_entry_point_bridge_executed"],
...overrides
} as any;
}
describe("assistant MCP discovery response candidate", () => {
it("builds a Russian guarded candidate from a confirmed discovery draft", () => {
const candidate = buildAssistantMcpDiscoveryResponseCandidate(entryPoint());
expect(candidate.candidate_status).toBe("ready_for_guarded_use");
expect(candidate.hot_runtime_wired).toBe(false);
expect(candidate.reply_type).toBe("partial_coverage");
expect(candidate.eligible_for_future_hot_runtime).toBe(true);
expect(candidate.reply_text).toContain("Коротко:");
expect(candidate.reply_text).toContain("В 1С найдены строки активности по контрагенту SVK.");
expect(candidate.reply_text).toContain("Юридическая дата регистрации этим поиском не подтверждена.");
expect(candidate.reply_text).not.toContain("query_documents");
expect(candidate.reply_text).not.toContain("primitive");
});
it("returns not applicable when discovery was skipped for an exact supported route", () => {
const candidate = buildAssistantMcpDiscoveryResponseCandidate({
schema_version: "assistant_mcp_discovery_runtime_entry_point_v1",
policy_owner: "assistantMcpDiscoveryRuntimeEntryPoint",
entry_status: "skipped_not_applicable",
hot_runtime_wired: false,
discovery_attempted: false,
turn_input: { adapter_status: "not_applicable" },
bridge: null,
reason_codes: []
} as any);
expect(candidate.candidate_status).toBe("not_applicable");
expect(candidate.reply_text).toBeNull();
expect(candidate.eligible_for_future_hot_runtime).toBe(false);
});
it("creates a clarification candidate from a clarification bridge", () => {
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
entryPoint({
bridge: {
bridge_status: "needs_clarification",
user_facing_response_allowed: true,
business_fact_answer_allowed: false,
requires_user_clarification: true,
answer_draft: {
answer_mode: "needs_clarification",
headline: "Нужно уточнить контекст перед поиском в 1С.",
confirmed_lines: [],
inference_lines: [],
unknown_lines: [],
limitation_lines: [],
next_step_line: "Уточните контрагента, период или организацию."
}
}
})
);
expect(candidate.candidate_status).toBe("clarification_candidate");
expect(candidate.reply_type).toBe("clarification_required");
expect(candidate.reply_text).toContain("Нужно уточнить контекст");
expect(candidate.eligible_for_future_hot_runtime).toBe(true);
});
it("does not expose unsupported bridge output as a future hot candidate", () => {
const candidate = buildAssistantMcpDiscoveryResponseCandidate(
entryPoint({
bridge: {
bridge_status: "unsupported",
user_facing_response_allowed: true,
business_fact_answer_allowed: false,
requires_user_clarification: false,
answer_draft: null
}
})
);
expect(candidate.candidate_status).toBe("unsupported");
expect(candidate.reply_type).toBe("no_grounded_answer");
expect(candidate.reply_text).toBeNull();
expect(candidate.eligible_for_future_hot_runtime).toBe(false);
});
});