АРЧ - Добавить поддержку агентных смысловых прогонов в автопрогоны и правило AGENT в AGENTS.md

This commit is contained in:
2026-04-17 10:51:13 +03:00
parent dc8dfcf237
commit 1484c2375f
25 changed files with 10574 additions and 743 deletions
+14 -4
View File
@@ -183,7 +183,13 @@ function readAutoGenHistory() {
: null,
source_session_id: toStringSafe(toRecord(item.context)?.source_session_id),
saved_session_file: toStringSafe(toRecord(item.context)?.saved_session_file),
saved_case_set_kind: toStringSafe(toRecord(item.context)?.saved_case_set_kind)
saved_case_set_kind: toStringSafe(toRecord(item.context)?.saved_case_set_kind),
agent_run: toBooleanSafe(toRecord(item.context)?.agent_run),
agent_focus: toStringSafe(toRecord(item.context)?.agent_focus)
? repairAutogenMojibake(String(toRecord(item.context)?.agent_focus))
: null,
architecture_phase: toStringSafe(toRecord(item.context)?.architecture_phase),
source_spec_file: toStringSafe(toRecord(item.context)?.source_spec_file)
}
: null
}))
@@ -1486,7 +1492,7 @@ function buildSavedSessionCaseSetPayload(input) {
? [
{
case_id: caseId,
scenario_tag: "saved_user_sessions",
scenario_tag: toStringSafe(input.scenarioTag) ?? "saved_user_sessions",
title: input.title,
question_type: turns.length > 1 ? "followup" : "direct",
broadness_level: "medium",
@@ -1515,7 +1521,10 @@ function rewriteAutoGenCaseSetFile(record) {
? buildSavedSessionCaseSetPayload({
generationId: record.generation_id,
title: record.title,
questions: record.questions
questions: record.questions,
scenarioTag: record.context?.saved_case_set_kind === "agent_semantic_scenario"
? "agent_saved_user_sessions"
: "saved_user_sessions"
})
: buildAutogenCaseSetPayload({
generationId: record.generation_id,
@@ -2064,7 +2073,8 @@ function buildAutoRunsRouter(services, openaiClient = new openaiResponsesClient_
writeJsonFile(caseSetPath, buildSavedSessionCaseSetPayload({
generationId,
title,
questions
questions,
scenarioTag: "saved_user_sessions"
}));
const snapshotFile = writeSavedAssistantSessionSnapshot({
generationId,
+263 -338
View File
@@ -3430,6 +3430,107 @@ class AddressQueryService {
debug: debugPayload
};
};
const buildFactualExecutionResult = (input) => {
const resultSemantics = mergeAddressResultSemantics(deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: input.selectedRecipe,
filters: input.extractedFilters ?? filters.extracted_filters,
semanticFrame: input.semanticFrame ?? semanticFrame,
responseType: input.responseType,
rowsMatched: input.rowsMatched
}), input.responseSemantics);
const routeExpectationAudit = input.routeExpectationAudit ??
buildRouteExpectationAudit({
intent: routeExpectationIntent,
selectedRecipe: input.selectedRecipe,
requestedResultMode,
resultMode: resultSemantics.result_mode
});
const debugPayload = (0, addressTruthGatePolicy_1.attachAddressTruthGate)({
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: input.extractedFilters ?? filters.extracted_filters,
missing_required_filters: [],
selected_recipe: input.selectedRecipe,
mcp_call_status_legacy: toLegacyMcpStatus(input.mcpCallStatus),
account_scope_mode: input.accountScopeMode,
account_scope_fallback_applied: input.accountScopeFallbackApplied,
anchor_type: input.anchor.anchor_type,
anchor_value_raw: input.anchor.anchor_value_raw,
anchor_value_resolved: input.anchor.anchor_value_resolved,
resolver_confidence: input.anchor.resolver_confidence,
ambiguity_count: input.anchor.ambiguity_count,
match_failure_stage: input.matchFailureStage,
match_failure_reason: input.matchFailureReason,
mcp_call_status: input.mcpCallStatus,
rows_fetched: input.rowsFetched,
raw_rows_received: input.rawRowsReceived,
rows_after_account_scope: input.rowsAfterAccountScope,
rows_after_recipe_filter: input.rowsAfterRecipeFilter,
rows_materialized: input.rowsMaterialized,
rows_matched: input.rowsMatched,
raw_row_keys_sample: input.rawRowKeysSample,
materialization_drop_reason: input.materializationDropReason,
account_token_raw: input.accountScopeAudit.accountTokenRaw,
account_token_normalized: input.accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: input.accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: input.accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: input.accountScopeAudit.accountScopeDropReason,
runtime_readiness: input.runtimeReadiness ?? "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: input.limitedReasonCategory ?? null,
response_type: input.responseType,
route_expectation_status: routeExpectationAudit.status,
route_expectation_reason: routeExpectationAudit.reason,
route_expectation_expected_selected_recipes: routeExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes: routeExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: routeExpectationAudit.expectedResultModes,
semantic_frame: input.semanticFrame ?? semanticFrame,
...resultSemantics,
limitations: input.limitations,
reasons: input.reasons,
...(input.capabilityAudit
? {
capability_id: input.capabilityAudit.capabilityId,
capability_layer: input.capabilityAudit.layer,
capability_route_mode: input.capabilityAudit.routeMode,
capability_route_enabled: input.capabilityAudit.enabled,
capability_route_reason: input.capabilityAudit.reason
}
: {}),
...(input.shadowRouteAudit
? {
shadow_route_intent: input.shadowRouteAudit.intent,
shadow_route_selected_recipe: input.shadowRouteAudit.selectedRecipe,
shadow_route_status: input.shadowRouteAudit.status
}
: {})
}, {
intent: intent.intent,
filters: input.extractedFilters ?? filters.extracted_filters,
semanticFrame: input.semanticFrame ?? semanticFrame,
selectedRecipe: input.selectedRecipe,
truthGateStatusHint: input.truthGateStatusHint ?? null,
rowsMatched: input.rowsMatched,
limitedReasonCategory: input.limitedReasonCategory ?? null,
runtimeReadiness: input.runtimeReadiness ?? "LIVE_QUERYABLE_WITH_LIMITS",
limitations: input.limitations,
reasons: input.reasons,
routeExpectationStatus: routeExpectationAudit.status,
routeExpectationReason: routeExpectationAudit.reason,
replyType: (0, composeStage_1.inferReplyType)(input.responseType)
});
return {
handled: true,
reply_text: input.replyText,
reply_type: (0, composeStage_1.inferReplyType)(input.responseType),
response_type: input.responseType,
debug: debugPayload
};
};
if (organizationWarehouseRecoveryApplied) {
if (!baseReasons.includes("organization_scope_live_grounding_recovered_rows")) {
baseReasons.push("organization_scope_live_grounding_recovered_rows");
@@ -3481,60 +3582,33 @@ class AddressQueryService {
const replyPrefix = recoveredBankRows.length > 0
? "Документный фильтр в live дал пустой набор; показываю связанные банковские операции по договору."
: "Документный фильтр в live дал пустой набор; показываю найденные строки по договорному якорю.";
return {
handled: true,
reply_text: `${replyPrefix}\n${factual.text}`,
reply_type: (0, composeStage_1.inferReplyType)(factual.responseType),
response_type: factual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: toLegacyMcpStatus("matched_non_empty"),
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: "matched_non_empty",
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: recoveredRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: factual.responseType,
...mergeAddressResultSemantics(deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: effectiveRecipeId,
filters: filters.extracted_filters,
semanticFrame,
responseType: factual.responseType,
rowsMatched: recoveredRows.length
}), factual.semantics),
limitations: [...filters.warnings, recoveryReason],
reasons: withConfirmedBalanceFallbackReason([...baseReasons, recoveryReason], requestedResultMode, factual.semantics)
}
};
return buildFactualExecutionResult({
replyText: `${replyPrefix}\n${factual.text}`,
responseType: factual.responseType,
responseSemantics: factual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: "matched_non_empty",
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: recoveredRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: [...filters.warnings, recoveryReason],
reasons: withConfirmedBalanceFallbackReason([...baseReasons, recoveryReason], requestedResultMode, factual.semantics),
limitedReasonCategory: "recipe_visibility_gap",
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
if (filteredRows.length === 0 &&
@@ -3605,60 +3679,32 @@ class AddressQueryService {
const expandedPrefix = `Период сохранен. Глубина live-выборки автоматически расширена до ${expandedPlan.limit} строк.`;
const expandedLimitations = [...filters.warnings, "query_limit_auto_expanded_for_anchor_recovery"];
const expandedReasons = [...baseReasons, "query_limit_auto_expanded_for_anchor_recovery"];
return {
handled: true,
reply_text: `${expandedPrefix}\n${expandedFactual.text}`,
reply_type: (0, composeStage_1.inferReplyType)(expandedFactual.responseType),
response_type: expandedFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: expandedSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(expandedStageStatus),
account_scope_mode: expandedPlan.account_scope_mode,
account_scope_fallback_applied: expandedAccountScopeFallbackApplied,
anchor_type: expandedAnchor.anchor_type,
anchor_value_raw: expandedAnchor.anchor_value_raw,
anchor_value_resolved: expandedAnchor.anchor_value_resolved,
resolver_confidence: expandedAnchor.resolver_confidence,
ambiguity_count: expandedAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: expandedStageStatus,
rows_fetched: expandedMcp.fetched_rows,
raw_rows_received: expandedMcp.raw_rows.length,
rows_after_account_scope: expandedNormalizedRows.length,
rows_after_recipe_filter: expandedRowsByAnchor.length,
rows_materialized: expandedNormalizedRows.length,
rows_matched: expandedFilteredRows.length,
raw_row_keys_sample: expandedRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: expandedRowDiagnostics.materializationDropReason,
account_token_raw: expandedAccountScopeAudit.accountTokenRaw,
account_token_normalized: expandedAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: expandedAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: expandedAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: expandedAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: expandedFactual.responseType,
...mergeAddressResultSemantics(deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: expandedSelection.selected_recipe.recipe_id,
filters: filters.extracted_filters,
semanticFrame,
responseType: expandedFactual.responseType,
rowsMatched: expandedFilteredRows.length
}), expandedFactual.semantics),
limitations: expandedLimitations,
reasons: withConfirmedBalanceFallbackReason(expandedReasons, requestedResultMode, expandedFactual.semantics)
}
};
return buildFactualExecutionResult({
replyText: `${expandedPrefix}\n${expandedFactual.text}`,
responseType: expandedFactual.responseType,
responseSemantics: expandedFactual.semantics,
selectedRecipe: expandedSelection.selected_recipe.recipe_id,
mcpCallStatus: expandedStageStatus,
rowsFetched: expandedMcp.fetched_rows,
rawRowsReceived: expandedMcp.raw_rows.length,
rowsAfterAccountScope: expandedNormalizedRows.length,
rowsAfterRecipeFilter: expandedRowsByAnchor.length,
rowsMaterialized: expandedNormalizedRows.length,
rowsMatched: expandedFilteredRows.length,
rawRowKeysSample: expandedRowDiagnostics.rawRowKeysSample,
materializationDropReason: expandedRowDiagnostics.materializationDropReason,
accountScopeMode: expandedPlan.account_scope_mode,
accountScopeFallbackApplied: expandedAccountScopeFallbackApplied,
accountScopeAudit: expandedAccountScopeAudit,
anchor: expandedAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: expandedLimitations,
reasons: withConfirmedBalanceFallbackReason(expandedReasons, requestedResultMode, expandedFactual.semantics),
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
}
@@ -3752,67 +3798,34 @@ class AddressQueryService {
requestedResultMode,
resultMode: broadenedResultSemantics.result_mode
});
return {
handled: true,
reply_text: injectNoticeAfterLeadLine(broadenedFactual.text, broadenedPrefix),
reply_type: (0, composeStage_1.inferReplyType)(broadenedFactual.responseType),
response_type: broadenedFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: broadenedSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(broadenedStageStatus),
account_scope_mode: broadenedPlan.account_scope_mode,
account_scope_fallback_applied: broadenedAccountScopeFallbackApplied,
anchor_type: broadenedAnchor.anchor_type,
anchor_value_raw: broadenedAnchor.anchor_value_raw,
anchor_value_resolved: broadenedAnchor.anchor_value_resolved,
resolver_confidence: broadenedAnchor.resolver_confidence,
ambiguity_count: broadenedAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: broadenedStageStatus,
rows_fetched: broadenedMcp.fetched_rows,
raw_rows_received: broadenedMcp.raw_rows.length,
rows_after_account_scope: broadenedNormalizedRows.length,
rows_after_recipe_filter: broadenedRowsByAnchor.length,
rows_materialized: broadenedNormalizedRows.length,
rows_matched: broadenedFilteredRows.length,
raw_row_keys_sample: broadenedRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: broadenedRowDiagnostics.materializationDropReason,
account_token_raw: broadenedAccountScopeAudit.accountTokenRaw,
account_token_normalized: broadenedAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: broadenedAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: broadenedAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: broadenedAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: broadenedFactual.responseType,
capability_id: capabilityAudit.capabilityId,
capability_layer: capabilityAudit.layer,
capability_route_mode: capabilityAudit.routeMode,
capability_route_enabled: capabilityAudit.enabled,
capability_route_reason: capabilityAudit.reason,
shadow_route_intent: shadowRouteAudit.intent,
shadow_route_selected_recipe: shadowRouteAudit.selectedRecipe,
shadow_route_status: shadowRouteAudit.status,
route_expectation_status: broadenedRouteExpectationAudit.status,
route_expectation_reason: broadenedRouteExpectationAudit.reason,
route_expectation_expected_selected_recipes: broadenedRouteExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes: broadenedRouteExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: broadenedRouteExpectationAudit.expectedResultModes,
semantic_frame: semanticFrame,
...broadenedResultSemantics,
limitations: broadenedLimitations,
reasons: withConfirmedBalanceFallbackReason(broadenedReasons, requestedResultMode, broadenedFactual.semantics)
}
};
return buildFactualExecutionResult({
replyText: injectNoticeAfterLeadLine(broadenedFactual.text, broadenedPrefix),
responseType: broadenedFactual.responseType,
responseSemantics: broadenedFactual.semantics,
selectedRecipe: broadenedSelection.selected_recipe.recipe_id,
mcpCallStatus: broadenedStageStatus,
rowsFetched: broadenedMcp.fetched_rows,
rawRowsReceived: broadenedMcp.raw_rows.length,
rowsAfterAccountScope: broadenedNormalizedRows.length,
rowsAfterRecipeFilter: broadenedRowsByAnchor.length,
rowsMaterialized: broadenedNormalizedRows.length,
rowsMatched: broadenedFilteredRows.length,
rawRowKeysSample: broadenedRowDiagnostics.rawRowKeysSample,
materializationDropReason: broadenedRowDiagnostics.materializationDropReason,
accountScopeMode: broadenedPlan.account_scope_mode,
accountScopeFallbackApplied: broadenedAccountScopeFallbackApplied,
accountScopeAudit: broadenedAccountScopeAudit,
anchor: broadenedAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: broadenedLimitations,
reasons: withConfirmedBalanceFallbackReason(broadenedReasons, requestedResultMode, broadenedFactual.semantics),
routeExpectationAudit: broadenedRouteExpectationAudit,
capabilityAudit,
shadowRouteAudit,
semanticFrame,
truthGateStatusHint: "limited_temporal_or_contextual"
});
}
}
}
@@ -3887,60 +3900,33 @@ class AddressQueryService {
: "";
const historicalLimitations = [...filters.warnings, "historical_window_sort_recovery_applied"];
const historicalReasons = [...baseReasons, "historical_window_sort_recovery_applied"];
return {
handled: true,
reply_text: `${historicalPrefix}\n${historicalFactual.text}${historicalSuggestion}`,
reply_type: (0, composeStage_1.inferReplyType)(historicalFactual.responseType),
response_type: historicalFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: historicalSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(historicalStageStatus),
account_scope_mode: historicalPlan.account_scope_mode,
account_scope_fallback_applied: historicalAccountScopeFallbackApplied,
anchor_type: historicalAnchor.anchor_type,
anchor_value_raw: historicalAnchor.anchor_value_raw,
anchor_value_resolved: historicalAnchor.anchor_value_resolved,
resolver_confidence: historicalAnchor.resolver_confidence,
ambiguity_count: historicalAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: historicalStageStatus,
rows_fetched: historicalMcp.fetched_rows,
raw_rows_received: historicalMcp.raw_rows.length,
rows_after_account_scope: historicalNormalizedRows.length,
rows_after_recipe_filter: historicalRowsByAnchor.length,
rows_materialized: historicalNormalizedRows.length,
rows_matched: historicalFilteredRows.length,
raw_row_keys_sample: historicalRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: historicalRowDiagnostics.materializationDropReason,
account_token_raw: historicalAccountScopeAudit.accountTokenRaw,
account_token_normalized: historicalAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: historicalAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: historicalAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: historicalAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: historicalFactual.responseType,
...mergeAddressResultSemantics(deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: historicalSelection.selected_recipe.recipe_id,
filters: filters.extracted_filters,
semanticFrame,
responseType: historicalFactual.responseType,
rowsMatched: historicalFilteredRows.length
}), historicalFactual.semantics),
limitations: historicalLimitations,
reasons: withConfirmedBalanceFallbackReason(historicalReasons, requestedResultMode, historicalFactual.semantics)
}
};
return buildFactualExecutionResult({
replyText: `${historicalPrefix}\n${historicalFactual.text}${historicalSuggestion}`,
responseType: historicalFactual.responseType,
responseSemantics: historicalFactual.semantics,
selectedRecipe: historicalSelection.selected_recipe.recipe_id,
mcpCallStatus: historicalStageStatus,
rowsFetched: historicalMcp.fetched_rows,
rawRowsReceived: historicalMcp.raw_rows.length,
rowsAfterAccountScope: historicalNormalizedRows.length,
rowsAfterRecipeFilter: historicalRowsByAnchor.length,
rowsMaterialized: historicalNormalizedRows.length,
rowsMatched: historicalFilteredRows.length,
rawRowKeysSample: historicalRowDiagnostics.rawRowKeysSample,
materializationDropReason: historicalRowDiagnostics.materializationDropReason,
accountScopeMode: historicalPlan.account_scope_mode,
accountScopeFallbackApplied: historicalAccountScopeFallbackApplied,
accountScopeAudit: historicalAccountScopeAudit,
anchor: historicalAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: historicalLimitations,
reasons: withConfirmedBalanceFallbackReason(historicalReasons, requestedResultMode, historicalFactual.semantics),
capabilityAudit,
shadowRouteAudit,
semanticFrame,
truthGateStatusHint: "limited_temporal_or_contextual"
});
}
}
}
@@ -3959,60 +3945,33 @@ class AddressQueryService {
: "";
const fallbackLimitations = [...filters.warnings, "anchor_not_matched_fallback_rows"];
const fallbackReasons = [...baseReasons, "anchor_not_matched_fallback_rows"];
return {
handled: true,
reply_text: `${fallbackPrefix}\n${fallbackFactual.text}${fallbackSuggestion}`,
reply_type: (0, composeStage_1.inferReplyType)(fallbackFactual.responseType),
response_type: fallbackFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: "matched_non_empty",
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: matchFailureStage,
match_failure_reason: matchFailureReason,
mcp_call_status: "matched_non_empty",
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: documentBankFallbackRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: fallbackFactual.responseType,
...mergeAddressResultSemantics(deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: effectiveRecipeId,
filters: filters.extracted_filters,
semanticFrame,
responseType: fallbackFactual.responseType,
rowsMatched: documentBankFallbackRows.length
}), fallbackFactual.semantics),
limitations: fallbackLimitations,
reasons: withConfirmedBalanceFallbackReason(fallbackReasons, requestedResultMode, fallbackFactual.semantics)
}
};
return buildFactualExecutionResult({
replyText: `${fallbackPrefix}\n${fallbackFactual.text}${fallbackSuggestion}`,
responseType: fallbackFactual.responseType,
responseSemantics: fallbackFactual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: "matched_non_empty",
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: documentBankFallbackRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage,
matchFailureReason,
limitations: fallbackLimitations,
reasons: withConfirmedBalanceFallbackReason(fallbackReasons, requestedResultMode, fallbackFactual.semantics),
capabilityAudit,
shadowRouteAudit,
limitedReasonCategory: "recipe_visibility_gap",
semanticFrame
});
}
}
const allowConfirmedAsOfZeroSnapshot = filteredRows.length === 0 &&
@@ -4297,67 +4256,33 @@ class AddressQueryService {
const reasonsWithRouteExpectation = finalRouteExpectationAudit.status === "mismatch"
? [...baseReasons, `route_expectation_mismatch:${finalRouteExpectationAudit.reason}`]
: baseReasons;
return {
handled: true,
reply_text: factual.text,
reply_type: (0, composeStage_1.inferReplyType)(factual.responseType),
response_type: factual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: toLegacyMcpStatus(stageStatus),
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: stageStatus,
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: filteredRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: factual.responseType,
capability_id: capabilityAudit.capabilityId,
capability_layer: capabilityAudit.layer,
capability_route_mode: capabilityAudit.routeMode,
capability_route_enabled: capabilityAudit.enabled,
capability_route_reason: capabilityAudit.reason,
shadow_route_intent: shadowRouteAudit.intent,
shadow_route_selected_recipe: shadowRouteAudit.selectedRecipe,
shadow_route_status: shadowRouteAudit.status,
route_expectation_status: finalRouteExpectationAudit.status,
route_expectation_reason: finalRouteExpectationAudit.reason,
route_expectation_expected_selected_recipes: finalRouteExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes: finalRouteExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: finalRouteExpectationAudit.expectedResultModes,
semantic_frame: semanticFrame,
...factualResultSemantics,
limitations: factualLimitations,
reasons: withConfirmedBalanceFallbackReason(reasonsWithRouteExpectation, requestedResultMode, factual.semantics, factualResultSemantics.result_mode)
}
};
return buildFactualExecutionResult({
replyText: factual.text,
responseType: factual.responseType,
responseSemantics: factual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: stageStatus,
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: filteredRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: factualLimitations,
reasons: withConfirmedBalanceFallbackReason(reasonsWithRouteExpectation, requestedResultMode, factual.semantics, factualResultSemantics.result_mode),
routeExpectationAudit: finalRouteExpectationAudit,
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
exports.AddressQueryService = AddressQueryService;
@@ -115,6 +115,9 @@ function hasReusableRootScope(input) {
return Boolean(input.semanticFrame && input.semanticFrame.scope_kind !== "none");
}
function truthGateStatusFrom(input) {
if (input.truthGateStatusHint) {
return input.truthGateStatusHint;
}
const missingRequiredFilters = input.missingRequiredFilters ?? [];
if (input.routeExpectationStatus === "mismatch") {
return "blocked_route_expectation_failure";
@@ -192,7 +192,7 @@ exports.INVENTORY_CAPABILITY_CONTRACTS = [
capability_id: "confirmed_inventory_on_hand_as_of_date",
intent_ids: ["inventory_on_hand_as_of_date"],
entry_modes: ["root_entry", "root_followup", "clarification_resume"],
transitions: ["T1", "T2", "T7"],
transitions: ["T1", "T2", "T6", "T7"],
requiresFocusObject: false,
requiredAnchors: [],
resultShape: "item_list_with_quantity_cost_warehouse_organization",
@@ -18,7 +18,7 @@ function hasInventorySupplierCue(text) {
if (/(?:кто\s+(?:был\s+)?продавец|кто\s+нам\s+продал|кто\s+продал\s+нам|(?:^|[\s,.;:!?()\-])(?:продавец|seller)(?=$|[\s,.;:!?()\-]))/iu.test(value)) {
return true;
}
if (/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|откуда\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(value)) {
if (/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?(?:это|этот\s+товар|эту\s+позицию)\s+поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|откуда\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(value)) {
return true;
}
return hasInventoryPurchaseStem(value) && /(?:у\s+кого|от\s+кого|где)/iu.test(value);
+20 -4
View File
@@ -193,6 +193,10 @@ interface AutoGenHistoryRecord {
source_session_id?: string | null;
saved_session_file?: string | null;
saved_case_set_kind?: string | null;
agent_run?: boolean | null;
agent_focus?: string | null;
architecture_phase?: string | null;
source_spec_file?: string | null;
} | null;
}
@@ -365,7 +369,13 @@ function readAutoGenHistory(): AutoGenHistoryRecord[] {
: null,
source_session_id: toStringSafe(toRecord(item.context)?.source_session_id),
saved_session_file: toStringSafe(toRecord(item.context)?.saved_session_file),
saved_case_set_kind: toStringSafe(toRecord(item.context)?.saved_case_set_kind)
saved_case_set_kind: toStringSafe(toRecord(item.context)?.saved_case_set_kind),
agent_run: toBooleanSafe(toRecord(item.context)?.agent_run),
agent_focus: toStringSafe(toRecord(item.context)?.agent_focus)
? repairAutogenMojibake(String(toRecord(item.context)?.agent_focus))
: null,
architecture_phase: toStringSafe(toRecord(item.context)?.architecture_phase),
source_spec_file: toStringSafe(toRecord(item.context)?.source_spec_file)
}
: null
}))
@@ -1797,6 +1807,7 @@ function buildSavedSessionCaseSetPayload(input: {
generationId: string;
title: string | null;
questions: string[];
scenarioTag?: string | null;
}): Record<string, unknown> {
const questions = parseAssistantSessionQuestions(input.questions);
const turns = questions.map((question) => ({
@@ -1818,7 +1829,7 @@ function buildSavedSessionCaseSetPayload(input: {
? [
{
case_id: caseId,
scenario_tag: "saved_user_sessions",
scenario_tag: toStringSafe(input.scenarioTag) ?? "saved_user_sessions",
title: input.title,
question_type: turns.length > 1 ? "followup" : "direct",
broadness_level: "medium",
@@ -1851,7 +1862,11 @@ function rewriteAutoGenCaseSetFile(record: AutoGenHistoryRecord): string | null
? buildSavedSessionCaseSetPayload({
generationId: record.generation_id,
title: record.title,
questions: record.questions
questions: record.questions,
scenarioTag:
record.context?.saved_case_set_kind === "agent_semantic_scenario"
? "agent_saved_user_sessions"
: "saved_user_sessions"
})
: buildAutogenCaseSetPayload({
generationId: record.generation_id,
@@ -2468,7 +2483,8 @@ export function buildAutoRunsRouter(services: AppServices, openaiClient = new Op
buildSavedSessionCaseSetPayload({
generationId,
title,
questions
questions,
scenarioTag: "saved_user_sessions"
})
);
@@ -9,6 +9,7 @@ import {
FEATURE_ASSISTANT_ADDRESS_QUERY_LIVE_V1,
SHARED_LLM_CONNECTION_FILE
} from "../config";
import type { AssistantTruthGateContractStatus } from "../types/assistantRuntimeContracts";
import type {
AddressCapabilityLayer,
AddressCapabilityRouteMode,
@@ -4207,6 +4208,150 @@ export class AddressQueryService {
debug: debugPayload
};
};
const buildFactualExecutionResult = (input: {
replyText: string;
responseType: AddressResponseType;
responseSemantics?: ComposeReplySemantics;
selectedRecipe: string | null;
mcpCallStatus: AddressMcpCallStatus;
rowsFetched: number;
rawRowsReceived: number;
rowsAfterAccountScope: number;
rowsAfterRecipeFilter: number;
rowsMaterialized: number;
rowsMatched: number;
rawRowKeysSample: string[];
materializationDropReason:
| "none"
| "dropped_by_account_scope_filter"
| "missing_period_and_registrator_fields"
| "missing_period_field"
| "missing_registrator_field"
| "unknown_row_shape";
accountScopeMode: "strict" | "preferred";
accountScopeFallbackApplied: boolean;
accountScopeAudit: AccountScopeAuditDebug;
anchor: AnchorResolutionDebug;
matchFailureStage: AddressMatchFailureStage;
matchFailureReason: string | null;
limitations: string[];
reasons: string[];
routeExpectationAudit?: AddressRouteExpectationAuditState;
capabilityAudit?: AddressCapabilityAudit;
shadowRouteAudit?: AddressShadowRouteAudit;
semanticFrame?: AddressSemanticFrame | null;
runtimeReadiness?: AddressRuntimeReadiness;
limitedReasonCategory?: AddressLimitedReasonCategory | null;
truthGateStatusHint?: AssistantTruthGateContractStatus | null;
extractedFilters?: AddressFilterSet;
}): AddressExecutionResult => {
const resultSemantics = mergeAddressResultSemantics(
deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: input.selectedRecipe,
filters: input.extractedFilters ?? filters.extracted_filters,
semanticFrame: input.semanticFrame ?? semanticFrame,
responseType: input.responseType,
rowsMatched: input.rowsMatched
}),
input.responseSemantics
);
const routeExpectationAudit =
input.routeExpectationAudit ??
buildRouteExpectationAudit({
intent: routeExpectationIntent,
selectedRecipe: input.selectedRecipe,
requestedResultMode,
resultMode: resultSemantics.result_mode
});
const debugPayload = attachAddressTruthGate(
{
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: input.extractedFilters ?? filters.extracted_filters,
missing_required_filters: [],
selected_recipe: input.selectedRecipe,
mcp_call_status_legacy: toLegacyMcpStatus(input.mcpCallStatus),
account_scope_mode: input.accountScopeMode,
account_scope_fallback_applied: input.accountScopeFallbackApplied,
anchor_type: input.anchor.anchor_type,
anchor_value_raw: input.anchor.anchor_value_raw,
anchor_value_resolved: input.anchor.anchor_value_resolved,
resolver_confidence: input.anchor.resolver_confidence,
ambiguity_count: input.anchor.ambiguity_count,
match_failure_stage: input.matchFailureStage,
match_failure_reason: input.matchFailureReason,
mcp_call_status: input.mcpCallStatus,
rows_fetched: input.rowsFetched,
raw_rows_received: input.rawRowsReceived,
rows_after_account_scope: input.rowsAfterAccountScope,
rows_after_recipe_filter: input.rowsAfterRecipeFilter,
rows_materialized: input.rowsMaterialized,
rows_matched: input.rowsMatched,
raw_row_keys_sample: input.rawRowKeysSample,
materialization_drop_reason: input.materializationDropReason,
account_token_raw: input.accountScopeAudit.accountTokenRaw,
account_token_normalized: input.accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: input.accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: input.accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: input.accountScopeAudit.accountScopeDropReason,
runtime_readiness: input.runtimeReadiness ?? "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: input.limitedReasonCategory ?? null,
response_type: input.responseType,
route_expectation_status: routeExpectationAudit.status,
route_expectation_reason: routeExpectationAudit.reason,
route_expectation_expected_selected_recipes: routeExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes: routeExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: routeExpectationAudit.expectedResultModes,
semantic_frame: input.semanticFrame ?? semanticFrame,
...resultSemantics,
limitations: input.limitations,
reasons: input.reasons,
...(input.capabilityAudit
? {
capability_id: input.capabilityAudit.capabilityId,
capability_layer: input.capabilityAudit.layer,
capability_route_mode: input.capabilityAudit.routeMode,
capability_route_enabled: input.capabilityAudit.enabled,
capability_route_reason: input.capabilityAudit.reason
}
: {}),
...(input.shadowRouteAudit
? {
shadow_route_intent: input.shadowRouteAudit.intent,
shadow_route_selected_recipe: input.shadowRouteAudit.selectedRecipe,
shadow_route_status: input.shadowRouteAudit.status
}
: {})
},
{
intent: intent.intent,
filters: input.extractedFilters ?? filters.extracted_filters,
semanticFrame: input.semanticFrame ?? semanticFrame,
selectedRecipe: input.selectedRecipe,
truthGateStatusHint: input.truthGateStatusHint ?? null,
rowsMatched: input.rowsMatched,
limitedReasonCategory: input.limitedReasonCategory ?? null,
runtimeReadiness: input.runtimeReadiness ?? "LIVE_QUERYABLE_WITH_LIMITS",
limitations: input.limitations,
reasons: input.reasons,
routeExpectationStatus: routeExpectationAudit.status,
routeExpectationReason: routeExpectationAudit.reason,
replyType: inferReplyType(input.responseType)
}
);
return {
handled: true,
reply_text: input.replyText,
reply_type: inferReplyType(input.responseType),
response_type: input.responseType,
debug: debugPayload
};
};
if (organizationWarehouseRecoveryApplied) {
if (!baseReasons.includes("organization_scope_live_grounding_recovered_rows")) {
baseReasons.push("organization_scope_live_grounding_recovered_rows");
@@ -4262,67 +4407,33 @@ export class AddressQueryService {
recoveredBankRows.length > 0
? "Документный фильтр в live дал пустой набор; показываю связанные банковские операции по договору."
: "Документный фильтр в live дал пустой набор; показываю найденные строки по договорному якорю.";
return {
handled: true,
reply_text: `${replyPrefix}\n${factual.text}`,
reply_type: inferReplyType(factual.responseType),
response_type: factual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: toLegacyMcpStatus("matched_non_empty"),
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: "matched_non_empty",
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: recoveredRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: factual.responseType,
...mergeAddressResultSemantics(
deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: effectiveRecipeId,
filters: filters.extracted_filters,
semanticFrame,
responseType: factual.responseType,
rowsMatched: recoveredRows.length
}),
factual.semantics
),
limitations: [...filters.warnings, recoveryReason],
reasons: withConfirmedBalanceFallbackReason(
[...baseReasons, recoveryReason],
requestedResultMode,
factual.semantics
)
}
};
return buildFactualExecutionResult({
replyText: `${replyPrefix}\n${factual.text}`,
responseType: factual.responseType,
responseSemantics: factual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: "matched_non_empty",
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: recoveredRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: [...filters.warnings, recoveryReason],
reasons: withConfirmedBalanceFallbackReason([...baseReasons, recoveryReason], requestedResultMode, factual.semantics),
limitedReasonCategory: "recipe_visibility_gap",
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
@@ -4411,67 +4522,32 @@ export class AddressQueryService {
const expandedPrefix = `Период сохранен. Глубина live-выборки автоматически расширена до ${expandedPlan.limit} строк.`;
const expandedLimitations = [...filters.warnings, "query_limit_auto_expanded_for_anchor_recovery"];
const expandedReasons = [...baseReasons, "query_limit_auto_expanded_for_anchor_recovery"];
return {
handled: true,
reply_text: `${expandedPrefix}\n${expandedFactual.text}`,
reply_type: inferReplyType(expandedFactual.responseType),
response_type: expandedFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: expandedSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(expandedStageStatus),
account_scope_mode: expandedPlan.account_scope_mode,
account_scope_fallback_applied: expandedAccountScopeFallbackApplied,
anchor_type: expandedAnchor.anchor_type,
anchor_value_raw: expandedAnchor.anchor_value_raw,
anchor_value_resolved: expandedAnchor.anchor_value_resolved,
resolver_confidence: expandedAnchor.resolver_confidence,
ambiguity_count: expandedAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: expandedStageStatus,
rows_fetched: expandedMcp.fetched_rows,
raw_rows_received: expandedMcp.raw_rows.length,
rows_after_account_scope: expandedNormalizedRows.length,
rows_after_recipe_filter: expandedRowsByAnchor.length,
rows_materialized: expandedNormalizedRows.length,
rows_matched: expandedFilteredRows.length,
raw_row_keys_sample: expandedRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: expandedRowDiagnostics.materializationDropReason,
account_token_raw: expandedAccountScopeAudit.accountTokenRaw,
account_token_normalized: expandedAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: expandedAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: expandedAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: expandedAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: expandedFactual.responseType,
...mergeAddressResultSemantics(
deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: expandedSelection.selected_recipe.recipe_id,
filters: filters.extracted_filters,
semanticFrame,
responseType: expandedFactual.responseType,
rowsMatched: expandedFilteredRows.length
}),
expandedFactual.semantics
),
limitations: expandedLimitations,
reasons: withConfirmedBalanceFallbackReason(
expandedReasons,
requestedResultMode,
expandedFactual.semantics
)
}
};
return buildFactualExecutionResult({
replyText: `${expandedPrefix}\n${expandedFactual.text}`,
responseType: expandedFactual.responseType,
responseSemantics: expandedFactual.semantics,
selectedRecipe: expandedSelection.selected_recipe.recipe_id,
mcpCallStatus: expandedStageStatus,
rowsFetched: expandedMcp.fetched_rows,
rawRowsReceived: expandedMcp.raw_rows.length,
rowsAfterAccountScope: expandedNormalizedRows.length,
rowsAfterRecipeFilter: expandedRowsByAnchor.length,
rowsMaterialized: expandedNormalizedRows.length,
rowsMatched: expandedFilteredRows.length,
rawRowKeysSample: expandedRowDiagnostics.rawRowKeysSample,
materializationDropReason: expandedRowDiagnostics.materializationDropReason,
accountScopeMode: expandedPlan.account_scope_mode,
accountScopeFallbackApplied: expandedAccountScopeFallbackApplied,
accountScopeAudit: expandedAccountScopeAudit,
anchor: expandedAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: expandedLimitations,
reasons: withConfirmedBalanceFallbackReason(expandedReasons, requestedResultMode, expandedFactual.semantics),
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
}
@@ -4586,72 +4662,34 @@ export class AddressQueryService {
requestedResultMode,
resultMode: broadenedResultSemantics.result_mode
});
return {
handled: true,
reply_text: injectNoticeAfterLeadLine(broadenedFactual.text, broadenedPrefix),
reply_type: inferReplyType(broadenedFactual.responseType),
response_type: broadenedFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: broadenedSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(broadenedStageStatus),
account_scope_mode: broadenedPlan.account_scope_mode,
account_scope_fallback_applied: broadenedAccountScopeFallbackApplied,
anchor_type: broadenedAnchor.anchor_type,
anchor_value_raw: broadenedAnchor.anchor_value_raw,
anchor_value_resolved: broadenedAnchor.anchor_value_resolved,
resolver_confidence: broadenedAnchor.resolver_confidence,
ambiguity_count: broadenedAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: broadenedStageStatus,
rows_fetched: broadenedMcp.fetched_rows,
raw_rows_received: broadenedMcp.raw_rows.length,
rows_after_account_scope: broadenedNormalizedRows.length,
rows_after_recipe_filter: broadenedRowsByAnchor.length,
rows_materialized: broadenedNormalizedRows.length,
rows_matched: broadenedFilteredRows.length,
raw_row_keys_sample: broadenedRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: broadenedRowDiagnostics.materializationDropReason,
account_token_raw: broadenedAccountScopeAudit.accountTokenRaw,
account_token_normalized: broadenedAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: broadenedAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: broadenedAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: broadenedAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: broadenedFactual.responseType,
capability_id: capabilityAudit.capabilityId,
capability_layer: capabilityAudit.layer,
capability_route_mode: capabilityAudit.routeMode,
capability_route_enabled: capabilityAudit.enabled,
capability_route_reason: capabilityAudit.reason,
shadow_route_intent: shadowRouteAudit.intent,
shadow_route_selected_recipe: shadowRouteAudit.selectedRecipe,
shadow_route_status: shadowRouteAudit.status,
route_expectation_status: broadenedRouteExpectationAudit.status,
route_expectation_reason: broadenedRouteExpectationAudit.reason,
route_expectation_expected_selected_recipes: broadenedRouteExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes:
broadenedRouteExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: broadenedRouteExpectationAudit.expectedResultModes,
semantic_frame: semanticFrame,
...broadenedResultSemantics,
limitations: broadenedLimitations,
reasons: withConfirmedBalanceFallbackReason(
broadenedReasons,
requestedResultMode,
broadenedFactual.semantics
)
}
};
return buildFactualExecutionResult({
replyText: injectNoticeAfterLeadLine(broadenedFactual.text, broadenedPrefix),
responseType: broadenedFactual.responseType,
responseSemantics: broadenedFactual.semantics,
selectedRecipe: broadenedSelection.selected_recipe.recipe_id,
mcpCallStatus: broadenedStageStatus,
rowsFetched: broadenedMcp.fetched_rows,
rawRowsReceived: broadenedMcp.raw_rows.length,
rowsAfterAccountScope: broadenedNormalizedRows.length,
rowsAfterRecipeFilter: broadenedRowsByAnchor.length,
rowsMaterialized: broadenedNormalizedRows.length,
rowsMatched: broadenedFilteredRows.length,
rawRowKeysSample: broadenedRowDiagnostics.rawRowKeysSample,
materializationDropReason: broadenedRowDiagnostics.materializationDropReason,
accountScopeMode: broadenedPlan.account_scope_mode,
accountScopeFallbackApplied: broadenedAccountScopeFallbackApplied,
accountScopeAudit: broadenedAccountScopeAudit,
anchor: broadenedAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: broadenedLimitations,
reasons: withConfirmedBalanceFallbackReason(broadenedReasons, requestedResultMode, broadenedFactual.semantics),
routeExpectationAudit: broadenedRouteExpectationAudit,
capabilityAudit,
shadowRouteAudit,
semanticFrame,
truthGateStatusHint: "limited_temporal_or_contextual"
});
}
}
}
@@ -4745,67 +4783,33 @@ export class AddressQueryService {
: "";
const historicalLimitations = [...filters.warnings, "historical_window_sort_recovery_applied"];
const historicalReasons = [...baseReasons, "historical_window_sort_recovery_applied"];
return {
handled: true,
reply_text: `${historicalPrefix}\n${historicalFactual.text}${historicalSuggestion}`,
reply_type: inferReplyType(historicalFactual.responseType),
response_type: historicalFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: historicalSelection.selected_recipe.recipe_id,
mcp_call_status_legacy: toLegacyMcpStatus(historicalStageStatus),
account_scope_mode: historicalPlan.account_scope_mode,
account_scope_fallback_applied: historicalAccountScopeFallbackApplied,
anchor_type: historicalAnchor.anchor_type,
anchor_value_raw: historicalAnchor.anchor_value_raw,
anchor_value_resolved: historicalAnchor.anchor_value_resolved,
resolver_confidence: historicalAnchor.resolver_confidence,
ambiguity_count: historicalAnchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: historicalStageStatus,
rows_fetched: historicalMcp.fetched_rows,
raw_rows_received: historicalMcp.raw_rows.length,
rows_after_account_scope: historicalNormalizedRows.length,
rows_after_recipe_filter: historicalRowsByAnchor.length,
rows_materialized: historicalNormalizedRows.length,
rows_matched: historicalFilteredRows.length,
raw_row_keys_sample: historicalRowDiagnostics.rawRowKeysSample,
materialization_drop_reason: historicalRowDiagnostics.materializationDropReason,
account_token_raw: historicalAccountScopeAudit.accountTokenRaw,
account_token_normalized: historicalAccountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: historicalAccountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: historicalAccountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: historicalAccountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: historicalFactual.responseType,
...mergeAddressResultSemantics(
deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: historicalSelection.selected_recipe.recipe_id,
filters: filters.extracted_filters,
semanticFrame,
responseType: historicalFactual.responseType,
rowsMatched: historicalFilteredRows.length
}),
historicalFactual.semantics
),
limitations: historicalLimitations,
reasons: withConfirmedBalanceFallbackReason(
historicalReasons,
requestedResultMode,
historicalFactual.semantics
)
}
};
return buildFactualExecutionResult({
replyText: `${historicalPrefix}\n${historicalFactual.text}${historicalSuggestion}`,
responseType: historicalFactual.responseType,
responseSemantics: historicalFactual.semantics,
selectedRecipe: historicalSelection.selected_recipe.recipe_id,
mcpCallStatus: historicalStageStatus,
rowsFetched: historicalMcp.fetched_rows,
rawRowsReceived: historicalMcp.raw_rows.length,
rowsAfterAccountScope: historicalNormalizedRows.length,
rowsAfterRecipeFilter: historicalRowsByAnchor.length,
rowsMaterialized: historicalNormalizedRows.length,
rowsMatched: historicalFilteredRows.length,
rawRowKeysSample: historicalRowDiagnostics.rawRowKeysSample,
materializationDropReason: historicalRowDiagnostics.materializationDropReason,
accountScopeMode: historicalPlan.account_scope_mode,
accountScopeFallbackApplied: historicalAccountScopeFallbackApplied,
accountScopeAudit: historicalAccountScopeAudit,
anchor: historicalAnchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: historicalLimitations,
reasons: withConfirmedBalanceFallbackReason(historicalReasons, requestedResultMode, historicalFactual.semantics),
capabilityAudit,
shadowRouteAudit,
semanticFrame,
truthGateStatusHint: "limited_temporal_or_contextual"
});
}
}
}
@@ -4832,67 +4836,33 @@ export class AddressQueryService {
: "";
const fallbackLimitations = [...filters.warnings, "anchor_not_matched_fallback_rows"];
const fallbackReasons = [...baseReasons, "anchor_not_matched_fallback_rows"];
return {
handled: true,
reply_text: `${fallbackPrefix}\n${fallbackFactual.text}${fallbackSuggestion}`,
reply_type: inferReplyType(fallbackFactual.responseType),
response_type: fallbackFactual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: "matched_non_empty",
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: matchFailureStage,
match_failure_reason: matchFailureReason,
mcp_call_status: "matched_non_empty",
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: documentBankFallbackRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: fallbackFactual.responseType,
...mergeAddressResultSemantics(
deriveAddressResultSemantics({
intent: intent.intent,
selectedRecipe: effectiveRecipeId,
filters: filters.extracted_filters,
semanticFrame,
responseType: fallbackFactual.responseType,
rowsMatched: documentBankFallbackRows.length
}),
fallbackFactual.semantics
),
limitations: fallbackLimitations,
reasons: withConfirmedBalanceFallbackReason(
fallbackReasons,
requestedResultMode,
fallbackFactual.semantics
)
}
};
return buildFactualExecutionResult({
replyText: `${fallbackPrefix}\n${fallbackFactual.text}${fallbackSuggestion}`,
responseType: fallbackFactual.responseType,
responseSemantics: fallbackFactual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: "matched_non_empty",
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: documentBankFallbackRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage,
matchFailureReason,
limitations: fallbackLimitations,
reasons: withConfirmedBalanceFallbackReason(fallbackReasons, requestedResultMode, fallbackFactual.semantics),
capabilityAudit,
shadowRouteAudit,
limitedReasonCategory: "recipe_visibility_gap",
semanticFrame
});
}
}
@@ -5223,71 +5193,37 @@ export class AddressQueryService {
finalRouteExpectationAudit.status === "mismatch"
? [...baseReasons, `route_expectation_mismatch:${finalRouteExpectationAudit.reason}`]
: baseReasons;
return {
handled: true,
reply_text: factual.text,
reply_type: inferReplyType(factual.responseType),
response_type: factual.responseType,
debug: {
detected_mode: mode.mode,
detected_mode_confidence: mode.confidence,
query_shape: shape.shape,
query_shape_confidence: shape.confidence,
detected_intent: intent.intent,
detected_intent_confidence: intent.confidence,
extracted_filters: filters.extracted_filters,
missing_required_filters: [],
selected_recipe: effectiveRecipeId,
mcp_call_status_legacy: toLegacyMcpStatus(stageStatus),
account_scope_mode: plan.account_scope_mode,
account_scope_fallback_applied: accountScopeFallbackApplied,
anchor_type: anchor.anchor_type,
anchor_value_raw: anchor.anchor_value_raw,
anchor_value_resolved: anchor.anchor_value_resolved,
resolver_confidence: anchor.resolver_confidence,
ambiguity_count: anchor.ambiguity_count,
match_failure_stage: "none",
match_failure_reason: null,
mcp_call_status: stageStatus,
rows_fetched: mcp.fetched_rows,
raw_rows_received: mcp.raw_rows.length,
rows_after_account_scope: normalizedRows.length,
rows_after_recipe_filter: filterByAnchors.length,
rows_materialized: normalizedRows.length,
rows_matched: filteredRows.length,
raw_row_keys_sample: rowDiagnostics.rawRowKeysSample,
materialization_drop_reason: rowDiagnostics.materializationDropReason,
account_token_raw: accountScopeAudit.accountTokenRaw,
account_token_normalized: accountScopeAudit.accountTokenNormalized,
account_scope_fields_checked: accountScopeAudit.accountScopeFieldsChecked,
account_scope_match_strategy: accountScopeAudit.accountScopeMatchStrategy,
account_scope_drop_reason: accountScopeAudit.accountScopeDropReason,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
limited_reason_category: null,
response_type: factual.responseType,
capability_id: capabilityAudit.capabilityId,
capability_layer: capabilityAudit.layer,
capability_route_mode: capabilityAudit.routeMode,
capability_route_enabled: capabilityAudit.enabled,
capability_route_reason: capabilityAudit.reason,
shadow_route_intent: shadowRouteAudit.intent,
shadow_route_selected_recipe: shadowRouteAudit.selectedRecipe,
shadow_route_status: shadowRouteAudit.status,
route_expectation_status: finalRouteExpectationAudit.status,
route_expectation_reason: finalRouteExpectationAudit.reason,
route_expectation_expected_selected_recipes: finalRouteExpectationAudit.expectedSelectedRecipes,
route_expectation_expected_requested_result_modes: finalRouteExpectationAudit.expectedRequestedResultModes,
route_expectation_expected_result_modes: finalRouteExpectationAudit.expectedResultModes,
semantic_frame: semanticFrame,
...factualResultSemantics,
limitations: factualLimitations,
reasons: withConfirmedBalanceFallbackReason(
reasonsWithRouteExpectation,
requestedResultMode,
factual.semantics,
factualResultSemantics.result_mode
)
}
};
return buildFactualExecutionResult({
replyText: factual.text,
responseType: factual.responseType,
responseSemantics: factual.semantics,
selectedRecipe: effectiveRecipeId,
mcpCallStatus: stageStatus,
rowsFetched: mcp.fetched_rows,
rawRowsReceived: mcp.raw_rows.length,
rowsAfterAccountScope: normalizedRows.length,
rowsAfterRecipeFilter: filterByAnchors.length,
rowsMaterialized: normalizedRows.length,
rowsMatched: filteredRows.length,
rawRowKeysSample: rowDiagnostics.rawRowKeysSample,
materializationDropReason: rowDiagnostics.materializationDropReason,
accountScopeMode: plan.account_scope_mode,
accountScopeFallbackApplied,
accountScopeAudit,
anchor,
matchFailureStage: "none",
matchFailureReason: null,
limitations: factualLimitations,
reasons: withConfirmedBalanceFallbackReason(
reasonsWithRouteExpectation,
requestedResultMode,
factual.semantics,
factualResultSemantics.result_mode
),
routeExpectationAudit: finalRouteExpectationAudit,
capabilityAudit,
shadowRouteAudit,
semanticFrame
});
}
}
@@ -28,6 +28,7 @@ export interface ResolveAddressTruthGateInput {
filters?: AddressFilterSet | null;
semanticFrame?: AddressSemanticFrame | null;
selectedRecipe?: string | null;
truthGateStatusHint?: AssistantTruthGateContractStatus | null;
rowsMatched?: number;
limitedReasonCategory?: AddressLimitedReasonCategory | null;
runtimeReadiness?: AddressRuntimeReadiness | null;
@@ -170,6 +171,9 @@ function hasReusableRootScope(input: ResolveAddressTruthGateInput): boolean {
}
function truthGateStatusFrom(input: ResolveAddressTruthGateInput): AssistantTruthGateContractStatus {
if (input.truthGateStatusHint) {
return input.truthGateStatusHint;
}
const missingRequiredFilters = input.missingRequiredFilters ?? [];
if (input.routeExpectationStatus === "mismatch") {
return "blocked_route_expectation_failure";
@@ -207,7 +207,7 @@ export const INVENTORY_CAPABILITY_CONTRACTS: readonly AssistantCapabilityContrac
capability_id: "confirmed_inventory_on_hand_as_of_date",
intent_ids: ["inventory_on_hand_as_of_date"],
entry_modes: ["root_entry", "root_followup", "clarification_resume"],
transitions: ["T1", "T2", "T7"],
transitions: ["T1", "T2", "T6", "T7"],
requiresFocusObject: false,
requiredAnchors: [],
resultShape: "item_list_with_quantity_cost_warehouse_organization",
@@ -15,7 +15,7 @@ export function hasInventorySupplierCue(text: string): boolean {
return true;
}
if (
/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|откуда\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(
/(?:кто\s+(?:(?:это|этот\s+товар|эту\s+позицию)\s+)?(?:нам\s+)?поставил|кто\s+(?:нам\s+)?(?:это|этот\s+товар|эту\s+позицию)\s+поставил|кто\s+(?:нам\s+)?поставил\s+(?:это|этот\s+товар|эту\s+позицию)|от\s+какого\s+поставщика|у\s+какого\s+поставщика|от\s+кого\s+куплен|у\s+кого\s+купили|у\s+кого\s+куплено|где\s+(?:мы\s+)?купили(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|откуда\s+(?:мы\s+)?взяли(?:\s+(?:это|его|этот\s+товар|эту\s+позицию))?|где\s+куплено|supplier|vendor|поставщик)/iu.test(
value
)
) {
@@ -114,6 +114,7 @@ describe("counterparty shipment item flow and open-items routing", () => {
expect(result?.handled).toBe(true);
expect(result?.response_type).toBe("FACTUAL_LIST");
expect(result?.debug.detected_intent).toBe("list_documents_by_counterparty");
expect(result?.debug.address_truth_gate_v1?.truth_gate_status).toBe("full_confirmed");
expect(String(result?.reply_text ?? "")).toContain("Контрагент: Чепурнов П.Д.");
expect(String(result?.reply_text ?? "")).toContain("Позиции:");
expect(String(result?.reply_text ?? "")).toContain("Кабель силовой");
@@ -144,6 +144,38 @@ describe("inventory root frame regressions", () => {
expect(result?.baseReasons).toContain("address_followup_context_applied");
});
it("restores inventory root frame for 'покажи еще раз остатки на эту же дату' after item documents drilldown", () => {
const result = runAddressDecomposeStage("покажи еще раз остатки на эту же дату", {
previous_intent: "inventory_purchase_documents_for_item",
previous_filters: {
item: "Столешница 600*3050*26 альмандин",
organization: 'ООО "Альтернатива Плюс"',
as_of_date: "2021-03-31"
},
previous_anchor_type: "item",
previous_anchor_value: "Столешница 600*3050*26 альмандин",
root_intent: "inventory_on_hand_as_of_date",
root_filters: {
organization: 'ООО "Альтернатива Плюс"',
period_from: "2021-03-01",
period_to: "2021-03-31",
as_of_date: "2021-03-31"
},
root_anchor_type: "organization",
root_anchor_value: 'ООО "Альтернатива Плюс"',
current_frame_kind: "inventory_drilldown"
});
expect(result).not.toBeNull();
expect(result?.intent.intent).toBe("inventory_on_hand_as_of_date");
expect(result?.intent.reasons).toContain("intent_restored_to_inventory_root_frame");
expect(result?.filters.extracted_filters.organization).toBe('ООО "Альтернатива Плюс"');
expect(result?.filters.extracted_filters.as_of_date).toBe("2021-03-31");
expect(result?.filters.extracted_filters.period_from).toBe("2021-03-01");
expect(result?.filters.extracted_filters.period_to).toBe("2021-03-31");
expect(result?.filters.extracted_filters.item).toBeUndefined();
});
it("restores inventory root frame for root-context-only month follow-up after drilldown", () => {
const result = runAddressDecomposeStage("остатки на июль 2019", {
previous_filters: {
@@ -107,6 +107,8 @@ describe("inventory selected-object follow-up", () => {
expect(result?.debug.capability_route_mode).toBe("exact");
expect(result?.debug.reasons).toContain("period_window_auto_broadened_to_available_data");
expect(result?.debug.limitations).toContain("period_window_auto_broadened_to_available_data");
expect(result?.debug.address_truth_gate_v1?.truth_gate_status).toBe("limited_temporal_or_contextual");
expect(result?.debug.address_truth_gate_v1?.carryover_eligibility).toBe("object_only");
const replyLines = String(result?.reply_text ?? "").split("\n");
expect(replyLines[0]).toContain("По позиции Кромка с клеем 33 альмандин 137 м");
expect(replyLines[0]).toContain("до 31.03.2021 подтвержден поставщик");
@@ -197,6 +199,56 @@ describe("inventory selected-object follow-up", () => {
expect(String(result?.reply_text ?? "")).toContain("Торговый дом \\Союз МСК\\");
});
it("handles selected-object supplier wording 'кто нам это поставил' as provenance follow-up", async () => {
executeAddressMcpQueryMock.mockResolvedValueOnce({
fetched_rows: 1,
matched_rows: 1,
raw_rows: [
{
Period: "2019-02-12T00:00:00Z",
Registrator: "Поступление товаров и услуг 00000000003 от 12.02.2019 0:00:00",
AccountDt: "41.01",
AccountKt: "60.01",
Amount: 3690,
SubcontoDt1: "Столешница 600*3050*26 альмандин",
SubcontoDt3: "Основной склад",
SubcontoKt1: "Торговый дом \\Союз",
SubcontoKt2: "Договор поставки № 12 от 01.02.2019",
Organization: "ООО \\Альтернатива Плюс\\"
}
],
rows: [],
error: null
});
const service = new AddressQueryService();
const result = await service.tryHandle(
'По выбранному объекту "Столешница 600*3050*26 альмандин": кто нам это поставил?',
{
followupContext: {
previous_intent: "inventory_on_hand_as_of_date",
previous_filters: {
as_of_date: "2021-03-31",
period_from: "2021-03-01",
period_to: "2021-03-31",
warehouse: "Основной склад",
organization: "ООО \\Альтернатива Плюс\\"
},
previous_anchor_type: "unknown",
previous_anchor_value: null
}
}
);
expect(result?.handled).toBe(true);
expect(result?.response_type).toBe("FACTUAL_SUMMARY");
expect(result?.debug.detected_intent).toBe("inventory_purchase_provenance_for_item");
expect(result?.debug.extracted_filters?.item).toBe("Столешница 600*3050*26 альмандин");
expect(result?.debug.extracted_filters?.as_of_date).toBeUndefined();
expect(result?.debug.capability_id).toBe("inventory_inventory_purchase_provenance_for_item");
expect(String(result?.reply_text ?? "")).toContain("Торговый дом \\Союз");
});
it("handles selected-object colloquial supplier wording 'у кого купили' as provenance follow-up", async () => {
executeAddressMcpQueryMock.mockResolvedValueOnce({
fetched_rows: 1,
@@ -123,6 +123,38 @@ describe("assistant capability runtime binding adapter", () => {
expect(binding.violations).toContain("transition_not_supported_by_capability");
});
it("allows inventory root capability to return through T6 after a drilldown pivot", () => {
const binding = resolveAssistantCapabilityRuntimeBinding({
addressDebug: {
capability_id: "confirmed_inventory_on_hand_as_of_date",
detected_intent: "inventory_on_hand_as_of_date",
detected_mode: "address_query",
capability_layer: "compute",
capability_route_mode: "exact",
rows_matched: 11,
route_expectation_status: "matched"
},
runtimeContractShadow: {
schema_version: "assistant_runtime_contracts_v1",
transition_contract_id: "T6",
transition_contract_title: "Domain Pivot With Root-Only Carryover",
transition_contract_reason: ["root_context_reused_after_drilldown_context"],
capability_contract_id: "confirmed_inventory_on_hand_as_of_date",
capability_contract_reason: ["debug_capability_id_matched_contract"],
truth_gate_contract_status: "full_confirmed",
carryover_eligibility: "root_only"
},
groundingStatus: "grounded",
replyType: "factual"
});
expect(binding.binding_status).toBe("bound");
expect(binding.binding_action).toBe("allow");
expect(binding.transition_id).toBe("T6");
expect(binding.transition_allowed).toBe(true);
expect(binding.violations).toEqual([]);
});
it("attaches compact debug fields and preserves the binding contract", () => {
const debug = attachAssistantCapabilityRuntimeBinding(
{
@@ -117,6 +117,33 @@ describe("assistant truth answer policy runtime adapter", () => {
expect(policy.answer_shape.may_power_followup).toBe(true);
});
it("keeps explicit temporal-limited factual answers limited in the truth contract", () => {
const policy = resolveAssistantTruthAnswerPolicyRuntime({
addressDebug: {
capability_id: "inventory_inventory_purchase_provenance_for_item",
rows_matched: 2,
address_truth_gate_v1: {
schema_version: "address_truth_gate_v1",
policy_owner: "addressTruthGatePolicy",
truth_gate_status: "limited_temporal_or_contextual",
carryover_eligibility: "object_only",
limited_reason_category: null,
runtime_readiness: "LIVE_QUERYABLE_WITH_LIMITS",
reason_codes: ["period_window_auto_broadened_to_available_data"],
blocked_or_limited_explanation: "temporal_or_contextual_limit"
}
},
replyType: "factual"
});
expect(policy.truth_gate.coverage_status).toBe("partial");
expect(policy.truth_gate.truth_mode).toBe("limited");
expect(policy.truth_gate.carryover_eligibility).toBe("object_only");
expect(policy.truth_gate.blocked_or_limited_explanation).toBe("temporal_or_contextual_limit");
expect(policy.answer_shape.answer_shape).toBe("limited_with_reason");
expect(policy.answer_shape.must_include_limitation).toBe(true);
});
it("attaches top-level debug fields without hiding the nested contract", () => {
const debug = attachAssistantTruthAnswerPolicy(
{