АРЧ АП11 - Вынести provider runtime policy из оркестрации и закрыть Phase 6 агентным прогоном

This commit is contained in:
2026-04-17 12:02:38 +03:00
parent 15fa643fc8
commit f5ff844105
16 changed files with 647 additions and 52 deletions
@@ -2,6 +2,7 @@
export interface ResolveLivingAssistantModeDecisionInput {
userMessage?: unknown;
addressLaneTriggered?: boolean;
llmProvider?: unknown;
useMock?: boolean;
predecomposeMode?: unknown;
predecomposeModeConfidence?: unknown;
@@ -17,6 +18,14 @@ export interface AssistantLivingModePolicyDeps {
hasSmallTalkSignal: (text: string) => boolean;
hasAssistantCapabilityQuestionSignal: (text: string) => boolean;
hasOperationalAdminActionRequestSignal: (text: string) => boolean;
resolveProviderExecutionState: (input: {
llmProvider?: unknown;
useMock?: unknown;
llmPreDecomposeReason?: unknown;
}) => {
living_mode_forced_deep: boolean;
living_mode_forced_reason: string | null;
};
}
export interface AssistantLivingModeDecision {
@@ -49,7 +58,8 @@ export function createAssistantLivingModePolicy(deps: AssistantLivingModePolicyD
hasReferentialPointer,
hasSmallTalkSignal,
hasAssistantCapabilityQuestionSignal,
hasOperationalAdminActionRequestSignal
hasOperationalAdminActionRequestSignal,
resolveProviderExecutionState
} = deps;
function hasStrongDataIntentSignal(text) {
@@ -328,10 +338,14 @@ export function createAssistantLivingModePolicy(deps: AssistantLivingModePolicyD
reason: "living_chat_router_disabled"
};
}
if (Boolean(input?.useMock)) {
const providerExecution = resolveProviderExecutionState({
llmProvider: input?.llmProvider,
useMock: input?.useMock
});
if (providerExecution.living_mode_forced_deep) {
return {
mode: "deep_analysis",
reason: "mock_mode_keeps_deep_pipeline"
reason: providerExecution.living_mode_forced_reason ?? "mock_mode_keeps_deep_pipeline"
};
}
if (hasAssistantDataScopeMetaQuestionSignal(userMessage)) {
@@ -0,0 +1,92 @@
export const ASSISTANT_PROVIDER_EXECUTION_CONTRACT_SCHEMA_VERSION =
"assistant_provider_execution_contract_v1" as const;
export interface ResolveAssistantProviderExecutionInput {
llmProvider?: unknown;
useMock?: unknown;
baseUrl?: unknown;
llmPreDecomposeReason?: unknown;
}
export interface AssistantProviderExecutionContract {
schema_version: typeof ASSISTANT_PROVIDER_EXECUTION_CONTRACT_SCHEMA_VERSION;
policy_owner: "assistantProviderExecutionPolicy";
provider_mode: "mock" | "openai" | "local" | "unknown";
normalized_provider: "openai" | "local" | null;
use_mock: boolean;
base_url_configured: boolean;
llm_runtime_unavailable_detected: boolean;
living_mode_forced_deep: boolean;
living_mode_forced_reason: string | null;
reason_codes: string[];
}
export interface AssistantProviderExecutionPolicy {
normalizeProvider: (value: unknown) => "openai" | "local" | null;
detectLlmRuntimeUnavailable: (reason: unknown) => boolean;
resolveProviderExecutionState: (
input: ResolveAssistantProviderExecutionInput
) => AssistantProviderExecutionContract;
}
export function createAssistantProviderExecutionPolicy(): AssistantProviderExecutionPolicy {
function normalizeProvider(value: unknown): "openai" | "local" | null {
return value === "local" ? "local" : value === "openai" ? "openai" : null;
}
function detectLlmRuntimeUnavailable(reason: unknown): boolean {
const source = String(reason ?? "").trim();
if (!source) {
return false;
}
return /(?:openai\s+api\s+key\s+is\s+missing|api\s+key\s+is\s+missing|missing\s+api\s+key|authentication|unauthoriz(?:ed|ation)|401\b)/iu.test(
source
);
}
function resolveProviderExecutionState(
input: ResolveAssistantProviderExecutionInput
): AssistantProviderExecutionContract {
const normalizedProvider = normalizeProvider(input?.llmProvider);
const useMock = Boolean(input?.useMock);
const baseUrlConfigured = String(input?.baseUrl ?? "").trim().length > 0;
const llmRuntimeUnavailableDetected = detectLlmRuntimeUnavailable(input?.llmPreDecomposeReason);
const reasonCodes: string[] = [];
if (useMock) {
reasonCodes.push("mock_mode_enabled");
}
if (normalizedProvider === "local") {
reasonCodes.push("provider_local");
} else if (normalizedProvider === "openai") {
reasonCodes.push("provider_openai");
} else {
reasonCodes.push("provider_unknown");
}
if (baseUrlConfigured) {
reasonCodes.push("base_url_configured");
}
if (llmRuntimeUnavailableDetected) {
reasonCodes.push("llm_runtime_unavailable");
}
return {
schema_version: ASSISTANT_PROVIDER_EXECUTION_CONTRACT_SCHEMA_VERSION,
policy_owner: "assistantProviderExecutionPolicy",
provider_mode: useMock ? "mock" : normalizedProvider ?? "unknown",
normalized_provider: normalizedProvider,
use_mock: useMock,
base_url_configured: baseUrlConfigured,
llm_runtime_unavailable_detected: llmRuntimeUnavailableDetected,
living_mode_forced_deep: useMock,
living_mode_forced_reason: useMock ? "mock_mode_keeps_deep_pipeline" : null,
reason_codes: reasonCodes
};
}
return {
normalizeProvider,
detectLlmRuntimeUnavailable,
resolveProviderExecutionState
};
}
@@ -78,7 +78,8 @@ export function createAssistantRoutePolicy(deps) {
hasDirectDeepAnalysisSignal,
compactWhitespace,
hasDeepSessionContinuationSignal,
resolveLivingAssistantModeDecision
resolveLivingAssistantModeDecision,
resolveProviderExecutionState
} = deps;
function resolveAssistantOrchestrationDecision(input) {
const rawUserMessage = String(input?.rawUserMessage ?? input?.userMessage ?? "");
@@ -144,8 +145,11 @@ export function createAssistantRoutePolicy(deps) {
const resolvedIntentResolution = intentResolution.intent !== "unknown" ? intentResolution : intentResolutionRaw;
const llmContractIntent = toNonEmptyString(llmPreDecomposeMeta?.predecomposeContract?.intent);
const llmPreDecomposeReason = toNonEmptyString(llmPreDecomposeMeta?.reason);
const llmRuntimeUnavailableDetected = Boolean(llmPreDecomposeReason &&
/(?:openai\s+api\s+key\s+is\s+missing|api\s+key\s+is\s+missing|missing\s+api\s+key|authentication)/iu.test(llmPreDecomposeReason));
const providerExecution = resolveProviderExecutionState({
useMock,
llmPreDecomposeReason
});
const llmRuntimeUnavailableDetected = providerExecution.llm_runtime_unavailable_detected === true;
const semanticExtractionContract = llmPreDecomposeMeta?.semanticExtractionContract &&
typeof llmPreDecomposeMeta.semanticExtractionContract === "object"
? llmPreDecomposeMeta.semanticExtractionContract
@@ -257,6 +261,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: "data_scope",
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -286,6 +291,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: "capability",
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -313,6 +319,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: "capability",
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -342,6 +349,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: "non_domain",
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -369,6 +377,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: "non_domain",
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -540,6 +549,7 @@ export function createAssistantRoutePolicy(deps) {
let livingDecision = resolveLivingAssistantModeDecision({
userMessage: rawUserMessage,
addressLaneTriggered: runAddressLane,
llmProvider: providerExecution.normalized_provider,
useMock,
predecomposeMode: llmPreDecomposeMeta?.predecomposeContract?.mode ?? null,
predecomposeModeConfidence: llmPreDecomposeMeta?.predecomposeContract?.mode_confidence ?? null
@@ -585,6 +595,7 @@ export function createAssistantRoutePolicy(deps) {
orchestrationContract: {
schema_version: "assistant_orchestration_contract_v1",
hard_meta_mode: null,
provider_execution: providerExecution,
address_mode: resolvedModeDetection.mode,
address_mode_confidence: resolvedModeDetection.confidence,
address_intent: resolvedIntentResolution.intent,
@@ -24,6 +24,7 @@ import * as assistantBoundaryPolicy_1 from "./assistantBoundaryPolicy";
import * as assistantLivingModePolicy_1 from "./assistantLivingModePolicy";
import * as assistantMetaFollowupPolicy_1 from "./assistantMetaFollowupPolicy";
import * as assistantMemoryRecapPolicy_1 from "./assistantMemoryRecapPolicy";
import * as assistantProviderExecutionPolicy_1 from "./assistantProviderExecutionPolicy";
import * as assistantRoutePolicy_1 from "./assistantRoutePolicy";
import * as assistantTransitionPolicy_1 from "./assistantTransitionPolicy";
import * as assistantOrganizationScopeRuntimeAdapter_1 from "./assistantOrganizationScopeRuntimeAdapter";
@@ -3781,6 +3782,8 @@ function hasPredecomposeDiagnosticUncertaintyLead(text) {
return /^(?:неясно|не\s+ясно|непонятно|не\s+понятно|unclear|not\s+clear|ambiguous|unknown)(?=$|[\s,.;:!?])/iu.test(normalized);
}
function attachAddressPredecomposeContract(meta, sourceMessage) {
const sourceMeta = meta && typeof meta === "object" ? meta : {};
const { providerExecutionInput, providerExecutionContract: providerExecutionContractInput, ...restMeta } = sourceMeta;
const canonicalMessage = toNonEmptyString(meta?.effectiveMessage) ?? String(sourceMessage ?? "");
const predecomposeContract = (0, predecomposeContract_1.buildAddressLlmPredecomposeContractV1)({
sourceMessage: String(sourceMessage ?? ""),
@@ -3792,20 +3795,34 @@ function attachAddressPredecomposeContract(meta, sourceMessage) {
canonicalMessage,
predecomposeContract
});
const providerExecutionContract = providerExecutionContractInput && typeof providerExecutionContractInput === "object"
? providerExecutionContractInput
: assistantProviderExecutionPolicy.resolveProviderExecutionState({
llmProvider: providerExecutionInput?.llmProvider,
useMock: providerExecutionInput?.useMock,
baseUrl: providerExecutionInput?.baseUrl,
llmPreDecomposeReason: restMeta?.reason
});
return {
...meta,
...restMeta,
providerExecutionContract,
predecomposeContract,
semanticExtractionContract
};
}
async function runAddressLlmPreDecompose(normalizerService, payload, userMessage) {
const provider = payload?.llmProvider === "local" ? "local" : payload?.llmProvider === "openai" ? "openai" : null;
const provider = assistantProviderExecutionPolicy.normalizeProvider(payload?.llmProvider);
const sanitizedUserMessage = sanitizeAddressMessageForFallback(userMessage);
const fallbackCandidate = resolveAddressDeterministicFallback(userMessage, sanitizedUserMessage);
const baseMeta = {
attempted: false,
applied: false,
provider,
providerExecutionInput: {
llmProvider: payload?.llmProvider,
useMock: payload?.useMock,
baseUrl: payload?.baseUrl
},
traceId: null,
effectiveMessage: userMessage,
reason: "not_attempted",
@@ -4705,6 +4722,7 @@ function normalizeOrganizationScopeValue(value) {
.trim();
return unwrapped ? unwrapped : null;
}
const assistantProviderExecutionPolicy = (0, assistantProviderExecutionPolicy_1.createAssistantProviderExecutionPolicy)();
const assistantLivingModePolicy = (0, assistantLivingModePolicy_1.createAssistantLivingModePolicy)({
featureAssistantLivingChatRouterV1: config_1.FEATURE_ASSISTANT_LIVING_CHAT_ROUTER_V1,
compactWhitespace,
@@ -4714,7 +4732,8 @@ const assistantLivingModePolicy = (0, assistantLivingModePolicy_1.createAssistan
hasReferentialPointer,
hasSmallTalkSignal,
hasAssistantCapabilityQuestionSignal,
hasOperationalAdminActionRequestSignal
hasOperationalAdminActionRequestSignal,
resolveProviderExecutionState: assistantProviderExecutionPolicy.resolveProviderExecutionState
});
const assistantMetaFollowupPolicy = (0, assistantMetaFollowupPolicy_1.createAssistantMetaFollowupPolicy)({
hasAssistantDataScopeMetaQuestionSignal: assistantLivingModePolicy.hasAssistantDataScopeMetaQuestionSignal,
@@ -4760,7 +4779,8 @@ const assistantRoutePolicy = (0, assistantRoutePolicy_1.createAssistantRoutePoli
hasDirectDeepAnalysisSignal,
compactWhitespace,
hasDeepSessionContinuationSignal,
resolveLivingAssistantModeDecision: assistantLivingModePolicy.resolveLivingAssistantModeDecision
resolveLivingAssistantModeDecision: assistantLivingModePolicy.resolveLivingAssistantModeDecision,
resolveProviderExecutionState: assistantProviderExecutionPolicy.resolveProviderExecutionState
});
const assistantTransitionPolicy = (0, assistantTransitionPolicy_1.createAssistantTransitionPolicy)({
compactWhitespace,