109 lines
4.9 KiB
TypeScript
109 lines
4.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import { AddressQueryService } from "../src/services/addressQueryService";
|
||
import { resolveAssistantOrchestrationDecision, resolveLivingAssistantModeDecision } from "../src/services/assistantService";
|
||
|
||
describe("wave17 run regressions (2026-04-11 real runs)", () => {
|
||
it("keeps real run 17:51 data-heavy prompts in address lane", () => {
|
||
const realRunPrompts = [
|
||
"Где у нас накопились авансы к отгрузкам, которые уже давно пора закрыть или хотя бы перепроверить, чтобы не подозревать худшее?",
|
||
"Какие контрагенты у нас на этом моменте могут быть причислены к тем, кто вообще не платит уже несколько месяцев?",
|
||
"В каких случаях мы видим зависшие отгрузки, которые уже давно пора закрыть - это грозит проблемами в отчетности."
|
||
];
|
||
|
||
for (const prompt of realRunPrompts) {
|
||
const decision = resolveAssistantOrchestrationDecision({
|
||
rawUserMessage: prompt,
|
||
effectiveAddressUserMessage: prompt,
|
||
followupContext: null,
|
||
llmPreDecomposeMeta: null,
|
||
useMock: false
|
||
});
|
||
|
||
expect(decision.runAddressLane).toBe(true);
|
||
expect(["address_mode_classifier_detected", "address_signal_detected", "address_intent_resolver_detected"]).toContain(
|
||
decision.toolGateReason
|
||
);
|
||
expect(decision.livingMode).toBe("address_data");
|
||
expect(decision.livingReason).toBe("address_lane_triggered");
|
||
}
|
||
});
|
||
|
||
it("keeps short follow-up style prompts out of chat drift when predecompose says unsupported", () => {
|
||
const shortFollowups = ["без воды?", "и коротко?", "прям сейчас?"];
|
||
|
||
for (const prompt of shortFollowups) {
|
||
const decision = resolveLivingAssistantModeDecision({
|
||
userMessage: prompt,
|
||
addressLaneTriggered: false,
|
||
useMock: false,
|
||
predecomposeMode: "unsupported",
|
||
predecomposeModeConfidence: "low"
|
||
});
|
||
|
||
expect(decision.mode).toBe("deep_analysis");
|
||
expect(decision.reason).toBe("predecompose_unsupported_mode_fallback_to_deep");
|
||
}
|
||
});
|
||
|
||
it("routes data-scope slang wording to chat mode", () => {
|
||
const decision = resolveLivingAssistantModeDecision({
|
||
userMessage: "по каким конторам можем общаться?",
|
||
addressLaneTriggered: false,
|
||
useMock: false,
|
||
predecomposeMode: "unsupported",
|
||
predecomposeModeConfidence: "low"
|
||
});
|
||
|
||
expect(decision.mode).toBe("chat");
|
||
expect(decision.reason).toBe("assistant_data_scope_query_detected");
|
||
});
|
||
|
||
it("keeps open-contracts request in address lane even with stale deep followup context", () => {
|
||
const decision = resolveAssistantOrchestrationDecision({
|
||
rawUserMessage: "Покажи незакрытые договоры на 2020-12-31",
|
||
effectiveAddressUserMessage: "Покажи незакрытые договоры на 2020-12-31",
|
||
followupContext: {
|
||
previous_question_id: "msg-prev",
|
||
last_user_message: "почему так по закрытию месяца",
|
||
active_domain: "month_close_costs_20_44",
|
||
active_requirement_ids: ["R1"],
|
||
uncovered_requirement_ids: ["R1"],
|
||
referenced_requirement_ids: ["R1"]
|
||
} as any,
|
||
llmPreDecomposeMeta: {
|
||
applied: true,
|
||
llmCanonicalCandidateDetected: true,
|
||
reason: "normalized_fragment_applied",
|
||
predecomposeContract: {
|
||
mode: "address_query",
|
||
mode_confidence: "high",
|
||
intent: "list_open_contracts",
|
||
intent_confidence: "medium"
|
||
}
|
||
} as any,
|
||
useMock: false
|
||
});
|
||
|
||
expect(decision.runAddressLane).toBe(true);
|
||
expect(decision.livingMode).toBe("address_data");
|
||
expect(decision.livingReason).toBe("address_lane_triggered");
|
||
expect(decision.orchestrationContract?.deep_analysis_signal_fallback_to_deep).toBe(false);
|
||
});
|
||
|
||
it("uses soft unsupported aggregate replies instead of rigid old template", async () => {
|
||
const service = new AddressQueryService();
|
||
const prompts = ["какой самый доходный год?", "какие обороты по альтернативе за 2020 год"];
|
||
|
||
for (const prompt of prompts) {
|
||
const result = await service.tryHandle(prompt);
|
||
const reply = String(result?.reply_text ?? "");
|
||
|
||
expect(result?.handled).toBe(true);
|
||
expect(result?.reply_type).toBe("partial_coverage");
|
||
expect(result?.debug.limited_reason_category).toBe("unsupported");
|
||
expect(reply).toContain("Что могу сделать сейчас:");
|
||
expect(reply).not.toMatch(/Сейчас этот тип вопроса вне поддерживаемого контура адресного режима/iu);
|
||
}
|
||
});
|
||
});
|