From 18e4eba54e9353f344a905c60fc49a2c09c6cfa9 Mon Sep 17 00:00:00 2001 From: dctouch Date: Fri, 17 Apr 2026 17:05:42 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=A0=D0=A7=20=D0=90=D0=9F11=20-=20?= =?UTF-8?q?=D0=90=D1=80=D1=85=D0=B8=D1=82=D0=B5=D0=BA=D1=82=D1=83=D1=80?= =?UTF-8?q?=D0=B0:=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81=D1=82=D0=B8=20debug=20?= =?UTF-8?q?payload=20assembly=20=D0=B8=D0=B7=20assistantService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../05 - assistantService_extraction_map.md | 4 +- .../08 - current_status_audit_2026-04-17.md | 8 +- .../assistantDebugPayloadAssembler.js | 150 ++++++++++++++++ .../backend/dist/services/assistantService.js | 149 ++-------------- .../assistantDebugPayloadAssembler.ts | 163 ++++++++++++++++++ .../backend/src/services/assistantService.ts | 150 ++-------------- 6 files changed, 343 insertions(+), 281 deletions(-) diff --git a/docs/ARCH/11 - architecture_turnaround/05 - assistantService_extraction_map.md b/docs/ARCH/11 - architecture_turnaround/05 - assistantService_extraction_map.md index e517d15..faddc9b 100644 --- a/docs/ARCH/11 - architecture_turnaround/05 - assistantService_extraction_map.md +++ b/docs/ARCH/11 - architecture_turnaround/05 - assistantService_extraction_map.md @@ -14,7 +14,7 @@ The goal is to turn it from a god-service into a thinner coordinator. Approximate size: -- `5178` lines +- `5050` lines It currently mixes concerns from: @@ -26,6 +26,7 @@ It currently mixes concerns from: - memory recap detection; - provider-aware predecompose orchestration; - chat/data-scope/address boundary policy. +- debug and backend-error payload assembly. ## Extraction Principle @@ -214,6 +215,7 @@ What is already true: - route, transition, boundary, meta, memory, and provider policies have explicit external owners; - data-scope probing and organization-history extraction now also have an explicit owner; +- address/backend debug payload assembly now delegates into `assistantDebugPayloadAssembler`; - runtime already delegates important decisions to those owners. What is still not fully true: diff --git a/docs/ARCH/11 - architecture_turnaround/08 - current_status_audit_2026-04-17.md b/docs/ARCH/11 - architecture_turnaround/08 - current_status_audit_2026-04-17.md index a43f9cd..8ed2828 100644 --- a/docs/ARCH/11 - architecture_turnaround/08 - current_status_audit_2026-04-17.md +++ b/docs/ARCH/11 - architecture_turnaround/08 - current_status_audit_2026-04-17.md @@ -126,7 +126,7 @@ This is enough to build targeted semantic packs that are not single-domain toy s ## Honest Phase Status -Estimated overall turnaround completion: `~86%` +Estimated overall turnaround completion: `~87%` ### Phase 0. Shared Baseline @@ -191,16 +191,17 @@ Remaining debt: ### Phase 5. AssistantService Extraction -Status: `79%` +Status: `82%` Reason: - major policy categories have real owners outside the coordinator. - data-scope probing and organization-history extraction are now delegated to a dedicated owner. +- address/backend debug payload assembly is no longer owned only by the coordinator. Remaining debt: -- `assistantService.ts` is still about `5178` lines; +- `assistantService.ts` is still about `5050` lines; - runtime uses extracted owners, but legacy bodies and fallback branches still live in the coordinator file; - code review still sometimes requires reading `assistantService` together with extracted owners. @@ -242,6 +243,7 @@ Compared with the pre-turnaround baseline, the system is now materially better i - factual-negative answers can remain truthful instead of collapsing into generic technical refusals; - meta questions and memory recap are no longer purely incidental side effects of route logic; - organization data-scope probing is no longer owned only by coordinator-local helper bodies; +- debug payload assembly is now further isolated from top-level turn coordination; - architecture regressions can now be localized to route, transition, truth gate, coverage/evidence, boundary, or meta/memory layers. ## What Still Remains The Main Architectural Debt diff --git a/llm_normalizer/backend/dist/services/assistantDebugPayloadAssembler.js b/llm_normalizer/backend/dist/services/assistantDebugPayloadAssembler.js index 2f76e0c..7477e65 100644 --- a/llm_normalizer/backend/dist/services/assistantDebugPayloadAssembler.js +++ b/llm_normalizer/backend/dist/services/assistantDebugPayloadAssembler.js @@ -1,5 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.buildEmptyCoverageReport = buildEmptyCoverageReport; +exports.buildAssistantBackendErrorDebugPayload = buildAssistantBackendErrorDebugPayload; +exports.buildAddressRuntimeDebugPayload = buildAddressRuntimeDebugPayload; exports.buildDeepAnalysisDebugPayload = buildDeepAnalysisDebugPayload; const assistantCapabilityRuntimeBindingAdapter_1 = require("./assistantCapabilityRuntimeBindingAdapter"); const assistantRuntimeContractResolver_1 = require("./assistantRuntimeContractResolver"); @@ -18,6 +21,153 @@ function toAnalysisContext(input) { snapshot_mode: input.snapshot_mode }; } +function buildEmptyCoverageReport() { + return { + requirements_total: 0, + requirements_covered: 0, + requirements_uncovered: [], + requirements_partially_covered: [], + clarification_needed_for: [], + out_of_scope_requirements: [] + }; +} +function buildAssistantBackendErrorDebugPayload(input) { + return { + trace_id: input.traceIdFactory(), + prompt_version: "assistant_backend_error_fallback_v1", + schema_version: "assistant_backend_error_fallback_v1", + fallback_type: "unknown", + route_summary: null, + fragments: [], + requirements_extracted: [], + coverage_report: buildEmptyCoverageReport(), + routes: [], + retrieval_status: [], + retrieval_results: [], + answer_grounding_check: { + status: "no_grounded_answer", + route_subject_match: true, + missing_requirements: [], + reasons: [`backend_error:${String(input.errorMessage ?? "unknown_error").slice(0, 280)}`], + why_included_summary: [], + selection_reason_summary: [] + }, + dropped_intent_segments: [], + answer_structure_v11: null, + investigation_state_snapshot: null, + normalized: null + }; +} +function buildAddressRuntimeDebugPayload(input) { + const grounded = input.addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "grounded"; + const llmMeta = input.llmPreDecomposeMeta && typeof input.llmPreDecomposeMeta === "object" ? input.llmPreDecomposeMeta : null; + return { + trace_id: input.traceIdFactory(), + prompt_version: "address_query_runtime_v1", + schema_version: "address_query_runtime_v1", + fallback_type: input.addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "none", + route_summary: null, + fragments: [], + requirements_extracted: [], + coverage_report: buildEmptyCoverageReport(), + routes: [], + retrieval_status: [], + retrieval_results: [], + answer_grounding_check: { + status: grounded, + route_subject_match: true, + missing_requirements: [], + reasons: input.addressDebug.reasons ?? [], + why_included_summary: [], + selection_reason_summary: [] + }, + dropped_intent_segments: [], + detected_mode: input.addressDebug.detected_mode, + detected_mode_confidence: input.addressDebug.detected_mode_confidence, + query_shape: input.addressDebug.query_shape, + query_shape_confidence: input.addressDebug.query_shape_confidence, + detected_intent: input.addressDebug.detected_intent, + detected_intent_confidence: input.addressDebug.detected_intent_confidence, + extracted_filters: input.addressDebug.extracted_filters, + missing_required_filters: input.addressDebug.missing_required_filters, + selected_recipe: input.addressDebug.selected_recipe, + mcp_call_status_legacy: input.addressDebug.mcp_call_status_legacy, + account_scope_mode: input.addressDebug.account_scope_mode, + account_scope_fallback_applied: input.addressDebug.account_scope_fallback_applied, + anchor_type: input.addressDebug.anchor_type, + anchor_value_raw: input.addressDebug.anchor_value_raw, + anchor_value_resolved: input.addressDebug.anchor_value_resolved, + resolver_confidence: input.addressDebug.resolver_confidence, + ambiguity_count: input.addressDebug.ambiguity_count, + match_failure_stage: input.addressDebug.match_failure_stage, + match_failure_reason: input.addressDebug.match_failure_reason, + mcp_call_status: input.addressDebug.mcp_call_status, + rows_fetched: input.addressDebug.rows_fetched, + raw_rows_received: input.addressDebug.raw_rows_received, + rows_after_account_scope: input.addressDebug.rows_after_account_scope, + rows_after_recipe_filter: input.addressDebug.rows_after_recipe_filter, + rows_materialized: input.addressDebug.rows_materialized, + rows_matched: input.addressDebug.rows_matched, + raw_row_keys_sample: input.addressDebug.raw_row_keys_sample, + materialization_drop_reason: input.addressDebug.materialization_drop_reason, + account_token_raw: input.addressDebug.account_token_raw, + account_token_normalized: input.addressDebug.account_token_normalized, + account_scope_fields_checked: input.addressDebug.account_scope_fields_checked, + account_scope_match_strategy: input.addressDebug.account_scope_match_strategy, + account_scope_drop_reason: input.addressDebug.account_scope_drop_reason, + runtime_readiness: input.addressDebug.runtime_readiness, + limited_reason_category: input.addressDebug.limited_reason_category, + organization_candidates: input.addressDebug.organization_candidates ?? undefined, + response_type: input.addressDebug.response_type, + requested_result_mode: input.addressDebug.requested_result_mode ?? undefined, + result_mode: input.addressDebug.result_mode ?? undefined, + evidence_strength: input.addressDebug.evidence_strength ?? undefined, + balance_confirmed: typeof input.addressDebug.balance_confirmed === "boolean" ? input.addressDebug.balance_confirmed : undefined, + as_of_date_basis: input.addressDebug.as_of_date_basis ?? undefined, + capability_id: input.addressDebug.capability_id ?? undefined, + capability_layer: input.addressDebug.capability_layer ?? undefined, + capability_route_mode: input.addressDebug.capability_route_mode ?? undefined, + capability_route_enabled: typeof input.addressDebug.capability_route_enabled === "boolean" + ? input.addressDebug.capability_route_enabled + : undefined, + capability_route_reason: input.addressDebug.capability_route_reason ?? undefined, + shadow_route_intent: input.addressDebug.shadow_route_intent ?? undefined, + shadow_route_selected_recipe: input.addressDebug.shadow_route_selected_recipe ?? undefined, + shadow_route_status: input.addressDebug.shadow_route_status ?? undefined, + route_expectation_status: input.addressDebug.route_expectation_status ?? undefined, + route_expectation_reason: input.addressDebug.route_expectation_reason ?? undefined, + route_expectation_expected_selected_recipes: input.addressDebug.route_expectation_expected_selected_recipes ?? undefined, + route_expectation_expected_requested_result_modes: input.addressDebug.route_expectation_expected_requested_result_modes ?? undefined, + route_expectation_expected_result_modes: input.addressDebug.route_expectation_expected_result_modes ?? undefined, + execution_lane: "address_query", + llm_decomposition_applied: Boolean(llmMeta?.applied), + llm_decomposition_attempted: Boolean(llmMeta?.attempted), + llm_provider_used: llmMeta?.provider ?? null, + llm_decomposition_trace_id: llmMeta?.traceId ?? null, + llm_decomposition_effective_message: llmMeta?.effectiveMessage ?? null, + llm_decomposition_reason: llmMeta?.reason ?? null, + llm_canonical_candidate_detected: Boolean(llmMeta?.llmCanonicalCandidateDetected), + llm_predecompose_contract: llmMeta?.predecomposeContract ?? null, + fallback_rule_hit: llmMeta?.fallbackRuleHit ?? null, + sanitized_user_message: llmMeta?.sanitizedUserMessage ?? null, + tool_gate_decision: llmMeta?.toolGateDecision ?? null, + tool_gate_reason: llmMeta?.toolGateReason ?? null, + orchestration_contract_v1: llmMeta?.orchestrationContract ?? null, + dialog_continuation_contract_v2: llmMeta?.dialogContinuationContract ?? null, + address_retry_audit: llmMeta?.addressRetryAudit ?? null, + answer_structure_v11: null, + investigation_state_snapshot: null, + normalized: null, + normalizer_output: llmMeta?.traceId + ? { + trace_id: llmMeta.traceId, + prompt_version: "normalizer_v2_0_2", + applied: Boolean(llmMeta?.applied), + effective_message: llmMeta?.effectiveMessage ?? null + } + : null + }; +} function buildDeepAnalysisDebugPayload(input) { const analysisContext = toAnalysisContext(input.runtimeAnalysisContext); const answerContractStage4Audit = (0, assistantStage4AnswerContractAudit_1.buildStage4AnswerContractAuditV1)(input.assistantReply); diff --git a/llm_normalizer/backend/dist/services/assistantService.js b/llm_normalizer/backend/dist/services/assistantService.js index a3c35e0..8526efc 100644 --- a/llm_normalizer/backend/dist/services/assistantService.js +++ b/llm_normalizer/backend/dist/services/assistantService.js @@ -66,6 +66,7 @@ const assistantCanon_1 = __importStar(require("./assistantCanon")); const assistantAddressAttemptRuntimeAdapter_1 = __importStar(require("./assistantAddressAttemptRuntimeAdapter")); const assistantCoverageGrounding_1 = __importStar(require("./assistantCoverageGrounding")); const assistantDataScopePolicy_1 = __importStar(require("./assistantDataScopePolicy")); +const assistantDebugPayloadAssembler_1 = __importStar(require("./assistantDebugPayloadAssembler")); const assistantDeepTurnAttemptRuntimeAdapter_1 = __importStar(require("./assistantDeepTurnAttemptRuntimeAdapter")); const assistantBoundaryPolicy_1 = __importStar(require("./assistantBoundaryPolicy")); const assistantLivingModePolicy_1 = __importStar(require("./assistantLivingModePolicy")); @@ -1385,151 +1386,23 @@ function cloneItems(items) { })); } function buildAddressCoverageReport() { - return { - requirements_total: 0, - requirements_covered: 0, - requirements_uncovered: [], - requirements_partially_covered: [], - clarification_needed_for: [], - out_of_scope_requirements: [] - }; + return (0, assistantDebugPayloadAssembler_1.buildEmptyCoverageReport)(); } function buildAssistantBackendErrorDebugPayload(errorMessage) { - return { - trace_id: `chat-${(0, nanoid_1.nanoid)(10)}`, - prompt_version: "assistant_backend_error_fallback_v1", - schema_version: "assistant_backend_error_fallback_v1", - fallback_type: "unknown", - route_summary: null, - fragments: [], - requirements_extracted: [], - coverage_report: buildAddressCoverageReport(), - routes: [], - retrieval_status: [], - retrieval_results: [], - answer_grounding_check: { - status: "no_grounded_answer", - route_subject_match: true, - missing_requirements: [], - reasons: [ - `backend_error:${String(errorMessage ?? "unknown_error").slice(0, 280)}` - ], - why_included_summary: [], - selection_reason_summary: [] - }, - dropped_intent_segments: [] - }; + return (0, assistantDebugPayloadAssembler_1.buildAssistantBackendErrorDebugPayload)({ + errorMessage, + traceIdFactory: () => `chat-${(0, nanoid_1.nanoid)(10)}` + }); } function buildAssistantBackendErrorReply() { return "Сейчас не удалось завершить разбор из-за внутренней ошибки контуров LLM. Могу продолжить в адресном режиме: проверить документы, договоры и операции по нужному периоду или контрагенту."; } function buildAddressDebugPayload(addressDebug, llmPreDecomposeMeta = null) { - const grounded = addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "grounded"; - const llmMeta = llmPreDecomposeMeta && typeof llmPreDecomposeMeta === "object" ? llmPreDecomposeMeta : null; - return { - trace_id: `address-${(0, nanoid_1.nanoid)(10)}`, - prompt_version: "address_query_runtime_v1", - schema_version: "address_query_runtime_v1", - fallback_type: addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "none", - route_summary: null, - fragments: [], - requirements_extracted: [], - coverage_report: buildAddressCoverageReport(), - routes: [], - retrieval_status: [], - retrieval_results: [], - answer_grounding_check: { - status: grounded, - route_subject_match: true, - missing_requirements: [], - reasons: addressDebug.reasons ?? [], - why_included_summary: [], - selection_reason_summary: [] - }, - dropped_intent_segments: [], - detected_mode: addressDebug.detected_mode, - detected_mode_confidence: addressDebug.detected_mode_confidence, - query_shape: addressDebug.query_shape, - query_shape_confidence: addressDebug.query_shape_confidence, - detected_intent: addressDebug.detected_intent, - detected_intent_confidence: addressDebug.detected_intent_confidence, - extracted_filters: addressDebug.extracted_filters, - missing_required_filters: addressDebug.missing_required_filters, - selected_recipe: addressDebug.selected_recipe, - mcp_call_status_legacy: addressDebug.mcp_call_status_legacy, - account_scope_mode: addressDebug.account_scope_mode, - account_scope_fallback_applied: addressDebug.account_scope_fallback_applied, - anchor_type: addressDebug.anchor_type, - anchor_value_raw: addressDebug.anchor_value_raw, - anchor_value_resolved: addressDebug.anchor_value_resolved, - resolver_confidence: addressDebug.resolver_confidence, - ambiguity_count: addressDebug.ambiguity_count, - match_failure_stage: addressDebug.match_failure_stage, - match_failure_reason: addressDebug.match_failure_reason, - mcp_call_status: addressDebug.mcp_call_status, - rows_fetched: addressDebug.rows_fetched, - raw_rows_received: addressDebug.raw_rows_received, - rows_after_account_scope: addressDebug.rows_after_account_scope, - rows_after_recipe_filter: addressDebug.rows_after_recipe_filter, - rows_materialized: addressDebug.rows_materialized, - rows_matched: addressDebug.rows_matched, - raw_row_keys_sample: addressDebug.raw_row_keys_sample, - materialization_drop_reason: addressDebug.materialization_drop_reason, - account_token_raw: addressDebug.account_token_raw, - account_token_normalized: addressDebug.account_token_normalized, - account_scope_fields_checked: addressDebug.account_scope_fields_checked, - account_scope_match_strategy: addressDebug.account_scope_match_strategy, - account_scope_drop_reason: addressDebug.account_scope_drop_reason, - runtime_readiness: addressDebug.runtime_readiness, - limited_reason_category: addressDebug.limited_reason_category, - organization_candidates: addressDebug.organization_candidates ?? undefined, - response_type: addressDebug.response_type, - requested_result_mode: addressDebug.requested_result_mode ?? undefined, - result_mode: addressDebug.result_mode ?? undefined, - evidence_strength: addressDebug.evidence_strength ?? undefined, - balance_confirmed: typeof addressDebug.balance_confirmed === "boolean" ? addressDebug.balance_confirmed : undefined, - as_of_date_basis: addressDebug.as_of_date_basis ?? undefined, - capability_id: addressDebug.capability_id ?? undefined, - capability_layer: addressDebug.capability_layer ?? undefined, - capability_route_mode: addressDebug.capability_route_mode ?? undefined, - capability_route_enabled: typeof addressDebug.capability_route_enabled === "boolean" ? addressDebug.capability_route_enabled : undefined, - capability_route_reason: addressDebug.capability_route_reason ?? undefined, - shadow_route_intent: addressDebug.shadow_route_intent ?? undefined, - shadow_route_selected_recipe: addressDebug.shadow_route_selected_recipe ?? undefined, - shadow_route_status: addressDebug.shadow_route_status ?? undefined, - route_expectation_status: addressDebug.route_expectation_status ?? undefined, - route_expectation_reason: addressDebug.route_expectation_reason ?? undefined, - route_expectation_expected_selected_recipes: addressDebug.route_expectation_expected_selected_recipes ?? undefined, - route_expectation_expected_requested_result_modes: addressDebug.route_expectation_expected_requested_result_modes ?? undefined, - route_expectation_expected_result_modes: addressDebug.route_expectation_expected_result_modes ?? undefined, - execution_lane: "address_query", - llm_decomposition_applied: Boolean(llmMeta?.applied), - llm_decomposition_attempted: Boolean(llmMeta?.attempted), - llm_provider_used: llmMeta?.provider ?? null, - llm_decomposition_trace_id: llmMeta?.traceId ?? null, - llm_decomposition_effective_message: llmMeta?.effectiveMessage ?? null, - llm_decomposition_reason: llmMeta?.reason ?? null, - llm_canonical_candidate_detected: Boolean(llmMeta?.llmCanonicalCandidateDetected), - llm_predecompose_contract: llmMeta?.predecomposeContract ?? null, - fallback_rule_hit: llmMeta?.fallbackRuleHit ?? null, - sanitized_user_message: llmMeta?.sanitizedUserMessage ?? null, - tool_gate_decision: llmMeta?.toolGateDecision ?? null, - tool_gate_reason: llmMeta?.toolGateReason ?? null, - orchestration_contract_v1: llmMeta?.orchestrationContract ?? null, - dialog_continuation_contract_v2: llmMeta?.dialogContinuationContract ?? null, - address_retry_audit: llmMeta?.addressRetryAudit ?? null, - answer_structure_v11: null, - investigation_state_snapshot: null, - normalized: null, - normalizer_output: llmMeta?.traceId - ? { - trace_id: llmMeta.traceId, - prompt_version: "normalizer_v2_0_2", - applied: Boolean(llmMeta?.applied), - effective_message: llmMeta?.effectiveMessage ?? null - } - : null - }; + return (0, assistantDebugPayloadAssembler_1.buildAddressRuntimeDebugPayload)({ + addressDebug, + llmPreDecomposeMeta, + traceIdFactory: () => `address-${(0, nanoid_1.nanoid)(10)}` + }); } function toNonEmptyString(value) { if (value === null || value === undefined) { diff --git a/llm_normalizer/backend/src/services/assistantDebugPayloadAssembler.ts b/llm_normalizer/backend/src/services/assistantDebugPayloadAssembler.ts index 1d658fa..24d4d15 100644 --- a/llm_normalizer/backend/src/services/assistantDebugPayloadAssembler.ts +++ b/llm_normalizer/backend/src/services/assistantDebugPayloadAssembler.ts @@ -98,6 +98,169 @@ function toAnalysisContext(input: DeepAnalysisDebugPayloadInput["runtimeAnalysis }; } +export function buildEmptyCoverageReport(): AssistantDebugPayload["coverage_report"] { + return { + requirements_total: 0, + requirements_covered: 0, + requirements_uncovered: [], + requirements_partially_covered: [], + clarification_needed_for: [], + out_of_scope_requirements: [] + }; +} + +export function buildAssistantBackendErrorDebugPayload(input: { + errorMessage: unknown; + traceIdFactory: () => string; +}): AssistantDebugPayload { + return { + trace_id: input.traceIdFactory(), + prompt_version: "assistant_backend_error_fallback_v1", + schema_version: "assistant_backend_error_fallback_v1", + fallback_type: "unknown", + route_summary: null, + fragments: [], + requirements_extracted: [], + coverage_report: buildEmptyCoverageReport(), + routes: [], + retrieval_status: [], + retrieval_results: [], + answer_grounding_check: { + status: "no_grounded_answer", + route_subject_match: true, + missing_requirements: [], + reasons: [`backend_error:${String(input.errorMessage ?? "unknown_error").slice(0, 280)}`], + why_included_summary: [], + selection_reason_summary: [] + }, + dropped_intent_segments: [], + answer_structure_v11: null, + investigation_state_snapshot: null, + normalized: null + } as unknown as AssistantDebugPayload; +} + +export function buildAddressRuntimeDebugPayload(input: { + addressDebug: Record; + llmPreDecomposeMeta?: Record | null; + traceIdFactory: () => string; +}): AssistantDebugPayload { + const grounded = input.addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "grounded"; + const llmMeta = + input.llmPreDecomposeMeta && typeof input.llmPreDecomposeMeta === "object" ? input.llmPreDecomposeMeta : null; + + return { + trace_id: input.traceIdFactory(), + prompt_version: "address_query_runtime_v1", + schema_version: "address_query_runtime_v1", + fallback_type: input.addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "none", + route_summary: null, + fragments: [], + requirements_extracted: [], + coverage_report: buildEmptyCoverageReport(), + routes: [], + retrieval_status: [], + retrieval_results: [], + answer_grounding_check: { + status: grounded, + route_subject_match: true, + missing_requirements: [], + reasons: input.addressDebug.reasons ?? [], + why_included_summary: [], + selection_reason_summary: [] + }, + dropped_intent_segments: [], + detected_mode: input.addressDebug.detected_mode, + detected_mode_confidence: input.addressDebug.detected_mode_confidence, + query_shape: input.addressDebug.query_shape, + query_shape_confidence: input.addressDebug.query_shape_confidence, + detected_intent: input.addressDebug.detected_intent, + detected_intent_confidence: input.addressDebug.detected_intent_confidence, + extracted_filters: input.addressDebug.extracted_filters, + missing_required_filters: input.addressDebug.missing_required_filters, + selected_recipe: input.addressDebug.selected_recipe, + mcp_call_status_legacy: input.addressDebug.mcp_call_status_legacy, + account_scope_mode: input.addressDebug.account_scope_mode, + account_scope_fallback_applied: input.addressDebug.account_scope_fallback_applied, + anchor_type: input.addressDebug.anchor_type, + anchor_value_raw: input.addressDebug.anchor_value_raw, + anchor_value_resolved: input.addressDebug.anchor_value_resolved, + resolver_confidence: input.addressDebug.resolver_confidence, + ambiguity_count: input.addressDebug.ambiguity_count, + match_failure_stage: input.addressDebug.match_failure_stage, + match_failure_reason: input.addressDebug.match_failure_reason, + mcp_call_status: input.addressDebug.mcp_call_status, + rows_fetched: input.addressDebug.rows_fetched, + raw_rows_received: input.addressDebug.raw_rows_received, + rows_after_account_scope: input.addressDebug.rows_after_account_scope, + rows_after_recipe_filter: input.addressDebug.rows_after_recipe_filter, + rows_materialized: input.addressDebug.rows_materialized, + rows_matched: input.addressDebug.rows_matched, + raw_row_keys_sample: input.addressDebug.raw_row_keys_sample, + materialization_drop_reason: input.addressDebug.materialization_drop_reason, + account_token_raw: input.addressDebug.account_token_raw, + account_token_normalized: input.addressDebug.account_token_normalized, + account_scope_fields_checked: input.addressDebug.account_scope_fields_checked, + account_scope_match_strategy: input.addressDebug.account_scope_match_strategy, + account_scope_drop_reason: input.addressDebug.account_scope_drop_reason, + runtime_readiness: input.addressDebug.runtime_readiness, + limited_reason_category: input.addressDebug.limited_reason_category, + organization_candidates: input.addressDebug.organization_candidates ?? undefined, + response_type: input.addressDebug.response_type, + requested_result_mode: input.addressDebug.requested_result_mode ?? undefined, + result_mode: input.addressDebug.result_mode ?? undefined, + evidence_strength: input.addressDebug.evidence_strength ?? undefined, + balance_confirmed: + typeof input.addressDebug.balance_confirmed === "boolean" ? input.addressDebug.balance_confirmed : undefined, + as_of_date_basis: input.addressDebug.as_of_date_basis ?? undefined, + capability_id: input.addressDebug.capability_id ?? undefined, + capability_layer: input.addressDebug.capability_layer ?? undefined, + capability_route_mode: input.addressDebug.capability_route_mode ?? undefined, + capability_route_enabled: + typeof input.addressDebug.capability_route_enabled === "boolean" + ? input.addressDebug.capability_route_enabled + : undefined, + capability_route_reason: input.addressDebug.capability_route_reason ?? undefined, + shadow_route_intent: input.addressDebug.shadow_route_intent ?? undefined, + shadow_route_selected_recipe: input.addressDebug.shadow_route_selected_recipe ?? undefined, + shadow_route_status: input.addressDebug.shadow_route_status ?? undefined, + route_expectation_status: input.addressDebug.route_expectation_status ?? undefined, + route_expectation_reason: input.addressDebug.route_expectation_reason ?? undefined, + route_expectation_expected_selected_recipes: + input.addressDebug.route_expectation_expected_selected_recipes ?? undefined, + route_expectation_expected_requested_result_modes: + input.addressDebug.route_expectation_expected_requested_result_modes ?? undefined, + route_expectation_expected_result_modes: input.addressDebug.route_expectation_expected_result_modes ?? undefined, + execution_lane: "address_query", + llm_decomposition_applied: Boolean(llmMeta?.applied), + llm_decomposition_attempted: Boolean(llmMeta?.attempted), + llm_provider_used: llmMeta?.provider ?? null, + llm_decomposition_trace_id: llmMeta?.traceId ?? null, + llm_decomposition_effective_message: llmMeta?.effectiveMessage ?? null, + llm_decomposition_reason: llmMeta?.reason ?? null, + llm_canonical_candidate_detected: Boolean(llmMeta?.llmCanonicalCandidateDetected), + llm_predecompose_contract: llmMeta?.predecomposeContract ?? null, + fallback_rule_hit: llmMeta?.fallbackRuleHit ?? null, + sanitized_user_message: llmMeta?.sanitizedUserMessage ?? null, + tool_gate_decision: llmMeta?.toolGateDecision ?? null, + tool_gate_reason: llmMeta?.toolGateReason ?? null, + orchestration_contract_v1: llmMeta?.orchestrationContract ?? null, + dialog_continuation_contract_v2: llmMeta?.dialogContinuationContract ?? null, + address_retry_audit: llmMeta?.addressRetryAudit ?? null, + answer_structure_v11: null, + investigation_state_snapshot: null, + normalized: null, + normalizer_output: llmMeta?.traceId + ? { + trace_id: llmMeta.traceId, + prompt_version: "normalizer_v2_0_2", + applied: Boolean(llmMeta?.applied), + effective_message: llmMeta?.effectiveMessage ?? null + } + : null + } as unknown as AssistantDebugPayload; +} + export function buildDeepAnalysisDebugPayload(input: DeepAnalysisDebugPayloadInput): AssistantDebugPayload { const analysisContext = toAnalysisContext(input.runtimeAnalysisContext); const answerContractStage4Audit = buildStage4AnswerContractAuditV1(input.assistantReply); diff --git a/llm_normalizer/backend/src/services/assistantService.ts b/llm_normalizer/backend/src/services/assistantService.ts index d1114de..df6923c 100644 --- a/llm_normalizer/backend/src/services/assistantService.ts +++ b/llm_normalizer/backend/src/services/assistantService.ts @@ -20,6 +20,7 @@ import * as assistantCanon_1 from "./assistantCanon"; import * as assistantAddressAttemptRuntimeAdapter_1 from "./assistantAddressAttemptRuntimeAdapter"; import * as assistantCoverageGrounding_1 from "./assistantCoverageGrounding"; import * as assistantDataScopePolicy_1 from "./assistantDataScopePolicy"; +import * as assistantDebugPayloadAssembler_1 from "./assistantDebugPayloadAssembler"; import * as assistantDeepTurnAttemptRuntimeAdapter_1 from "./assistantDeepTurnAttemptRuntimeAdapter"; import * as assistantBoundaryPolicy_1 from "./assistantBoundaryPolicy"; import * as assistantLivingModePolicy_1 from "./assistantLivingModePolicy"; @@ -1339,152 +1340,23 @@ function cloneItems(items) { })); } function buildAddressCoverageReport() { - return { - requirements_total: 0, - requirements_covered: 0, - requirements_uncovered: [], - requirements_partially_covered: [], - clarification_needed_for: [], - out_of_scope_requirements: [] - }; + return (0, assistantDebugPayloadAssembler_1.buildEmptyCoverageReport)(); } function buildAssistantBackendErrorDebugPayload(errorMessage) { - return { - trace_id: `chat-${(0, nanoid_1.nanoid)(10)}`, - prompt_version: "assistant_backend_error_fallback_v1", - schema_version: "assistant_backend_error_fallback_v1", - fallback_type: "unknown", - route_summary: null, - fragments: [], - requirements_extracted: [], - coverage_report: buildAddressCoverageReport(), - routes: [], - retrieval_status: [], - retrieval_results: [], - answer_grounding_check: { - status: "no_grounded_answer", - route_subject_match: true, - missing_requirements: [], - reasons: [ - `backend_error:${String(errorMessage ?? "unknown_error").slice(0, 280)}` - ], - why_included_summary: [], - selection_reason_summary: [] - }, - dropped_intent_segments: [] - }; + return (0, assistantDebugPayloadAssembler_1.buildAssistantBackendErrorDebugPayload)({ + errorMessage, + traceIdFactory: () => `chat-${(0, nanoid_1.nanoid)(10)}` + }); } function buildAssistantBackendErrorReply() { return "Сейчас не удалось завершить разбор из-за внутренней ошибки контуров LLM. Могу продолжить в адресном режиме: проверить документы, договоры и операции по нужному периоду или контрагенту."; } function buildAddressDebugPayload(addressDebug, llmPreDecomposeMeta = null) { - const grounded = addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "grounded"; - const llmMeta = llmPreDecomposeMeta && typeof llmPreDecomposeMeta === "object" ? llmPreDecomposeMeta : null; - return { - trace_id: `address-${(0, nanoid_1.nanoid)(10)}`, - prompt_version: "address_query_runtime_v1", - schema_version: "address_query_runtime_v1", - fallback_type: addressDebug.response_type === "LIMITED_WITH_REASON" ? "partial" : "none", - route_summary: null, - fragments: [], - requirements_extracted: [], - coverage_report: buildAddressCoverageReport(), - routes: [], - retrieval_status: [], - retrieval_results: [], - answer_grounding_check: { - status: grounded, - route_subject_match: true, - missing_requirements: [], - reasons: addressDebug.reasons ?? [], - why_included_summary: [], - selection_reason_summary: [] - }, - dropped_intent_segments: [], - detected_mode: addressDebug.detected_mode, - detected_mode_confidence: addressDebug.detected_mode_confidence, - query_shape: addressDebug.query_shape, - query_shape_confidence: addressDebug.query_shape_confidence, - detected_intent: addressDebug.detected_intent, - detected_intent_confidence: addressDebug.detected_intent_confidence, - extracted_filters: addressDebug.extracted_filters, - missing_required_filters: addressDebug.missing_required_filters, - selected_recipe: addressDebug.selected_recipe, - mcp_call_status_legacy: addressDebug.mcp_call_status_legacy, - account_scope_mode: addressDebug.account_scope_mode, - account_scope_fallback_applied: addressDebug.account_scope_fallback_applied, - anchor_type: addressDebug.anchor_type, - anchor_value_raw: addressDebug.anchor_value_raw, - anchor_value_resolved: addressDebug.anchor_value_resolved, - resolver_confidence: addressDebug.resolver_confidence, - ambiguity_count: addressDebug.ambiguity_count, - match_failure_stage: addressDebug.match_failure_stage, - match_failure_reason: addressDebug.match_failure_reason, - mcp_call_status: addressDebug.mcp_call_status, - rows_fetched: addressDebug.rows_fetched, - raw_rows_received: addressDebug.raw_rows_received, - rows_after_account_scope: addressDebug.rows_after_account_scope, - rows_after_recipe_filter: addressDebug.rows_after_recipe_filter, - rows_materialized: addressDebug.rows_materialized, - rows_matched: addressDebug.rows_matched, - raw_row_keys_sample: addressDebug.raw_row_keys_sample, - materialization_drop_reason: addressDebug.materialization_drop_reason, - account_token_raw: addressDebug.account_token_raw, - account_token_normalized: addressDebug.account_token_normalized, - account_scope_fields_checked: addressDebug.account_scope_fields_checked, - account_scope_match_strategy: addressDebug.account_scope_match_strategy, - account_scope_drop_reason: addressDebug.account_scope_drop_reason, - runtime_readiness: addressDebug.runtime_readiness, - limited_reason_category: addressDebug.limited_reason_category, - organization_candidates: addressDebug.organization_candidates ?? undefined, - response_type: addressDebug.response_type, - requested_result_mode: addressDebug.requested_result_mode ?? undefined, - result_mode: addressDebug.result_mode ?? undefined, - evidence_strength: addressDebug.evidence_strength ?? undefined, - balance_confirmed: typeof addressDebug.balance_confirmed === "boolean" ? addressDebug.balance_confirmed : undefined, - as_of_date_basis: addressDebug.as_of_date_basis ?? undefined, - capability_id: addressDebug.capability_id ?? undefined, - capability_layer: addressDebug.capability_layer ?? undefined, - capability_route_mode: addressDebug.capability_route_mode ?? undefined, - capability_route_enabled: typeof addressDebug.capability_route_enabled === "boolean" ? addressDebug.capability_route_enabled : undefined, - capability_route_reason: addressDebug.capability_route_reason ?? undefined, - shadow_route_intent: addressDebug.shadow_route_intent ?? undefined, - shadow_route_selected_recipe: addressDebug.shadow_route_selected_recipe ?? undefined, - shadow_route_status: addressDebug.shadow_route_status ?? undefined, - route_expectation_status: addressDebug.route_expectation_status ?? undefined, - route_expectation_reason: addressDebug.route_expectation_reason ?? undefined, - route_expectation_expected_selected_recipes: addressDebug.route_expectation_expected_selected_recipes ?? undefined, - route_expectation_expected_requested_result_modes: - addressDebug.route_expectation_expected_requested_result_modes ?? undefined, - route_expectation_expected_result_modes: addressDebug.route_expectation_expected_result_modes ?? undefined, - execution_lane: "address_query", - llm_decomposition_applied: Boolean(llmMeta?.applied), - llm_decomposition_attempted: Boolean(llmMeta?.attempted), - llm_provider_used: llmMeta?.provider ?? null, - llm_decomposition_trace_id: llmMeta?.traceId ?? null, - llm_decomposition_effective_message: llmMeta?.effectiveMessage ?? null, - llm_decomposition_reason: llmMeta?.reason ?? null, - llm_canonical_candidate_detected: Boolean(llmMeta?.llmCanonicalCandidateDetected), - llm_predecompose_contract: llmMeta?.predecomposeContract ?? null, - fallback_rule_hit: llmMeta?.fallbackRuleHit ?? null, - sanitized_user_message: llmMeta?.sanitizedUserMessage ?? null, - tool_gate_decision: llmMeta?.toolGateDecision ?? null, - tool_gate_reason: llmMeta?.toolGateReason ?? null, - orchestration_contract_v1: llmMeta?.orchestrationContract ?? null, - dialog_continuation_contract_v2: llmMeta?.dialogContinuationContract ?? null, - address_retry_audit: llmMeta?.addressRetryAudit ?? null, - answer_structure_v11: null, - investigation_state_snapshot: null, - normalized: null, - normalizer_output: llmMeta?.traceId - ? { - trace_id: llmMeta.traceId, - prompt_version: "normalizer_v2_0_2", - applied: Boolean(llmMeta?.applied), - effective_message: llmMeta?.effectiveMessage ?? null - } - : null - }; + return (0, assistantDebugPayloadAssembler_1.buildAddressRuntimeDebugPayload)({ + addressDebug, + llmPreDecomposeMeta, + traceIdFactory: () => `address-${(0, nanoid_1.nanoid)(10)}` + }); } function toNonEmptyString(value) { if (value === null || value === undefined) {