ARCH: добавить runtime authority смысла текущей реплики
This commit is contained in:
@@ -14,6 +14,15 @@ describe("addressIntentResolver regression bridges", () => {
|
||||
expect(result.intent).toBe("payables_confirmed_as_of_date");
|
||||
});
|
||||
|
||||
it("detects receivables snapshot wording through light current-turn typo noise", () => {
|
||||
const result = resolveAddressIntent(
|
||||
"\u043a\u0442\u043e \u043d\u0430\u043c\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043d\u0435\u0433 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f"
|
||||
);
|
||||
|
||||
expect(result.intent).toBe("receivables_confirmed_as_of_date");
|
||||
expect(result.reasons).toContain("current_turn_noise_normalized");
|
||||
});
|
||||
|
||||
it("detects top customer all-time revenue wording", () => {
|
||||
const result = resolveAddressIntent("кто у нас самый доходный клиент за все время");
|
||||
|
||||
|
||||
@@ -670,4 +670,34 @@ describe("assistantRoutePolicy", () => {
|
||||
expect(decision.toolGateDecision).toBe("run_address_lane");
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
});
|
||||
|
||||
it("recovers an address route from current-turn meaning when L0 resolver is noisy", () => {
|
||||
const policy = buildPolicy({
|
||||
resolveAddressToolGateDecision: undefined,
|
||||
resolveAssistantTurnMeaning: () => ({
|
||||
schema_version: "assistant_turn_meaning_v1",
|
||||
explicit_intent_candidate: "receivables_confirmed_as_of_date",
|
||||
meaning_confidence: "high",
|
||||
reason_codes: ["receivables_current_turn_meaning_signal"],
|
||||
stale_replay_forbidden: false
|
||||
})
|
||||
});
|
||||
|
||||
const decision = policy.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage:
|
||||
"\u043a\u0442\u043e \u043d\u0430\u043c\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043d\u0435\u0433 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f",
|
||||
effectiveAddressUserMessage:
|
||||
"\u043a\u0442\u043e \u043d\u0430\u043c\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043d\u0435\u0433 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f",
|
||||
followupContext: null,
|
||||
llmPreDecomposeMeta: null,
|
||||
useMock: false
|
||||
});
|
||||
|
||||
expect(decision.runAddressLane).toBe(true);
|
||||
expect(decision.livingMode).toBe("address_data");
|
||||
expect(decision.orchestrationContract?.address_intent).toBe("receivables_confirmed_as_of_date");
|
||||
expect(decision.orchestrationContract?.assistant_turn_meaning?.schema_version).toBe(
|
||||
"assistant_turn_meaning_v1"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -921,4 +921,48 @@ describe("assistantTransitionPolicy", () => {
|
||||
});
|
||||
expect(carryover?.followupContext?.previous_filters?.as_of_date).not.toBe("2021-04-15");
|
||||
});
|
||||
|
||||
it("drops carryover when current-turn meaning forbids stale replay", () => {
|
||||
const policy = buildPolicy({
|
||||
findLastAddressAssistantItem: () => ({
|
||||
text: "Documents by previous counterparty",
|
||||
debug: {
|
||||
execution_lane: "address_query",
|
||||
answer_grounding_check: { status: "grounded" },
|
||||
detected_intent: "list_documents_by_counterparty",
|
||||
extracted_filters: {
|
||||
counterparty: "Previous Counterparty",
|
||||
organization: "Org Alt"
|
||||
},
|
||||
anchor_type: "counterparty",
|
||||
anchor_value_resolved: "Previous Counterparty"
|
||||
}
|
||||
}),
|
||||
hasAddressFollowupContextSignal: () => true,
|
||||
resolveAssistantTurnMeaning: () => ({
|
||||
schema_version: "assistant_turn_meaning_v1",
|
||||
asked_domain_family: "counterparty",
|
||||
asked_action_family: "counterparty_value_or_turnover",
|
||||
unsupported_but_understood_family: "counterparty_value_or_turnover",
|
||||
explicit_entity_candidates: [
|
||||
{
|
||||
type: "counterparty",
|
||||
value: "svk",
|
||||
source: "current_turn_loose_entity_tail"
|
||||
}
|
||||
],
|
||||
stale_replay_forbidden: true
|
||||
})
|
||||
});
|
||||
|
||||
const carryover = policy.resolveAddressFollowupCarryoverContext(
|
||||
"\u043a\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0440\u043e\u0442 \u0431\u044b\u043b \u0441\u0432\u043a",
|
||||
[],
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
|
||||
expect(carryover).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createAssistantTurnMeaningPolicy } from "../src/services/assistantTurnMeaningPolicy";
|
||||
import { resolveAddressIntent } from "../src/services/addressIntentResolver";
|
||||
|
||||
function buildPolicy() {
|
||||
return createAssistantTurnMeaningPolicy({
|
||||
compactWhitespace: (value: string) => String(value ?? "").replace(/\s+/g, " ").trim(),
|
||||
repairAddressMojibake: (value: string) => value,
|
||||
resolveAddressIntent,
|
||||
toNonEmptyString: (value: unknown) => {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
const text = String(value).trim();
|
||||
return text.length > 0 ? text : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
describe("assistantTurnMeaningPolicy", () => {
|
||||
it("recovers a supported receivables intent from light current-turn typo noise", () => {
|
||||
const policy = buildPolicy();
|
||||
|
||||
const meaning = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage:
|
||||
"\u043a\u0442\u043e \u043d\u0430\u043c\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0434\u0435\u043d\u0435\u0433 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f"
|
||||
});
|
||||
|
||||
expect(meaning.schema_version).toBe("assistant_turn_meaning_v1");
|
||||
expect(meaning.explicit_intent_candidate).toBe("receivables_confirmed_as_of_date");
|
||||
expect(meaning.asked_domain_family).toBe("receivables");
|
||||
expect(meaning.carryover_budget).toBe("matching_family_only");
|
||||
expect(meaning.stale_replay_forbidden).toBe(false);
|
||||
});
|
||||
|
||||
it("marks unsupported counterparty turnover as understood and forbids stale replay", () => {
|
||||
const policy = buildPolicy();
|
||||
|
||||
const meaning = policy.resolveAssistantTurnMeaning({
|
||||
rawUserMessage:
|
||||
"\u043a\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0440\u043e\u0442 \u0431\u044b\u043b \u0441\u0432\u043a"
|
||||
});
|
||||
|
||||
expect(meaning.explicit_intent_candidate).toBeNull();
|
||||
expect(meaning.asked_domain_family).toBe("counterparty");
|
||||
expect(meaning.asked_action_family).toBe("counterparty_value_or_turnover");
|
||||
expect(meaning.unsupported_but_understood_family).toBe("counterparty_value_or_turnover");
|
||||
expect(meaning.stale_replay_forbidden).toBe(true);
|
||||
expect(meaning.explicit_entity_candidates).toEqual([
|
||||
{
|
||||
type: "counterparty",
|
||||
value: "\u0441\u0432\u043a",
|
||||
source: "current_turn_loose_entity_tail"
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user