АРЧ АП11 - Выделить route policy adapter для архитектуры assistant runtime
This commit is contained in:
parent
1d95ed9b60
commit
9d5928125d
|
|
@ -1,6 +1,7 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.buildAssistantAddressOrchestrationRuntime = buildAssistantAddressOrchestrationRuntime;
|
||||
const assistantRoutePolicyRuntimeAdapter_1 = require("./assistantRoutePolicyRuntimeAdapter");
|
||||
function hasSelectedObjectInventorySignal(text) {
|
||||
return /(?:по\s+выбранному\s+объекту|по\s+этой\s+позиции|по\s+этому\s+товару|selected\s+object)/iu.test(String(text ?? ""));
|
||||
}
|
||||
|
|
@ -78,26 +79,25 @@ async function buildAssistantAddressOrchestrationRuntime(input) {
|
|||
carryover = input.resolveAddressFollowupCarryoverContext(input.userMessage, input.sessionItems, addressInputMessage, addressPreDecompose, input.sessionAddressNavigationState);
|
||||
}
|
||||
const followupContext = carryover?.followupContext ?? null;
|
||||
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
|
||||
const routePolicyRuntime = (0, assistantRoutePolicyRuntimeAdapter_1.runAssistantRoutePolicyRuntime)({
|
||||
rawUserMessage: input.userMessage,
|
||||
effectiveAddressUserMessage: addressInputMessage,
|
||||
followupContext,
|
||||
llmPreDecomposeMeta: addressPreDecompose,
|
||||
sessionItems: input.sessionItems,
|
||||
sessionOrganizationScope: input.sessionOrganizationScope ?? null,
|
||||
useMock: input.useMock
|
||||
useMock: input.useMock,
|
||||
resolveAssistantOrchestrationDecision: input.resolveAssistantOrchestrationDecision
|
||||
});
|
||||
const orchestrationDecision = routePolicyRuntime.orchestrationDecision;
|
||||
const dialogContinuationContract = input.buildAddressDialogContinuationContractV2(input.userMessage, addressInputMessage, carryover, addressPreDecompose);
|
||||
const addressRuntimeMeta = {
|
||||
...addressPreDecompose,
|
||||
toolGateDecision: orchestrationDecision.toolGateDecision ?? null,
|
||||
toolGateReason: orchestrationDecision.toolGateReason ?? null,
|
||||
dialogContinuationContract,
|
||||
orchestrationContract: orchestrationDecision.orchestrationContract ?? null
|
||||
};
|
||||
const livingModeDecision = {
|
||||
mode: orchestrationDecision.livingMode,
|
||||
reason: orchestrationDecision.livingReason
|
||||
orchestrationContract: orchestrationDecision.orchestrationContract ?? null,
|
||||
routePolicyContract: routePolicyRuntime.routePolicyContract
|
||||
};
|
||||
return {
|
||||
addressPreDecompose,
|
||||
|
|
@ -105,6 +105,6 @@ async function buildAssistantAddressOrchestrationRuntime(input) {
|
|||
carryover,
|
||||
orchestrationDecision,
|
||||
addressRuntimeMeta,
|
||||
livingModeDecision
|
||||
livingModeDecision: routePolicyRuntime.livingModeDecision
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION = void 0;
|
||||
exports.runAssistantRoutePolicyRuntime = runAssistantRoutePolicyRuntime;
|
||||
exports.ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION = "assistant_route_policy_runtime_v1";
|
||||
function hasObject(value) {
|
||||
return Boolean(value && typeof value === "object");
|
||||
}
|
||||
function runAssistantRoutePolicyRuntime(input) {
|
||||
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: input.rawUserMessage,
|
||||
effectiveAddressUserMessage: input.effectiveAddressUserMessage,
|
||||
followupContext: input.followupContext,
|
||||
llmPreDecomposeMeta: input.llmPreDecomposeMeta,
|
||||
sessionItems: input.sessionItems,
|
||||
sessionOrganizationScope: input.sessionOrganizationScope,
|
||||
useMock: input.useMock
|
||||
});
|
||||
const livingModeDecision = {
|
||||
mode: orchestrationDecision.livingMode,
|
||||
reason: orchestrationDecision.livingReason
|
||||
};
|
||||
return {
|
||||
orchestrationDecision,
|
||||
livingModeDecision,
|
||||
routePolicyContract: {
|
||||
schema_version: exports.ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION,
|
||||
policy_owner: "assistantRoutePolicyRuntimeAdapter",
|
||||
decision_source: "resolveAssistantOrchestrationDecision",
|
||||
living_mode: livingModeDecision.mode,
|
||||
living_reason: livingModeDecision.reason,
|
||||
tool_gate_decision: orchestrationDecision.toolGateDecision ?? null,
|
||||
tool_gate_reason: orchestrationDecision.toolGateReason ?? null,
|
||||
has_followup_context: hasObject(input.followupContext),
|
||||
has_orchestration_contract: hasObject(orchestrationDecision.orchestrationContract)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { runAssistantRoutePolicyRuntime } from "./assistantRoutePolicyRuntimeAdapter";
|
||||
|
||||
export interface BuildAssistantAddressOrchestrationRuntimeInput {
|
||||
userMessage: string;
|
||||
sessionItems: unknown[];
|
||||
|
|
@ -195,15 +197,17 @@ export async function buildAssistantAddressOrchestrationRuntime(
|
|||
}
|
||||
|
||||
const followupContext = carryover?.followupContext ?? null;
|
||||
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
|
||||
const routePolicyRuntime = runAssistantRoutePolicyRuntime({
|
||||
rawUserMessage: input.userMessage,
|
||||
effectiveAddressUserMessage: addressInputMessage,
|
||||
followupContext,
|
||||
llmPreDecomposeMeta: addressPreDecompose,
|
||||
sessionItems: input.sessionItems,
|
||||
sessionOrganizationScope: input.sessionOrganizationScope ?? null,
|
||||
useMock: input.useMock
|
||||
useMock: input.useMock,
|
||||
resolveAssistantOrchestrationDecision: input.resolveAssistantOrchestrationDecision
|
||||
});
|
||||
const orchestrationDecision = routePolicyRuntime.orchestrationDecision;
|
||||
const dialogContinuationContract = input.buildAddressDialogContinuationContractV2(
|
||||
input.userMessage,
|
||||
addressInputMessage,
|
||||
|
|
@ -215,11 +219,8 @@ export async function buildAssistantAddressOrchestrationRuntime(
|
|||
toolGateDecision: orchestrationDecision.toolGateDecision ?? null,
|
||||
toolGateReason: orchestrationDecision.toolGateReason ?? null,
|
||||
dialogContinuationContract,
|
||||
orchestrationContract: orchestrationDecision.orchestrationContract ?? null
|
||||
};
|
||||
const livingModeDecision = {
|
||||
mode: orchestrationDecision.livingMode,
|
||||
reason: orchestrationDecision.livingReason
|
||||
orchestrationContract: orchestrationDecision.orchestrationContract ?? null,
|
||||
routePolicyContract: routePolicyRuntime.routePolicyContract
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
@ -228,6 +229,6 @@ export async function buildAssistantAddressOrchestrationRuntime(
|
|||
carryover,
|
||||
orchestrationDecision,
|
||||
addressRuntimeMeta,
|
||||
livingModeDecision
|
||||
livingModeDecision: routePolicyRuntime.livingModeDecision
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
export const ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION = "assistant_route_policy_runtime_v1" as const;
|
||||
|
||||
export interface RunAssistantRoutePolicyRuntimeInput {
|
||||
rawUserMessage: string;
|
||||
effectiveAddressUserMessage: string;
|
||||
followupContext: unknown;
|
||||
llmPreDecomposeMeta: Record<string, unknown>;
|
||||
sessionItems?: unknown[];
|
||||
sessionOrganizationScope?: unknown;
|
||||
useMock: boolean;
|
||||
resolveAssistantOrchestrationDecision: (input: {
|
||||
rawUserMessage: string;
|
||||
effectiveAddressUserMessage: string;
|
||||
followupContext: unknown;
|
||||
llmPreDecomposeMeta: Record<string, unknown>;
|
||||
sessionItems?: unknown[];
|
||||
sessionOrganizationScope?: unknown;
|
||||
useMock: boolean;
|
||||
}) => Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AssistantRoutePolicyRuntimeContract {
|
||||
schema_version: typeof ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION;
|
||||
policy_owner: "assistantRoutePolicyRuntimeAdapter";
|
||||
decision_source: "resolveAssistantOrchestrationDecision";
|
||||
living_mode: unknown;
|
||||
living_reason: unknown;
|
||||
tool_gate_decision: unknown;
|
||||
tool_gate_reason: unknown;
|
||||
has_followup_context: boolean;
|
||||
has_orchestration_contract: boolean;
|
||||
}
|
||||
|
||||
export interface RunAssistantRoutePolicyRuntimeOutput {
|
||||
orchestrationDecision: Record<string, unknown>;
|
||||
livingModeDecision: {
|
||||
mode: unknown;
|
||||
reason: unknown;
|
||||
};
|
||||
routePolicyContract: AssistantRoutePolicyRuntimeContract;
|
||||
}
|
||||
|
||||
function hasObject(value: unknown): boolean {
|
||||
return Boolean(value && typeof value === "object");
|
||||
}
|
||||
|
||||
export function runAssistantRoutePolicyRuntime(
|
||||
input: RunAssistantRoutePolicyRuntimeInput
|
||||
): RunAssistantRoutePolicyRuntimeOutput {
|
||||
const orchestrationDecision = input.resolveAssistantOrchestrationDecision({
|
||||
rawUserMessage: input.rawUserMessage,
|
||||
effectiveAddressUserMessage: input.effectiveAddressUserMessage,
|
||||
followupContext: input.followupContext,
|
||||
llmPreDecomposeMeta: input.llmPreDecomposeMeta,
|
||||
sessionItems: input.sessionItems,
|
||||
sessionOrganizationScope: input.sessionOrganizationScope,
|
||||
useMock: input.useMock
|
||||
});
|
||||
const livingModeDecision = {
|
||||
mode: orchestrationDecision.livingMode,
|
||||
reason: orchestrationDecision.livingReason
|
||||
};
|
||||
|
||||
return {
|
||||
orchestrationDecision,
|
||||
livingModeDecision,
|
||||
routePolicyContract: {
|
||||
schema_version: ASSISTANT_ROUTE_POLICY_RUNTIME_SCHEMA_VERSION,
|
||||
policy_owner: "assistantRoutePolicyRuntimeAdapter",
|
||||
decision_source: "resolveAssistantOrchestrationDecision",
|
||||
living_mode: livingModeDecision.mode,
|
||||
living_reason: livingModeDecision.reason,
|
||||
tool_gate_decision: orchestrationDecision.toolGateDecision ?? null,
|
||||
tool_gate_reason: orchestrationDecision.toolGateReason ?? null,
|
||||
has_followup_context: hasObject(input.followupContext),
|
||||
has_orchestration_contract: hasObject(orchestrationDecision.orchestrationContract)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -63,6 +63,16 @@ describe("assistant address orchestration runtime adapter", () => {
|
|||
expect(output.orchestrationDecision.runAddressLane).toBe(true);
|
||||
expect(output.livingModeDecision.mode).toBe("deep_analysis");
|
||||
expect(output.addressRuntimeMeta.toolGateDecision).toBe("run_address_lane");
|
||||
expect(output.addressRuntimeMeta.routePolicyContract).toEqual(
|
||||
expect.objectContaining({
|
||||
schema_version: "assistant_route_policy_runtime_v1",
|
||||
policy_owner: "assistantRoutePolicyRuntimeAdapter",
|
||||
living_mode: "deep_analysis",
|
||||
tool_gate_decision: "run_address_lane",
|
||||
has_followup_context: true,
|
||||
has_orchestration_contract: true
|
||||
})
|
||||
);
|
||||
expect(output.addressRuntimeMeta.dialogContinuationContract).toEqual({
|
||||
schema_version: "address_dialog_continuation_contract_v2"
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { runAssistantRoutePolicyRuntime } from "../src/services/assistantRoutePolicyRuntimeAdapter";
|
||||
|
||||
describe("assistant route policy runtime adapter", () => {
|
||||
it("delegates to the current orchestration decision function and emits a route policy contract", () => {
|
||||
const resolveAssistantOrchestrationDecision = vi.fn(() => ({
|
||||
runAddressLane: true,
|
||||
livingMode: "address_data",
|
||||
livingReason: "address_lane_triggered",
|
||||
toolGateDecision: "run_address_lane",
|
||||
toolGateReason: "followup_context_detected",
|
||||
orchestrationContract: {
|
||||
schema_version: "assistant_orchestration_contract_v1"
|
||||
}
|
||||
}));
|
||||
const followupContext = { previous_intent: "inventory_on_hand_as_of_date" };
|
||||
|
||||
const output = runAssistantRoutePolicyRuntime({
|
||||
rawUserMessage: "кто это поставил нам",
|
||||
effectiveAddressUserMessage: "кто это поставил нам",
|
||||
followupContext,
|
||||
llmPreDecomposeMeta: {
|
||||
attempted: true
|
||||
},
|
||||
sessionItems: [{ role: "assistant" }],
|
||||
sessionOrganizationScope: {
|
||||
selectedOrganization: "ООО Ромашка"
|
||||
},
|
||||
useMock: false,
|
||||
resolveAssistantOrchestrationDecision
|
||||
});
|
||||
|
||||
expect(resolveAssistantOrchestrationDecision).toHaveBeenCalledWith({
|
||||
rawUserMessage: "кто это поставил нам",
|
||||
effectiveAddressUserMessage: "кто это поставил нам",
|
||||
followupContext,
|
||||
llmPreDecomposeMeta: {
|
||||
attempted: true
|
||||
},
|
||||
sessionItems: [{ role: "assistant" }],
|
||||
sessionOrganizationScope: {
|
||||
selectedOrganization: "ООО Ромашка"
|
||||
},
|
||||
useMock: false
|
||||
});
|
||||
expect(output.orchestrationDecision.runAddressLane).toBe(true);
|
||||
expect(output.livingModeDecision).toEqual({
|
||||
mode: "address_data",
|
||||
reason: "address_lane_triggered"
|
||||
});
|
||||
expect(output.routePolicyContract).toEqual({
|
||||
schema_version: "assistant_route_policy_runtime_v1",
|
||||
policy_owner: "assistantRoutePolicyRuntimeAdapter",
|
||||
decision_source: "resolveAssistantOrchestrationDecision",
|
||||
living_mode: "address_data",
|
||||
living_reason: "address_lane_triggered",
|
||||
tool_gate_decision: "run_address_lane",
|
||||
tool_gate_reason: "followup_context_detected",
|
||||
has_followup_context: true,
|
||||
has_orchestration_contract: true
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue