АРЧ - Ассистент: отделить meta-followup по прошлому ответу от повторного запуска address lane
This commit is contained in:
@@ -50,6 +50,64 @@ export interface BuildAssistantAddressOrchestrationRuntimeOutput {
|
||||
};
|
||||
}
|
||||
|
||||
function hasSelectedObjectInventorySignal(text: string | null): boolean {
|
||||
return /(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(
|
||||
String(text ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
function hasSelectedObjectInventoryActionCue(text: string | null): boolean {
|
||||
return /(?:кому[\s\S]{0,80}продал[аи]?|кому[\s\S]{0,80}реализова[нлт][а-я]*|кому\s+был\s+продан|кто[\s\S]{0,40}купил|кто\s+это\s+поставил|кто\s+поставил|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+мы\s+купили|где\s+куплено|по\s+каким\s+документам|какими\s+документами|покажи\s+документы|документы\s+закупки|buyer|sale\s+trace|supplier|vendor|purchase\s+documents|purchase[\s-]?to[\s-]?sale|old\s+purchase|aged\s+stock)/iu.test(
|
||||
String(text ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
function isGenericCanonicalDriftIntent(intent: string | null): boolean {
|
||||
return (
|
||||
intent === "open_items_by_counterparty_or_contract" ||
|
||||
intent === "list_documents_by_counterparty" ||
|
||||
intent === "list_documents_by_contract" ||
|
||||
intent === "bank_operations_by_counterparty" ||
|
||||
intent === "bank_operations_by_contract" ||
|
||||
intent === "documents_forming_balance"
|
||||
);
|
||||
}
|
||||
|
||||
function shouldPreferRawFollowupMessage(
|
||||
userMessage: string,
|
||||
addressInputMessage: string,
|
||||
carryover: AssistantAddressCarryoverLike | null,
|
||||
addressPreDecompose: Record<string, unknown>,
|
||||
toNonEmptyString: BuildAssistantAddressOrchestrationRuntimeInput["toNonEmptyString"]
|
||||
): boolean {
|
||||
if (!carryover?.followupContext || typeof carryover.followupContext !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rawMessage = toNonEmptyString(userMessage);
|
||||
const canonicalMessage = toNonEmptyString(addressInputMessage);
|
||||
if (!rawMessage || !canonicalMessage || rawMessage === canonicalMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const predecomposeContract =
|
||||
addressPreDecompose?.predecomposeContract && typeof addressPreDecompose.predecomposeContract === "object"
|
||||
? (addressPreDecompose.predecomposeContract as Record<string, unknown>)
|
||||
: null;
|
||||
const mode = toNonEmptyString(predecomposeContract?.mode) ?? "unknown";
|
||||
const intent = toNonEmptyString(predecomposeContract?.intent) ?? "unknown";
|
||||
|
||||
if (mode === "unsupported" && intent === "unknown") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
hasSelectedObjectInventorySignal(rawMessage) &&
|
||||
hasSelectedObjectInventoryActionCue(rawMessage) &&
|
||||
isGenericCanonicalDriftIntent(intent)
|
||||
);
|
||||
}
|
||||
|
||||
function fallbackAddressPreDecompose(
|
||||
userMessage: string,
|
||||
llmProvider: unknown,
|
||||
@@ -80,7 +138,7 @@ function fallbackAddressPreDecompose(
|
||||
export async function buildAssistantAddressOrchestrationRuntime(
|
||||
input: BuildAssistantAddressOrchestrationRuntimeInput
|
||||
): Promise<BuildAssistantAddressOrchestrationRuntimeOutput> {
|
||||
const addressPreDecompose = input.featureAddressLlmPredecomposeV1
|
||||
const initialAddressPreDecompose = input.featureAddressLlmPredecomposeV1
|
||||
? await input.runAddressLlmPreDecompose()
|
||||
: fallbackAddressPreDecompose(
|
||||
input.userMessage,
|
||||
@@ -89,14 +147,43 @@ export async function buildAssistantAddressOrchestrationRuntime(
|
||||
input.sanitizeAddressMessageForFallback
|
||||
);
|
||||
|
||||
const addressInputMessage =
|
||||
let addressPreDecompose = initialAddressPreDecompose;
|
||||
let addressInputMessage =
|
||||
input.toNonEmptyString(addressPreDecompose?.effectiveMessage) ?? input.userMessage;
|
||||
const carryover = input.resolveAddressFollowupCarryoverContext(
|
||||
let carryover = input.resolveAddressFollowupCarryoverContext(
|
||||
input.userMessage,
|
||||
input.sessionItems,
|
||||
addressInputMessage,
|
||||
addressPreDecompose
|
||||
);
|
||||
if (
|
||||
shouldPreferRawFollowupMessage(
|
||||
input.userMessage,
|
||||
addressInputMessage,
|
||||
carryover,
|
||||
addressPreDecompose,
|
||||
input.toNonEmptyString
|
||||
)
|
||||
) {
|
||||
addressInputMessage = input.userMessage;
|
||||
addressPreDecompose = {
|
||||
...addressPreDecompose,
|
||||
applied: false,
|
||||
effectiveMessage: input.userMessage,
|
||||
reason: "followup_raw_message_preferred_over_llm_rewrite",
|
||||
predecomposeContract: input.buildAddressLlmPredecomposeContractV1({
|
||||
sourceMessage: input.userMessage,
|
||||
canonicalMessage: input.userMessage
|
||||
})
|
||||
};
|
||||
carryover = input.resolveAddressFollowupCarryoverContext(
|
||||
input.userMessage,
|
||||
input.sessionItems,
|
||||
addressInputMessage,
|
||||
addressPreDecompose
|
||||
);
|
||||
}
|
||||
|
||||
const followupContext = carryover?.followupContext ?? null;
|
||||
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: input.userMessage,
|
||||
|
||||
Reference in New Issue
Block a user