ГЛОБАЛЬНЫЙ РЕФАКТОРИНГ АРХИТЕКТУРЫ - Рефакторинг этапов 2.46: склейка всего address-потока в отдельный assistantAddressAttemptRuntimeAdapter, для того чтобы из handleMessage убрать три локальных closure целиком. Все три моста (lane, response, living chat) прокидываются и не ломают контракт.
This commit is contained in:
parent
5790e25b68
commit
5f4e898c7c
|
|
@ -1437,7 +1437,38 @@ Validation:
|
||||||
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
||||||
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
||||||
|
|
||||||
Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 + 2.45 completed)**
|
Implemented in current pass (Phase 2.46):
|
||||||
|
1. Activated full address-turn attempt runtime boundary inside `assistantService`:
|
||||||
|
- rewired address handling call-site to `runAssistantAddressAttemptRuntime(...)`;
|
||||||
|
- removed local inline closures for lane-attempt, lane-response, and living-chat handoff wiring from `handleMessage`.
|
||||||
|
2. Finalized and type-hardened address attempt adapter contract:
|
||||||
|
- `assistantAddressAttemptRuntimeAdapter.ts`
|
||||||
|
- aligned `logEvent` and `messageIdFactory` contract typing to runtime expectations.
|
||||||
|
3. Added focused unit tests:
|
||||||
|
- `assistantAddressAttemptRuntimeAdapter.test.ts`
|
||||||
|
|
||||||
|
Validation:
|
||||||
|
1. `npm run build` passed.
|
||||||
|
2. Targeted living/address/deep followup pack passed:
|
||||||
|
- `assistantAddressAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnResponseAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnAnalysisRuntimeAdapter.test.ts`
|
||||||
|
- `assistantAddressLaneResponseAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantLivingChatAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantAddressLaneAttemptRuntimeAdapter.test.ts`
|
||||||
|
- `assistantUserTurnBootstrapRuntimeAdapter.test.ts`
|
||||||
|
- `assistantLivingChatLlmRuntimeAdapter.test.ts`
|
||||||
|
- `assistantLivingChatHandlerRuntimeAdapter.test.ts`
|
||||||
|
- `assistantLivingChatRuntimeAdapter.test.ts`
|
||||||
|
- `assistantAddressRuntimeAdapter.test.ts`
|
||||||
|
- `assistantAddressLaneResponseRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnResponseRuntimeAdapter.test.ts`
|
||||||
|
- `assistantDeepTurnPackagingRuntimeAdapter.test.ts`
|
||||||
|
- `assistantWave10SettlementCorrectiveRegression.test.ts`
|
||||||
|
|
||||||
|
Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 + 2.45 + 2.46 completed)**
|
||||||
|
|
||||||
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards)
|
||||||
|
|
||||||
|
|
|
||||||
117
llm_normalizer/backend/dist/services/assistantAddressAttemptRuntimeAdapter.js
vendored
Normal file
117
llm_normalizer/backend/dist/services/assistantAddressAttemptRuntimeAdapter.js
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.runAssistantAddressAttemptRuntime = runAssistantAddressAttemptRuntime;
|
||||||
|
const assistantAddressRuntimeAdapter_1 = require("./assistantAddressRuntimeAdapter");
|
||||||
|
const assistantAddressLaneAttemptRuntimeAdapter_1 = require("./assistantAddressLaneAttemptRuntimeAdapter");
|
||||||
|
const assistantAddressLaneResponseAttemptRuntimeAdapter_1 = require("./assistantAddressLaneResponseAttemptRuntimeAdapter");
|
||||||
|
const assistantLivingChatAttemptRuntimeAdapter_1 = require("./assistantLivingChatAttemptRuntimeAdapter");
|
||||||
|
async function runAssistantAddressAttemptRuntime(input) {
|
||||||
|
const runAddressRuntimeSafe = input.runAddressRuntime ?? assistantAddressRuntimeAdapter_1.runAssistantAddressRuntime;
|
||||||
|
const runAddressLaneAttemptRuntimeSafe = input.runAddressLaneAttemptRuntime ?? assistantAddressLaneAttemptRuntimeAdapter_1.runAssistantAddressLaneAttemptRuntime;
|
||||||
|
const runAddressLaneResponseAttemptRuntimeSafe = input.runAddressLaneResponseAttemptRuntime ?? assistantAddressLaneResponseAttemptRuntimeAdapter_1.runAssistantAddressLaneResponseAttemptRuntime;
|
||||||
|
const runLivingChatAttemptRuntimeSafe = input.runLivingChatAttemptRuntime ?? assistantLivingChatAttemptRuntimeAdapter_1.runAssistantLivingChatAttemptRuntime;
|
||||||
|
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => runAddressLaneResponseAttemptRuntimeSafe({
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
effectiveAddressUserMessage,
|
||||||
|
addressLane,
|
||||||
|
carryoverMeta,
|
||||||
|
llmPreDecomposeMeta,
|
||||||
|
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization,
|
||||||
|
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||||
|
buildAddressDebugPayload: input.buildAddressDebugPayload,
|
||||||
|
buildAddressFollowupOffer: input.buildAddressFollowupOffer,
|
||||||
|
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
appendItem: input.appendItem,
|
||||||
|
getSession: input.getSession,
|
||||||
|
persistSession: input.persistSession,
|
||||||
|
cloneConversation: input.cloneConversation,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
messageIdFactory: input.messageIdFactory
|
||||||
|
});
|
||||||
|
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => runLivingChatAttemptRuntimeSafe({
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
sessionItems: input.sessionItems,
|
||||||
|
modeDecision,
|
||||||
|
sessionScope: {
|
||||||
|
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||||
|
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization
|
||||||
|
},
|
||||||
|
addressRuntimeMeta,
|
||||||
|
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
mergeKnownOrganizations: input.mergeKnownOrganizations,
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||||
|
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||||
|
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||||
|
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||||
|
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||||
|
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||||
|
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||||
|
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||||
|
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||||
|
applyScriptGuard: input.applyScriptGuard,
|
||||||
|
applyGroundingGuard: input.applyGroundingGuard,
|
||||||
|
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||||
|
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||||
|
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||||
|
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||||
|
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||||
|
appendItem: input.appendItem,
|
||||||
|
getSession: input.getSession,
|
||||||
|
persistSession: input.persistSession,
|
||||||
|
cloneConversation: input.cloneConversation,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
messageIdFactory: input.messageIdFactory,
|
||||||
|
nowIso: input.nowIso,
|
||||||
|
payload: input.payload,
|
||||||
|
chatClient: input.chatClient,
|
||||||
|
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||||
|
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: input.defaultModel,
|
||||||
|
defaultBaseUrl: input.defaultBaseUrl,
|
||||||
|
defaultApiKey: input.defaultApiKey
|
||||||
|
});
|
||||||
|
const runAddressLaneAttempt = async (messageUsed, carryMeta, analysisDateHint) => runAddressLaneAttemptRuntimeSafe({
|
||||||
|
messageUsed,
|
||||||
|
carryMeta,
|
||||||
|
analysisDateHint,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization,
|
||||||
|
mergeFollowupContextWithOrganizationScope: input.mergeFollowupContextWithOrganizationScope,
|
||||||
|
runAddressQueryTryHandle: input.runAddressQueryTryHandle
|
||||||
|
});
|
||||||
|
return runAddressRuntimeSafe({
|
||||||
|
featureAssistantAddressQueryV1: input.featureAssistantAddressQueryV1,
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
sessionItems: input.sessionItems,
|
||||||
|
llmProvider: input.payload.llmProvider,
|
||||||
|
useMock: Boolean(input.payload.useMock),
|
||||||
|
featureAddressLlmPredecomposeV1: input.featureAddressLlmPredecomposeV1,
|
||||||
|
runAddressLlmPreDecompose: input.runAddressLlmPreDecompose,
|
||||||
|
buildAddressLlmPredecomposeContractV1: input.buildAddressLlmPredecomposeContractV1,
|
||||||
|
sanitizeAddressMessageForFallback: input.sanitizeAddressMessageForFallback,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
resolveAddressFollowupCarryoverContext: input.resolveAddressFollowupCarryoverContext,
|
||||||
|
resolveAssistantOrchestrationDecision: input.resolveAssistantOrchestrationDecision,
|
||||||
|
buildAddressDialogContinuationContractV2: input.buildAddressDialogContinuationContractV2,
|
||||||
|
runtimeAnalysisContextAsOfDate: input.runtimeAnalysisContextAsOfDate,
|
||||||
|
payloadContextPeriodHint: input.payload?.context?.period_hint,
|
||||||
|
compactWhitespace: input.compactWhitespace,
|
||||||
|
runAddressLaneAttempt,
|
||||||
|
isRetryableAddressLimitedResult: input.isRetryableAddressLimitedResult,
|
||||||
|
finalizeAddressLaneResponse,
|
||||||
|
tryHandleLivingChat,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
nowIso: input.nowIso,
|
||||||
|
runAddressOrchestrationRuntime: input.runAddressOrchestrationRuntime,
|
||||||
|
runAddressToolGateRuntime: input.runAddressToolGateRuntime,
|
||||||
|
runAddressLaneRuntime: input.runAddressLaneRuntime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -62,12 +62,9 @@ const openaiResponsesClient_1 = __importStar(require("./openaiResponsesClient"))
|
||||||
const addressMcpClient_1 = __importStar(require("./addressMcpClient"));
|
const addressMcpClient_1 = __importStar(require("./addressMcpClient"));
|
||||||
const capabilitiesRegistry_1 = __importStar(require("./capabilitiesRegistry"));
|
const capabilitiesRegistry_1 = __importStar(require("./capabilitiesRegistry"));
|
||||||
const assistantCanon_1 = __importStar(require("./assistantCanon"));
|
const assistantCanon_1 = __importStar(require("./assistantCanon"));
|
||||||
const assistantAddressLaneResponseAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneResponseAttemptRuntimeAdapter"));
|
const assistantAddressAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressAttemptRuntimeAdapter"));
|
||||||
const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
|
const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding"));
|
||||||
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
|
const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter"));
|
||||||
const assistantAddressRuntimeAdapter_1 = __importStar(require("./assistantAddressRuntimeAdapter"));
|
|
||||||
const assistantAddressLaneAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressLaneAttemptRuntimeAdapter"));
|
|
||||||
const assistantLivingChatAttemptRuntimeAdapter_1 = __importStar(require("./assistantLivingChatAttemptRuntimeAdapter"));
|
|
||||||
const assistantUserTurnBootstrapRuntimeAdapter_1 = __importStar(require("./assistantUserTurnBootstrapRuntimeAdapter"));
|
const assistantUserTurnBootstrapRuntimeAdapter_1 = __importStar(require("./assistantUserTurnBootstrapRuntimeAdapter"));
|
||||||
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
|
const assistantQueryPlanning_1 = __importStar(require("./assistantQueryPlanning"));
|
||||||
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
const iconv_lite_1 = __importDefault(require("iconv-lite"));
|
||||||
|
|
@ -4385,40 +4382,30 @@ class AssistantService {
|
||||||
nowIso: () => new Date().toISOString()
|
nowIso: () => new Date().toISOString()
|
||||||
});
|
});
|
||||||
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
||||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => (0, assistantAddressLaneResponseAttemptRuntimeAdapter_1.runAssistantAddressLaneResponseAttemptRuntime)({
|
const addressRuntime = await (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)({
|
||||||
sessionId,
|
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||||
userMessage,
|
|
||||||
effectiveAddressUserMessage,
|
|
||||||
addressLane,
|
|
||||||
carryoverMeta,
|
|
||||||
llmPreDecomposeMeta,
|
|
||||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
buildAddressDebugPayload,
|
|
||||||
buildAddressFollowupOffer,
|
|
||||||
mergeKnownOrganizations,
|
|
||||||
toNonEmptyString,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`
|
|
||||||
});
|
|
||||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => (0, assistantLivingChatAttemptRuntimeAdapter_1.runAssistantLivingChatAttemptRuntime)({
|
|
||||||
sessionId,
|
sessionId,
|
||||||
userMessage,
|
userMessage,
|
||||||
sessionItems: session.items,
|
sessionItems: session.items,
|
||||||
modeDecision,
|
payload,
|
||||||
sessionScope: {
|
sessionScope: {
|
||||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
||||||
selectedOrganization: sessionOrganizationScope.selectedOrganization,
|
selectedOrganization: sessionOrganizationScope.selectedOrganization,
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization
|
activeOrganization: sessionOrganizationScope.activeOrganization
|
||||||
},
|
},
|
||||||
addressRuntimeMeta,
|
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||||
traceIdFactory: () => `chat-${(0, nanoid_1.nanoid)(10)}`,
|
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, payload, userMessage),
|
||||||
|
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||||
|
sanitizeAddressMessageForFallback,
|
||||||
toNonEmptyString,
|
toNonEmptyString,
|
||||||
|
resolveAddressFollowupCarryoverContext,
|
||||||
|
resolveAssistantOrchestrationDecision,
|
||||||
|
buildAddressDialogContinuationContractV2,
|
||||||
|
runtimeAnalysisContextAsOfDate: runtimeAnalysisContext.as_of_date,
|
||||||
|
compactWhitespace,
|
||||||
|
mergeFollowupContextWithOrganizationScope,
|
||||||
|
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
||||||
|
isRetryableAddressLimitedResult,
|
||||||
mergeKnownOrganizations,
|
mergeKnownOrganizations,
|
||||||
hasAssistantDataScopeMetaQuestionSignal,
|
hasAssistantDataScopeMetaQuestionSignal,
|
||||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||||
|
|
@ -4438,56 +4425,23 @@ class AssistantService {
|
||||||
buildAssistantDataScopeSelectionReply,
|
buildAssistantDataScopeSelectionReply,
|
||||||
buildAssistantOperationalBoundaryReply,
|
buildAssistantOperationalBoundaryReply,
|
||||||
buildAssistantCapabilityContractReply,
|
buildAssistantCapabilityContractReply,
|
||||||
|
chatClient: this.chatClient,
|
||||||
|
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||||
|
sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: config_1.DEFAULT_MODEL,
|
||||||
|
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
||||||
|
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||||
|
buildAddressDebugPayload,
|
||||||
|
buildAddressFollowupOffer,
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
||||||
cloneConversation: (items) => cloneItems(items),
|
cloneConversation: (items) => cloneItems(items),
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
logEvent: (payload) => (0, log_1.logJson)(payload),
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||||
nowIso: () => new Date().toISOString(),
|
|
||||||
payload,
|
|
||||||
chatClient: this.chatClient,
|
|
||||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? ""
|
|
||||||
});
|
|
||||||
let addressRuntimeMetaForDeep = null;
|
|
||||||
const runAddressLaneAttempt = async (messageUsed, carryMeta, analysisDateHint) => (0, assistantAddressLaneAttemptRuntimeAdapter_1.runAssistantAddressLaneAttemptRuntime)({
|
|
||||||
messageUsed,
|
|
||||||
carryMeta: carryMeta ?? null,
|
|
||||||
analysisDateHint: analysisDateHint ?? null,
|
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
|
||||||
mergeFollowupContextWithOrganizationScope,
|
|
||||||
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options)
|
|
||||||
});
|
|
||||||
const addressRuntime = await (0, assistantAddressRuntimeAdapter_1.runAssistantAddressRuntime)({
|
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
|
||||||
sessionId,
|
|
||||||
userMessage,
|
|
||||||
sessionItems: session.items,
|
|
||||||
llmProvider: payload?.llmProvider,
|
|
||||||
useMock: Boolean(payload.useMock),
|
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
|
||||||
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, payload, userMessage),
|
|
||||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
|
||||||
sanitizeAddressMessageForFallback,
|
|
||||||
toNonEmptyString,
|
|
||||||
resolveAddressFollowupCarryoverContext,
|
|
||||||
resolveAssistantOrchestrationDecision,
|
|
||||||
buildAddressDialogContinuationContractV2,
|
|
||||||
runtimeAnalysisContextAsOfDate: runtimeAnalysisContext.as_of_date,
|
|
||||||
payloadContextPeriodHint: payload?.context?.period_hint,
|
|
||||||
compactWhitespace,
|
|
||||||
runAddressLaneAttempt,
|
|
||||||
isRetryableAddressLimitedResult,
|
|
||||||
finalizeAddressLaneResponse,
|
|
||||||
tryHandleLivingChat: (modeDecision, runtimeMeta) => tryHandleLivingChat(modeDecision, runtimeMeta),
|
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
|
||||||
nowIso: () => new Date().toISOString()
|
nowIso: () => new Date().toISOString()
|
||||||
});
|
});
|
||||||
addressRuntimeMetaForDeep = addressRuntime.addressRuntimeMetaForDeep;
|
const addressRuntimeMetaForDeep = addressRuntime.addressRuntimeMetaForDeep;
|
||||||
if (addressRuntime.handled && addressRuntime.response) {
|
if (addressRuntime.handled && addressRuntime.response) {
|
||||||
return addressRuntime.response;
|
return addressRuntime.response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
import {
|
||||||
|
runAssistantAddressRuntime,
|
||||||
|
type RunAssistantAddressRuntimeInput,
|
||||||
|
type RunAssistantAddressRuntimeOutput
|
||||||
|
} from "./assistantAddressRuntimeAdapter";
|
||||||
|
import {
|
||||||
|
runAssistantAddressLaneAttemptRuntime,
|
||||||
|
type RunAssistantAddressLaneAttemptRuntimeInput
|
||||||
|
} from "./assistantAddressLaneAttemptRuntimeAdapter";
|
||||||
|
import {
|
||||||
|
runAssistantAddressLaneResponseAttemptRuntime,
|
||||||
|
type RunAssistantAddressLaneResponseAttemptRuntimeInput
|
||||||
|
} from "./assistantAddressLaneResponseAttemptRuntimeAdapter";
|
||||||
|
import {
|
||||||
|
runAssistantLivingChatAttemptRuntime,
|
||||||
|
type RunAssistantLivingChatAttemptRuntimeInput
|
||||||
|
} from "./assistantLivingChatAttemptRuntimeAdapter";
|
||||||
|
|
||||||
|
interface AddressAttemptPayload {
|
||||||
|
llmProvider?: unknown;
|
||||||
|
useMock?: unknown;
|
||||||
|
context?: {
|
||||||
|
period_hint?: unknown;
|
||||||
|
} | null;
|
||||||
|
apiKey?: unknown;
|
||||||
|
model?: unknown;
|
||||||
|
baseUrl?: unknown;
|
||||||
|
temperature?: number;
|
||||||
|
maxOutputTokens?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddressSessionScope {
|
||||||
|
knownOrganizations: string[];
|
||||||
|
selectedOrganization: string | null;
|
||||||
|
activeOrganization: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RunAssistantAddressAttemptRuntimeInput<ResponseType = unknown>
|
||||||
|
extends Omit<
|
||||||
|
RunAssistantAddressRuntimeInput<ResponseType>,
|
||||||
|
"llmProvider" | "useMock" | "payloadContextPeriodHint" | "runAddressLaneAttempt" | "finalizeAddressLaneResponse" | "tryHandleLivingChat"
|
||||||
|
> {
|
||||||
|
payload: AddressAttemptPayload;
|
||||||
|
sessionScope: AddressSessionScope;
|
||||||
|
mergeFollowupContextWithOrganizationScope: RunAssistantAddressLaneAttemptRuntimeInput["mergeFollowupContextWithOrganizationScope"];
|
||||||
|
runAddressQueryTryHandle: RunAssistantAddressLaneAttemptRuntimeInput["runAddressQueryTryHandle"];
|
||||||
|
mergeKnownOrganizations: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["mergeKnownOrganizations"];
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasAssistantDataScopeMetaQuestionSignal"];
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["shouldHandleAsAssistantCapabilityMetaQuery"];
|
||||||
|
hasDestructiveDataActionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasDestructiveDataActionSignal"];
|
||||||
|
hasDangerOrCoercionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasDangerOrCoercionSignal"];
|
||||||
|
hasOperationalAdminActionRequestSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOperationalAdminActionRequestSignal"];
|
||||||
|
hasOrganizationFactLookupSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOrganizationFactLookupSignal"];
|
||||||
|
hasOrganizationFactFollowupSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasOrganizationFactFollowupSignal"];
|
||||||
|
shouldEmitOrganizationSelectionReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["shouldEmitOrganizationSelectionReply"];
|
||||||
|
hasAssistantCapabilityQuestionSignal: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["hasAssistantCapabilityQuestionSignal"];
|
||||||
|
resolveDataScopeProbe: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["resolveDataScopeProbe"];
|
||||||
|
applyScriptGuard: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["applyScriptGuard"];
|
||||||
|
applyGroundingGuard: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["applyGroundingGuard"];
|
||||||
|
buildAssistantSafetyRefusalReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantSafetyRefusalReply"];
|
||||||
|
buildAssistantDataScopeContractReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantDataScopeContractReply"];
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantOrganizationFactBoundaryReply"];
|
||||||
|
buildAssistantDataScopeSelectionReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantDataScopeSelectionReply"];
|
||||||
|
buildAssistantOperationalBoundaryReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantOperationalBoundaryReply"];
|
||||||
|
buildAssistantCapabilityContractReply: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["buildAssistantCapabilityContractReply"];
|
||||||
|
chatClient: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["chatClient"];
|
||||||
|
loadAssistantCanonExcerpt: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["loadAssistantCanonExcerpt"];
|
||||||
|
sanitizeOutgoingAssistantText: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["sanitizeOutgoingAssistantText"];
|
||||||
|
defaultModel: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultModel"];
|
||||||
|
defaultBaseUrl: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultBaseUrl"];
|
||||||
|
defaultApiKey?: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>["defaultApiKey"];
|
||||||
|
buildAddressDebugPayload: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["buildAddressDebugPayload"];
|
||||||
|
buildAddressFollowupOffer: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["buildAddressFollowupOffer"];
|
||||||
|
appendItem: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["appendItem"];
|
||||||
|
getSession: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["getSession"];
|
||||||
|
persistSession: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["persistSession"];
|
||||||
|
cloneConversation: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["cloneConversation"];
|
||||||
|
logEvent: RunAssistantAddressRuntimeInput<ResponseType>["logEvent"];
|
||||||
|
messageIdFactory: NonNullable<
|
||||||
|
RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>["messageIdFactory"]
|
||||||
|
>;
|
||||||
|
runAddressRuntime?: (
|
||||||
|
input: RunAssistantAddressRuntimeInput<ResponseType>
|
||||||
|
) => Promise<RunAssistantAddressRuntimeOutput<ResponseType>>;
|
||||||
|
runAddressLaneAttemptRuntime?: (
|
||||||
|
input: RunAssistantAddressLaneAttemptRuntimeInput
|
||||||
|
) => Promise<Awaited<ReturnType<RunAssistantAddressLaneAttemptRuntimeInput["runAddressQueryTryHandle"]>>>;
|
||||||
|
runAddressLaneResponseAttemptRuntime?: (
|
||||||
|
input: RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>
|
||||||
|
) => ResponseType;
|
||||||
|
runLivingChatAttemptRuntime?: (
|
||||||
|
input: RunAssistantLivingChatAttemptRuntimeInput<ResponseType>
|
||||||
|
) => Promise<ResponseType | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runAssistantAddressAttemptRuntime<ResponseType = unknown>(
|
||||||
|
input: RunAssistantAddressAttemptRuntimeInput<ResponseType>
|
||||||
|
): Promise<RunAssistantAddressRuntimeOutput<ResponseType>> {
|
||||||
|
const runAddressRuntimeSafe = input.runAddressRuntime ?? runAssistantAddressRuntime;
|
||||||
|
const runAddressLaneAttemptRuntimeSafe = input.runAddressLaneAttemptRuntime ?? runAssistantAddressLaneAttemptRuntime;
|
||||||
|
const runAddressLaneResponseAttemptRuntimeSafe =
|
||||||
|
input.runAddressLaneResponseAttemptRuntime ?? runAssistantAddressLaneResponseAttemptRuntime;
|
||||||
|
const runLivingChatAttemptRuntimeSafe =
|
||||||
|
input.runLivingChatAttemptRuntime ?? runAssistantLivingChatAttemptRuntime;
|
||||||
|
|
||||||
|
const finalizeAddressLaneResponse: RunAssistantAddressRuntimeInput<ResponseType>["finalizeAddressLaneResponse"] = (
|
||||||
|
addressLane,
|
||||||
|
effectiveAddressUserMessage,
|
||||||
|
carryoverMeta = null,
|
||||||
|
llmPreDecomposeMeta = null
|
||||||
|
) =>
|
||||||
|
runAddressLaneResponseAttemptRuntimeSafe({
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
effectiveAddressUserMessage,
|
||||||
|
addressLane,
|
||||||
|
carryoverMeta,
|
||||||
|
llmPreDecomposeMeta,
|
||||||
|
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization,
|
||||||
|
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||||
|
buildAddressDebugPayload: input.buildAddressDebugPayload,
|
||||||
|
buildAddressFollowupOffer: input.buildAddressFollowupOffer,
|
||||||
|
mergeKnownOrganizations: input.mergeKnownOrganizations as any,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
appendItem: input.appendItem,
|
||||||
|
getSession: input.getSession,
|
||||||
|
persistSession: input.persistSession,
|
||||||
|
cloneConversation: input.cloneConversation,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
messageIdFactory: input.messageIdFactory
|
||||||
|
} as RunAssistantAddressLaneResponseAttemptRuntimeInput<ResponseType>);
|
||||||
|
|
||||||
|
const tryHandleLivingChat: RunAssistantAddressRuntimeInput<ResponseType>["tryHandleLivingChat"] = async (
|
||||||
|
modeDecision,
|
||||||
|
addressRuntimeMeta = null
|
||||||
|
) =>
|
||||||
|
runLivingChatAttemptRuntimeSafe({
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
sessionItems: input.sessionItems,
|
||||||
|
modeDecision,
|
||||||
|
sessionScope: {
|
||||||
|
knownOrganizations: input.sessionScope.knownOrganizations,
|
||||||
|
selectedOrganization: input.sessionScope.selectedOrganization,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization
|
||||||
|
},
|
||||||
|
addressRuntimeMeta,
|
||||||
|
traceIdFactory: () => `chat-${input.messageIdFactory().replace(/^msg-/, "")}`,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
mergeKnownOrganizations: input.mergeKnownOrganizations as any,
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: input.hasAssistantDataScopeMetaQuestionSignal,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: input.shouldHandleAsAssistantCapabilityMetaQuery,
|
||||||
|
hasDestructiveDataActionSignal: input.hasDestructiveDataActionSignal,
|
||||||
|
hasDangerOrCoercionSignal: input.hasDangerOrCoercionSignal,
|
||||||
|
hasOperationalAdminActionRequestSignal: input.hasOperationalAdminActionRequestSignal,
|
||||||
|
hasOrganizationFactLookupSignal: input.hasOrganizationFactLookupSignal,
|
||||||
|
hasOrganizationFactFollowupSignal: input.hasOrganizationFactFollowupSignal,
|
||||||
|
shouldEmitOrganizationSelectionReply: input.shouldEmitOrganizationSelectionReply,
|
||||||
|
hasAssistantCapabilityQuestionSignal: input.hasAssistantCapabilityQuestionSignal,
|
||||||
|
resolveDataScopeProbe: input.resolveDataScopeProbe,
|
||||||
|
applyScriptGuard: input.applyScriptGuard,
|
||||||
|
applyGroundingGuard: input.applyGroundingGuard,
|
||||||
|
buildAssistantSafetyRefusalReply: input.buildAssistantSafetyRefusalReply,
|
||||||
|
buildAssistantDataScopeContractReply: input.buildAssistantDataScopeContractReply,
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: input.buildAssistantOrganizationFactBoundaryReply,
|
||||||
|
buildAssistantDataScopeSelectionReply: input.buildAssistantDataScopeSelectionReply,
|
||||||
|
buildAssistantOperationalBoundaryReply: input.buildAssistantOperationalBoundaryReply,
|
||||||
|
buildAssistantCapabilityContractReply: input.buildAssistantCapabilityContractReply,
|
||||||
|
appendItem: input.appendItem,
|
||||||
|
getSession: input.getSession,
|
||||||
|
persistSession: input.persistSession,
|
||||||
|
cloneConversation: input.cloneConversation,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
messageIdFactory: input.messageIdFactory,
|
||||||
|
nowIso: input.nowIso,
|
||||||
|
payload: input.payload,
|
||||||
|
chatClient: input.chatClient,
|
||||||
|
loadAssistantCanonExcerpt: input.loadAssistantCanonExcerpt,
|
||||||
|
sanitizeOutgoingAssistantText: input.sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: input.defaultModel,
|
||||||
|
defaultBaseUrl: input.defaultBaseUrl,
|
||||||
|
defaultApiKey: input.defaultApiKey
|
||||||
|
} as RunAssistantLivingChatAttemptRuntimeInput<ResponseType>);
|
||||||
|
|
||||||
|
const runAddressLaneAttempt: RunAssistantAddressRuntimeInput<ResponseType>["runAddressLaneAttempt"] = async (
|
||||||
|
messageUsed,
|
||||||
|
carryMeta,
|
||||||
|
analysisDateHint
|
||||||
|
) =>
|
||||||
|
runAddressLaneAttemptRuntimeSafe({
|
||||||
|
messageUsed,
|
||||||
|
carryMeta,
|
||||||
|
analysisDateHint,
|
||||||
|
activeOrganization: input.sessionScope.activeOrganization,
|
||||||
|
mergeFollowupContextWithOrganizationScope: input.mergeFollowupContextWithOrganizationScope,
|
||||||
|
runAddressQueryTryHandle: input.runAddressQueryTryHandle
|
||||||
|
});
|
||||||
|
|
||||||
|
return runAddressRuntimeSafe({
|
||||||
|
featureAssistantAddressQueryV1: input.featureAssistantAddressQueryV1,
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
userMessage: input.userMessage,
|
||||||
|
sessionItems: input.sessionItems,
|
||||||
|
llmProvider: input.payload.llmProvider,
|
||||||
|
useMock: Boolean(input.payload.useMock),
|
||||||
|
featureAddressLlmPredecomposeV1: input.featureAddressLlmPredecomposeV1,
|
||||||
|
runAddressLlmPreDecompose: input.runAddressLlmPreDecompose,
|
||||||
|
buildAddressLlmPredecomposeContractV1: input.buildAddressLlmPredecomposeContractV1,
|
||||||
|
sanitizeAddressMessageForFallback: input.sanitizeAddressMessageForFallback,
|
||||||
|
toNonEmptyString: input.toNonEmptyString,
|
||||||
|
resolveAddressFollowupCarryoverContext: input.resolveAddressFollowupCarryoverContext,
|
||||||
|
resolveAssistantOrchestrationDecision: input.resolveAssistantOrchestrationDecision,
|
||||||
|
buildAddressDialogContinuationContractV2: input.buildAddressDialogContinuationContractV2,
|
||||||
|
runtimeAnalysisContextAsOfDate: input.runtimeAnalysisContextAsOfDate,
|
||||||
|
payloadContextPeriodHint: input.payload?.context?.period_hint,
|
||||||
|
compactWhitespace: input.compactWhitespace,
|
||||||
|
runAddressLaneAttempt,
|
||||||
|
isRetryableAddressLimitedResult: input.isRetryableAddressLimitedResult,
|
||||||
|
finalizeAddressLaneResponse,
|
||||||
|
tryHandleLivingChat,
|
||||||
|
logEvent: input.logEvent,
|
||||||
|
nowIso: input.nowIso,
|
||||||
|
runAddressOrchestrationRuntime: input.runAddressOrchestrationRuntime,
|
||||||
|
runAddressToolGateRuntime: input.runAddressToolGateRuntime,
|
||||||
|
runAddressLaneRuntime: input.runAddressLaneRuntime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -16,12 +16,9 @@ import * as openaiResponsesClient_1 from "./openaiResponsesClient";
|
||||||
import * as addressMcpClient_1 from "./addressMcpClient";
|
import * as addressMcpClient_1 from "./addressMcpClient";
|
||||||
import * as capabilitiesRegistry_1 from "./capabilitiesRegistry";
|
import * as capabilitiesRegistry_1 from "./capabilitiesRegistry";
|
||||||
import * as assistantCanon_1 from "./assistantCanon";
|
import * as assistantCanon_1 from "./assistantCanon";
|
||||||
import * as assistantAddressLaneResponseAttemptRuntimeAdapter_1 from "./assistantAddressLaneResponseAttemptRuntimeAdapter";
|
import * as assistantAddressAttemptRuntimeAdapter_1 from "./assistantAddressAttemptRuntimeAdapter";
|
||||||
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding";
|
||||||
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
|
import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter";
|
||||||
import * as assistantAddressRuntimeAdapter_1 from "./assistantAddressRuntimeAdapter";
|
|
||||||
import * as assistantAddressLaneAttemptRuntimeAdapter_1 from "./assistantAddressLaneAttemptRuntimeAdapter";
|
|
||||||
import * as assistantLivingChatAttemptRuntimeAdapter_1 from "./assistantLivingChatAttemptRuntimeAdapter";
|
|
||||||
import * as assistantUserTurnBootstrapRuntimeAdapter_1 from "./assistantUserTurnBootstrapRuntimeAdapter";
|
import * as assistantUserTurnBootstrapRuntimeAdapter_1 from "./assistantUserTurnBootstrapRuntimeAdapter";
|
||||||
import * as assistantQueryPlanning_1 from "./assistantQueryPlanning";
|
import * as assistantQueryPlanning_1 from "./assistantQueryPlanning";
|
||||||
import iconv from "iconv-lite";
|
import iconv from "iconv-lite";
|
||||||
|
|
@ -4340,40 +4337,30 @@ export class AssistantService {
|
||||||
nowIso: () => new Date().toISOString()
|
nowIso: () => new Date().toISOString()
|
||||||
});
|
});
|
||||||
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
const sessionOrganizationScope = resolveSessionOrganizationScopeContext(userMessage, session.items);
|
||||||
const finalizeAddressLaneResponse = (addressLane, effectiveAddressUserMessage, carryoverMeta = null, llmPreDecomposeMeta = null) => (0, assistantAddressLaneResponseAttemptRuntimeAdapter_1.runAssistantAddressLaneResponseAttemptRuntime)({
|
const addressRuntime = await (0, assistantAddressAttemptRuntimeAdapter_1.runAssistantAddressAttemptRuntime)({
|
||||||
sessionId,
|
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
||||||
userMessage,
|
|
||||||
effectiveAddressUserMessage,
|
|
||||||
addressLane,
|
|
||||||
carryoverMeta,
|
|
||||||
llmPreDecomposeMeta,
|
|
||||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
buildAddressDebugPayload,
|
|
||||||
buildAddressFollowupOffer,
|
|
||||||
mergeKnownOrganizations,
|
|
||||||
toNonEmptyString,
|
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
|
||||||
cloneConversation: (items) => cloneItems(items),
|
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`
|
|
||||||
});
|
|
||||||
const tryHandleLivingChat = async (modeDecision, addressRuntimeMeta = null) => (0, assistantLivingChatAttemptRuntimeAdapter_1.runAssistantLivingChatAttemptRuntime)({
|
|
||||||
sessionId,
|
sessionId,
|
||||||
userMessage,
|
userMessage,
|
||||||
sessionItems: session.items,
|
sessionItems: session.items,
|
||||||
modeDecision,
|
payload,
|
||||||
sessionScope: {
|
sessionScope: {
|
||||||
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
knownOrganizations: sessionOrganizationScope.knownOrganizations,
|
||||||
selectedOrganization: sessionOrganizationScope.selectedOrganization,
|
selectedOrganization: sessionOrganizationScope.selectedOrganization,
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization
|
activeOrganization: sessionOrganizationScope.activeOrganization
|
||||||
},
|
},
|
||||||
addressRuntimeMeta,
|
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
||||||
traceIdFactory: () => `chat-${(0, nanoid_1.nanoid)(10)}`,
|
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, payload, userMessage),
|
||||||
|
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
||||||
|
sanitizeAddressMessageForFallback,
|
||||||
toNonEmptyString,
|
toNonEmptyString,
|
||||||
|
resolveAddressFollowupCarryoverContext,
|
||||||
|
resolveAssistantOrchestrationDecision,
|
||||||
|
buildAddressDialogContinuationContractV2,
|
||||||
|
runtimeAnalysisContextAsOfDate: runtimeAnalysisContext.as_of_date,
|
||||||
|
compactWhitespace,
|
||||||
|
mergeFollowupContextWithOrganizationScope,
|
||||||
|
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options),
|
||||||
|
isRetryableAddressLimitedResult,
|
||||||
mergeKnownOrganizations,
|
mergeKnownOrganizations,
|
||||||
hasAssistantDataScopeMetaQuestionSignal,
|
hasAssistantDataScopeMetaQuestionSignal,
|
||||||
shouldHandleAsAssistantCapabilityMetaQuery,
|
shouldHandleAsAssistantCapabilityMetaQuery,
|
||||||
|
|
@ -4393,56 +4380,23 @@ export class AssistantService {
|
||||||
buildAssistantDataScopeSelectionReply,
|
buildAssistantDataScopeSelectionReply,
|
||||||
buildAssistantOperationalBoundaryReply,
|
buildAssistantOperationalBoundaryReply,
|
||||||
buildAssistantCapabilityContractReply,
|
buildAssistantCapabilityContractReply,
|
||||||
|
chatClient: this.chatClient,
|
||||||
|
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
||||||
|
sanitizeOutgoingAssistantText,
|
||||||
|
defaultModel: config_1.DEFAULT_MODEL,
|
||||||
|
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
||||||
|
defaultApiKey: process.env.OPENAI_API_KEY ?? "",
|
||||||
|
buildAddressDebugPayload,
|
||||||
|
buildAddressFollowupOffer,
|
||||||
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
appendItem: (targetSessionId, item) => this.sessions.appendItem(targetSessionId, item),
|
||||||
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
getSession: (targetSessionId) => this.sessions.getSession(targetSessionId),
|
||||||
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
persistSession: (sessionState) => this.sessionLogger.persistSession(sessionState),
|
||||||
cloneConversation: (items) => cloneItems(items),
|
cloneConversation: (items) => cloneItems(items),
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
logEvent: (payload) => (0, log_1.logJson)(payload),
|
||||||
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
messageIdFactory: () => `msg-${(0, nanoid_1.nanoid)(10)}`,
|
||||||
nowIso: () => new Date().toISOString(),
|
|
||||||
payload,
|
|
||||||
chatClient: this.chatClient,
|
|
||||||
loadAssistantCanonExcerpt: assistantCanon_1.loadAssistantCanonExcerpt,
|
|
||||||
sanitizeOutgoingAssistantText,
|
|
||||||
defaultModel: config_1.DEFAULT_MODEL,
|
|
||||||
defaultBaseUrl: config_1.DEFAULT_OPENAI_BASE_URL,
|
|
||||||
defaultApiKey: process.env.OPENAI_API_KEY ?? ""
|
|
||||||
});
|
|
||||||
let addressRuntimeMetaForDeep = null;
|
|
||||||
const runAddressLaneAttempt = async (messageUsed, carryMeta, analysisDateHint) => (0, assistantAddressLaneAttemptRuntimeAdapter_1.runAssistantAddressLaneAttemptRuntime)({
|
|
||||||
messageUsed,
|
|
||||||
carryMeta: carryMeta ?? null,
|
|
||||||
analysisDateHint: analysisDateHint ?? null,
|
|
||||||
activeOrganization: sessionOrganizationScope.activeOrganization,
|
|
||||||
mergeFollowupContextWithOrganizationScope,
|
|
||||||
runAddressQueryTryHandle: (laneMessageUsed, options) => this.addressQueryService.tryHandle(laneMessageUsed, options)
|
|
||||||
});
|
|
||||||
const addressRuntime = await (0, assistantAddressRuntimeAdapter_1.runAssistantAddressRuntime)({
|
|
||||||
featureAssistantAddressQueryV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_V1,
|
|
||||||
sessionId,
|
|
||||||
userMessage,
|
|
||||||
sessionItems: session.items,
|
|
||||||
llmProvider: payload?.llmProvider,
|
|
||||||
useMock: Boolean(payload.useMock),
|
|
||||||
featureAddressLlmPredecomposeV1: config_1.FEATURE_ASSISTANT_ADDRESS_QUERY_LLM_PREDECOMPOSE_V1,
|
|
||||||
runAddressLlmPreDecompose: async () => runAddressLlmPreDecompose(this.normalizerService, payload, userMessage),
|
|
||||||
buildAddressLlmPredecomposeContractV1: predecomposeContract_1.buildAddressLlmPredecomposeContractV1,
|
|
||||||
sanitizeAddressMessageForFallback,
|
|
||||||
toNonEmptyString,
|
|
||||||
resolveAddressFollowupCarryoverContext,
|
|
||||||
resolveAssistantOrchestrationDecision,
|
|
||||||
buildAddressDialogContinuationContractV2,
|
|
||||||
runtimeAnalysisContextAsOfDate: runtimeAnalysisContext.as_of_date,
|
|
||||||
payloadContextPeriodHint: payload?.context?.period_hint,
|
|
||||||
compactWhitespace,
|
|
||||||
runAddressLaneAttempt,
|
|
||||||
isRetryableAddressLimitedResult,
|
|
||||||
finalizeAddressLaneResponse,
|
|
||||||
tryHandleLivingChat: (modeDecision, runtimeMeta) => tryHandleLivingChat(modeDecision, runtimeMeta),
|
|
||||||
logEvent: (payload) => (0, log_1.logJson)(payload),
|
|
||||||
nowIso: () => new Date().toISOString()
|
nowIso: () => new Date().toISOString()
|
||||||
});
|
});
|
||||||
addressRuntimeMetaForDeep = addressRuntime.addressRuntimeMetaForDeep;
|
const addressRuntimeMetaForDeep = addressRuntime.addressRuntimeMetaForDeep;
|
||||||
if (addressRuntime.handled && addressRuntime.response) {
|
if (addressRuntime.handled && addressRuntime.response) {
|
||||||
return addressRuntime.response;
|
return addressRuntime.response;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import { runAssistantAddressAttemptRuntime } from "../src/services/assistantAddressAttemptRuntimeAdapter";
|
||||||
|
|
||||||
|
function buildInput(overrides: Record<string, unknown> = {}) {
|
||||||
|
return {
|
||||||
|
featureAssistantAddressQueryV1: true,
|
||||||
|
sessionId: "asst-1",
|
||||||
|
userMessage: "where are overdue docs",
|
||||||
|
sessionItems: [],
|
||||||
|
payload: {
|
||||||
|
llmProvider: "openai",
|
||||||
|
useMock: 1,
|
||||||
|
context: {
|
||||||
|
period_hint: "2020-07-31"
|
||||||
|
},
|
||||||
|
apiKey: "key",
|
||||||
|
model: "gpt-5",
|
||||||
|
baseUrl: "http://localhost"
|
||||||
|
},
|
||||||
|
sessionScope: {
|
||||||
|
knownOrganizations: ["Org A"],
|
||||||
|
selectedOrganization: "Org A",
|
||||||
|
activeOrganization: "Org A"
|
||||||
|
},
|
||||||
|
featureAddressLlmPredecomposeV1: true,
|
||||||
|
runAddressLlmPreDecompose: async () => ({}),
|
||||||
|
buildAddressLlmPredecomposeContractV1: () => ({}),
|
||||||
|
sanitizeAddressMessageForFallback: (value: string) => value,
|
||||||
|
toNonEmptyString: (value: unknown) =>
|
||||||
|
typeof value === "string" && value.trim().length > 0 ? value.trim() : null,
|
||||||
|
resolveAddressFollowupCarryoverContext: () => null,
|
||||||
|
resolveAssistantOrchestrationDecision: () => ({ mode: "address_query", runAddressLane: true }),
|
||||||
|
buildAddressDialogContinuationContractV2: () => ({}),
|
||||||
|
runtimeAnalysisContextAsOfDate: "2020-07-31",
|
||||||
|
compactWhitespace: (value: string) => String(value ?? "").replace(/\s+/g, " ").trim(),
|
||||||
|
mergeFollowupContextWithOrganizationScope: (followupContext: Record<string, unknown> | null) =>
|
||||||
|
followupContext,
|
||||||
|
runAddressQueryTryHandle: async () => ({ response_type: "READY" }),
|
||||||
|
isRetryableAddressLimitedResult: () => false,
|
||||||
|
mergeKnownOrganizations: (knownOrganizations: string[], selectedOrganization: string | null) => ({
|
||||||
|
knownOrganizations,
|
||||||
|
selectedOrganization
|
||||||
|
}),
|
||||||
|
hasAssistantDataScopeMetaQuestionSignal: () => false,
|
||||||
|
shouldHandleAsAssistantCapabilityMetaQuery: () => false,
|
||||||
|
hasDestructiveDataActionSignal: () => false,
|
||||||
|
hasDangerOrCoercionSignal: () => false,
|
||||||
|
hasOperationalAdminActionRequestSignal: () => false,
|
||||||
|
hasOrganizationFactLookupSignal: () => false,
|
||||||
|
hasOrganizationFactFollowupSignal: () => false,
|
||||||
|
shouldEmitOrganizationSelectionReply: () => false,
|
||||||
|
hasAssistantCapabilityQuestionSignal: () => false,
|
||||||
|
resolveDataScopeProbe: () => null,
|
||||||
|
applyScriptGuard: (chatText: string) => chatText,
|
||||||
|
applyGroundingGuard: (guardInput: Record<string, unknown>) => guardInput,
|
||||||
|
buildAssistantSafetyRefusalReply: () => "safety",
|
||||||
|
buildAssistantDataScopeContractReply: () => "scope",
|
||||||
|
buildAssistantOrganizationFactBoundaryReply: () => "boundary",
|
||||||
|
buildAssistantDataScopeSelectionReply: () => "selection",
|
||||||
|
buildAssistantOperationalBoundaryReply: () => "operational",
|
||||||
|
buildAssistantCapabilityContractReply: () => "capability",
|
||||||
|
chatClient: {} as any,
|
||||||
|
loadAssistantCanonExcerpt: () => "",
|
||||||
|
sanitizeOutgoingAssistantText: (value: unknown, fallback = "") => {
|
||||||
|
const text = typeof value === "string" ? value.trim() : "";
|
||||||
|
return text || fallback;
|
||||||
|
},
|
||||||
|
defaultModel: "gpt-5",
|
||||||
|
defaultBaseUrl: "http://localhost",
|
||||||
|
defaultApiKey: "key",
|
||||||
|
buildAddressDebugPayload: () => ({}),
|
||||||
|
buildAddressFollowupOffer: () => null,
|
||||||
|
appendItem: () => {},
|
||||||
|
getSession: () => ({
|
||||||
|
session_id: "asst-1",
|
||||||
|
updated_at: "",
|
||||||
|
items: [],
|
||||||
|
investigation_state: null
|
||||||
|
}),
|
||||||
|
persistSession: () => {},
|
||||||
|
cloneConversation: (items: unknown[]) => items,
|
||||||
|
logEvent: () => {},
|
||||||
|
messageIdFactory: () => "msg-111",
|
||||||
|
nowIso: () => "2026-01-01T00:00:00.000Z",
|
||||||
|
...overrides
|
||||||
|
} as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("assistant address attempt runtime adapter", () => {
|
||||||
|
it("wires lane, response and living-chat attempt runtimes through one boundary", async () => {
|
||||||
|
const runAddressLaneAttemptRuntime = vi.fn(async () => ({
|
||||||
|
response_type: "READY"
|
||||||
|
}));
|
||||||
|
const runAddressLaneResponseAttemptRuntime = vi.fn(() => ({
|
||||||
|
kind: "address"
|
||||||
|
}));
|
||||||
|
const runLivingChatAttemptRuntime = vi.fn(async () => ({
|
||||||
|
kind: "chat"
|
||||||
|
}));
|
||||||
|
const runAddressRuntime = vi.fn(async (input: any) => {
|
||||||
|
const laneResult = await input.runAddressLaneAttempt(
|
||||||
|
"lane-message",
|
||||||
|
{ followupContext: { previous_intent: "docs_by_counterparty" } },
|
||||||
|
"2020-08-31"
|
||||||
|
);
|
||||||
|
expect(laneResult).toEqual({ response_type: "READY" });
|
||||||
|
|
||||||
|
const livingChatResult = await input.tryHandleLivingChat(
|
||||||
|
{ mode: "chat", reason: "living_chat_signal_detected" },
|
||||||
|
{ source: "address_runtime" }
|
||||||
|
);
|
||||||
|
expect(livingChatResult).toEqual({ kind: "chat" });
|
||||||
|
|
||||||
|
const response = input.finalizeAddressLaneResponse(
|
||||||
|
{ reply_text: "address reply", reply_type: "factual_with_explanation" },
|
||||||
|
"lane-message",
|
||||||
|
{ previousReplyType: "partial_coverage" },
|
||||||
|
{ mode: "supported", confidence: "high" }
|
||||||
|
);
|
||||||
|
expect(response).toEqual({ kind: "address" });
|
||||||
|
|
||||||
|
return {
|
||||||
|
handled: true,
|
||||||
|
response: { ok: true, lane: "address" },
|
||||||
|
addressRuntimeMetaForDeep: { source: "address_runtime" }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const runtime = await runAssistantAddressAttemptRuntime(
|
||||||
|
buildInput({
|
||||||
|
runAddressRuntime,
|
||||||
|
runAddressLaneAttemptRuntime,
|
||||||
|
runAddressLaneResponseAttemptRuntime,
|
||||||
|
runLivingChatAttemptRuntime
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(runtime).toEqual({
|
||||||
|
handled: true,
|
||||||
|
response: { ok: true, lane: "address" },
|
||||||
|
addressRuntimeMetaForDeep: { source: "address_runtime" }
|
||||||
|
});
|
||||||
|
expect(runAddressRuntime).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
llmProvider: "openai",
|
||||||
|
useMock: true,
|
||||||
|
payloadContextPeriodHint: "2020-07-31"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(runAddressLaneAttemptRuntime).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
messageUsed: "lane-message",
|
||||||
|
analysisDateHint: "2020-08-31",
|
||||||
|
activeOrganization: "Org A"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(runLivingChatAttemptRuntime).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionId: "asst-1",
|
||||||
|
sessionScope: expect.objectContaining({
|
||||||
|
selectedOrganization: "Org A"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(runAddressLaneResponseAttemptRuntime).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionId: "asst-1",
|
||||||
|
effectiveAddressUserMessage: "lane-message",
|
||||||
|
knownOrganizations: ["Org A"]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes empty payload fields to address runtime without breaking defaults", async () => {
|
||||||
|
const runAddressRuntime = vi.fn(async () => ({
|
||||||
|
handled: false,
|
||||||
|
response: null,
|
||||||
|
addressRuntimeMetaForDeep: null
|
||||||
|
}));
|
||||||
|
|
||||||
|
await runAssistantAddressAttemptRuntime(
|
||||||
|
buildInput({
|
||||||
|
payload: {},
|
||||||
|
runAddressRuntime
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(runAddressRuntime).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
llmProvider: undefined,
|
||||||
|
useMock: false,
|
||||||
|
payloadContextPeriodHint: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,64 @@
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
"generation_id": "gen-mnte8abx-ax3v3tr",
|
||||||
|
"created_at": "2026-04-10T21:03:44.205Z",
|
||||||
|
"mode": "qwen_seed",
|
||||||
|
"count": 10,
|
||||||
|
"domain": null,
|
||||||
|
"questions": [
|
||||||
|
"Покажи контрагентов с максимальными долгами, которые уже больше месяца не платят, и проверь, нет ли у них непроверенных авансовых отгрузок.",
|
||||||
|
"Где по покупателям висят заказы на конец месяца, но денег за них нет - требует ручной сверки?",
|
||||||
|
"Посмотри контрагентов, где сальдо не совпадает с актом сверки, и уточни, кого нужно уже непременно запросить справку по этой разнице.",
|
||||||
|
"Какие авансы давно остались висящими без закрытия - их пора либо отменять, либо перекладывать на счета реальных поставок?",
|
||||||
|
"Где у нас документы есть, но нет денег за них, и это уже выглядит как серьезная задолженность контрагента?",
|
||||||
|
"Проверь контрагентов с максимальными долгами - нет ли среди них тех, кто просто не закрыл накладные или оставил их без оплаты?",
|
||||||
|
"Какие реализации зависли на конец периода и могут портить выручку, если не проверять заранее?",
|
||||||
|
"Покажи контрагентов с максимальными долгами и уточни, нет ли среди них тех, кто просто игнорирует наши накладные.",
|
||||||
|
"Какие поставщики уже больше месяца не закрывают свои счета - это требует ручной проверки?",
|
||||||
|
"Проверь зависшие авансы и уточни, можно ли их перепривязать на текущие отгрузки или пора списывать как нереальные?"
|
||||||
|
],
|
||||||
|
"generated_by": "manual_reviewer",
|
||||||
|
"saved_case_set_file": "assistant_autogen_qwen_seed_20260410210344_gen-mnte8abx-ax3v3tr.json",
|
||||||
|
"context": {
|
||||||
|
"llm_provider": "local",
|
||||||
|
"model": "Qwen2.5 14B Instruct 1M",
|
||||||
|
"assistant_prompt_version": "address_query_runtime_v1",
|
||||||
|
"decomposition_prompt_version": "normalizer_v2_0_2",
|
||||||
|
"prompt_fingerprint": "Ты semantic-normalizer для бухгалтерского ассистента NDC.\nТвоя роль: только нормализация запроса пользователя в строгий JSON-контракт.\n\nЖесткие правила:\n1) Не давай бухгалтерский ответ по сути вопроса.\n2) Возвращай только JSON без markdown и пояснений.\n3) JSON обязан соответствовать переданной schema normalized_query_v1.\n4) Если период не указан, не выдумывай его; отмечай ambiguity.\n5) Для цепочек документов/проводок/оплат поднимай causal и cross-entity признаки.\n6) Для точечного object trace (номер/строка/ref) поднимай needs_exact_object_trace=true.\n7) Используй терминологию NDC.\nYou are semantic-normalizer for accounting assistant NDC.\nReturn strict JSON only, no markdown, no comments.\n\nTarget schema: normalized_query_v2_0_2.\n\nCore behavior (v2.0.2):\n1. Decompose message into semantic fragments.\n2. Classify fragment domain relevance and business scope.\n3. Fill route-critical flags and ",
|
||||||
|
"autogen_personality_id": "general",
|
||||||
|
"autogen_personality_prompt": "Генерируй реалистичные живые вопросы бухгалтера по 1С. Добавляй разговорные формулировки и опечатки, но сохраняй бизнес-смысл. акцент на контрагентов, долги нсд, счета, общий вывод по компании - контрагенты, заказчикам, скока денег кто принес и какие остатки по счетам, поиск документов, сальдо, банковские операции, незакрытые договора, документы по договорам, долги, Активность заказчиков по периодам, Поставщики и выплаты"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"generation_id": "gen-mnte6y9p-4v1kfbw",
|
||||||
|
"created_at": "2026-04-10T21:02:41.918Z",
|
||||||
|
"mode": "qwen_seed",
|
||||||
|
"count": 10,
|
||||||
|
"domain": null,
|
||||||
|
"questions": [
|
||||||
|
"Какие поставщики пока не закрыли взаиморасчёты на конец месяца и это выглядит как серьёзная проблема, а не просто задержка?",
|
||||||
|
"Где у нас висят покупатели 'грузили - денег нет - закрытия нет' и кто из них требует ручной проверки уже сейчас?",
|
||||||
|
"Покажи контрагентов с вероятным несоответствием сальдо, если мы запросим их акт сверки прямо сейчас.",
|
||||||
|
"Где у нас есть оплаты, но документы для закрытия взаиморасчётов всё ещё не пришли?",
|
||||||
|
"Какие контрагенты имеют документы, но нет нормального закрытия по оплатам?",
|
||||||
|
"Есть ли зависшие авансы, которые давно нужно перепроверить или закрыть?",
|
||||||
|
"Какие реализации на конец периода выглядят так, будто они зависли и могут испортить картину по выручке?",
|
||||||
|
"Где у нас отгрузки с проблемами не только в оплате, но и в самой связке документов?",
|
||||||
|
"Кто из поставщиков активно работает с нами последнее время и сколько денег принесли за последние 3 месяца?",
|
||||||
|
"Какие незакрытые договора есть на данный момент и что связано с ними по документам, долги и оплаты?"
|
||||||
|
],
|
||||||
|
"generated_by": "manual_reviewer",
|
||||||
|
"saved_case_set_file": "assistant_autogen_qwen_seed_20260410210241_gen-mnte6y9p-4v1kfbw.json",
|
||||||
|
"context": {
|
||||||
|
"llm_provider": "local",
|
||||||
|
"model": "Qwen2.5 14B Instruct 1M",
|
||||||
|
"assistant_prompt_version": "address_query_runtime_v1",
|
||||||
|
"decomposition_prompt_version": "normalizer_v2_0_2",
|
||||||
|
"prompt_fingerprint": "Ты semantic-normalizer для бухгалтерского ассистента NDC.\nТвоя роль: только нормализация запроса пользователя в строгий JSON-контракт.\n\nЖесткие правила:\n1) Не давай бухгалтерский ответ по сути вопроса.\n2) Возвращай только JSON без markdown и пояснений.\n3) JSON обязан соответствовать переданной schema normalized_query_v1.\n4) Если период не указан, не выдумывай его; отмечай ambiguity.\n5) Для цепочек документов/проводок/оплат поднимай causal и cross-entity признаки.\n6) Для точечного object trace (номер/строка/ref) поднимай needs_exact_object_trace=true.\n7) Используй терминологию NDC.\nYou are semantic-normalizer for accounting assistant NDC.\nReturn strict JSON only, no markdown, no comments.\n\nTarget schema: normalized_query_v2_0_2.\n\nCore behavior (v2.0.2):\n1. Decompose message into semantic fragments.\n2. Classify fragment domain relevance and business scope.\n3. Fill route-critical flags and ",
|
||||||
|
"autogen_personality_id": "general",
|
||||||
|
"autogen_personality_prompt": "Генерируй реалистичные живые вопросы бухгалтера по 1С. Добавляй разговорные формулировки и опечатки, но сохраняй бизнес-смысл. акцент на контрагентов, долги нсд, счета, общий вывод по компании - контрагенты, заказчикам, скока денег кто принес и какие остатки по счетам, поиск документов, сальдо, банковские операции, незакрытые договора, документы по договорам, долги, Активность заказчиков по периодам, Поставщики и выплаты"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"generation_id": "gen-mnsolawk-vugqyoc",
|
"generation_id": "gen-mnsolawk-vugqyoc",
|
||||||
"created_at": "2026-04-10T09:06:01.461Z",
|
"created_at": "2026-04-10T09:06:01.461Z",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
{
|
||||||
|
"suite_id": "assistant_autogen_gen-mnte6y9p-4v1kfbw",
|
||||||
|
"suite_version": "0.1.0",
|
||||||
|
"schema_version": "assistant_autogen_suite_v0_1",
|
||||||
|
"generated_at": "2026-04-10T21:02:41.918Z",
|
||||||
|
"generation_id": "gen-mnte6y9p-4v1kfbw",
|
||||||
|
"mode": "qwen_seed",
|
||||||
|
"domain": null,
|
||||||
|
"scenario_count": 10,
|
||||||
|
"case_ids": [
|
||||||
|
"AUTO-001",
|
||||||
|
"AUTO-002",
|
||||||
|
"AUTO-003",
|
||||||
|
"AUTO-004",
|
||||||
|
"AUTO-005",
|
||||||
|
"AUTO-006",
|
||||||
|
"AUTO-007",
|
||||||
|
"AUTO-008",
|
||||||
|
"AUTO-009",
|
||||||
|
"AUTO-010"
|
||||||
|
],
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-001",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие поставщики пока не закрыли взаиморасчёты на конец месяца и это выглядит как серьёзная проблема, а не просто задержка?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-002",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где у нас висят покупатели 'грузили - денег нет - закрытия нет' и кто из них требует ручной проверки уже сейчас?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-003",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Покажи контрагентов с вероятным несоответствием сальдо, если мы запросим их акт сверки прямо сейчас."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-004",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где у нас есть оплаты, но документы для закрытия взаиморасчётов всё ещё не пришли?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-005",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие контрагенты имеют документы, но нет нормального закрытия по оплатам?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-006",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Есть ли зависшие авансы, которые давно нужно перепроверить или закрыть?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-007",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие реализации на конец периода выглядят так, будто они зависли и могут испортить картину по выручке?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-008",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где у нас отгрузки с проблемами не только в оплате, но и в самой связке документов?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-009",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Кто из поставщиков активно работает с нами последнее время и сколько денег принесли за последние 3 месяца?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-010",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие незакрытые договора есть на данный момент и что связано с ними по документам, долги и оплаты?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
{
|
||||||
|
"suite_id": "assistant_autogen_gen-mnte8abx-ax3v3tr",
|
||||||
|
"suite_version": "0.1.0",
|
||||||
|
"schema_version": "assistant_autogen_suite_v0_1",
|
||||||
|
"generated_at": "2026-04-10T21:03:44.205Z",
|
||||||
|
"generation_id": "gen-mnte8abx-ax3v3tr",
|
||||||
|
"mode": "qwen_seed",
|
||||||
|
"domain": null,
|
||||||
|
"scenario_count": 10,
|
||||||
|
"case_ids": [
|
||||||
|
"AUTO-001",
|
||||||
|
"AUTO-002",
|
||||||
|
"AUTO-003",
|
||||||
|
"AUTO-004",
|
||||||
|
"AUTO-005",
|
||||||
|
"AUTO-006",
|
||||||
|
"AUTO-007",
|
||||||
|
"AUTO-008",
|
||||||
|
"AUTO-009",
|
||||||
|
"AUTO-010"
|
||||||
|
],
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-001",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Покажи контрагентов с максимальными долгами, которые уже больше месяца не платят, и проверь, нет ли у них непроверенных авансовых отгрузок."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-002",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где по покупателям висят заказы на конец месяца, но денег за них нет - требует ручной сверки?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-003",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Посмотри контрагентов, где сальдо не совпадает с актом сверки, и уточни, кого нужно уже непременно запросить справку по этой разнице."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-004",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие авансы давно остались висящими без закрытия - их пора либо отменять, либо перекладывать на счета реальных поставок?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-005",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где у нас документы есть, но нет денег за них, и это уже выглядит как серьезная задолженность контрагента?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-006",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Проверь контрагентов с максимальными долгами - нет ли среди них тех, кто просто не закрыл накладные или оставил их без оплаты?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-007",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие реализации зависли на конец периода и могут портить выручку, если не проверять заранее?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-008",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Покажи контрагентов с максимальными долгами и уточни, нет ли среди них тех, кто просто игнорирует наши накладные."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-009",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие поставщики уже больше месяца не закрывают свои счета - это требует ручной проверки?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-010",
|
||||||
|
"scenario_tag": "qwen_seed_general",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Проверь зависшие авансы и уточни, можно ли их перепривязать на текущие отгрузки или пора списывать как нереальные?"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"expected_hints": {
|
||||||
|
"expected_reply_type": null,
|
||||||
|
"expected_degraded_to": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
{
|
||||||
|
"suite_id": "assistant_autogen_runtime_job-bOkyd627Q3",
|
||||||
|
"suite_version": "0.1.0",
|
||||||
|
"schema_version": "assistant_autogen_runtime_v0_1",
|
||||||
|
"scenario_count": 10,
|
||||||
|
"case_ids": [
|
||||||
|
"AUTO-001",
|
||||||
|
"AUTO-002",
|
||||||
|
"AUTO-003",
|
||||||
|
"AUTO-004",
|
||||||
|
"AUTO-005",
|
||||||
|
"AUTO-006",
|
||||||
|
"AUTO-007",
|
||||||
|
"AUTO-008",
|
||||||
|
"AUTO-009",
|
||||||
|
"AUTO-010"
|
||||||
|
],
|
||||||
|
"cases": [
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-001",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Покажи контрагентов с максимальными долгами, которые уже больше месяца не платят, и проверь, нет ли у них непроверенных авансовых отгрузок."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-002",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где по покупателям висят заказы на конец месяца, но денег за них нет - требует ручной сверки?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-003",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Посмотри контрагентов, где сальдо не совпадает с актом сверки, и уточни, кого нужно уже непременно запросить справку по этой разнице."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-004",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие авансы давно остались висящими без закрытия - их пора либо отменять, либо перекладывать на счета реальных поставок?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-005",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Где у нас документы есть, но нет денег за них, и это уже выглядит как серьезная задолженность контрагента?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-006",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Проверь контрагентов с максимальными долгами - нет ли среди них тех, кто просто не закрыл накладные или оставил их без оплаты?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-007",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие реализации зависли на конец периода и могут портить выручку, если не проверять заранее?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-008",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Покажи контрагентов с максимальными долгами и уточни, нет ли среди них тех, кто просто игнорирует наши накладные."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-009",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Какие поставщики уже больше месяца не закрывают свои счета - это требует ручной проверки?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"case_id": "AUTO-010",
|
||||||
|
"scenario_tag": "autogen_runtime",
|
||||||
|
"question_type": "direct",
|
||||||
|
"broadness_level": "medium",
|
||||||
|
"turns": [
|
||||||
|
{
|
||||||
|
"user_message": "Проверь зависшие авансы и уточни, можно ли их перепривязать на текущие отгрузки или пора списывать как нереальные?"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue