104 lines
4.2 KiB
TypeScript
104 lines
4.2 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
import { buildAssistantAddressOrchestrationRuntime } from "../src/services/assistantAddressOrchestrationRuntimeAdapter";
|
|
|
|
function buildInput(overrides: Record<string, unknown> = {}) {
|
|
const runAddressLlmPreDecompose = vi.fn(async () => ({
|
|
attempted: true,
|
|
applied: true,
|
|
effectiveMessage: "канон",
|
|
reason: "normalized_fragment_applied"
|
|
}));
|
|
const resolveAddressFollowupCarryoverContext = vi.fn(() => ({
|
|
followupContext: { id: "ctx" }
|
|
}));
|
|
const resolveAssistantOrchestrationDecision = vi.fn(() => ({
|
|
runAddressLane: true,
|
|
livingMode: "deep_analysis",
|
|
livingReason: "address_mode_classifier_detected",
|
|
toolGateDecision: "run_address_lane",
|
|
toolGateReason: "address_mode_classifier_detected",
|
|
orchestrationContract: { schema_version: "assistant_orchestration_contract_v1" }
|
|
}));
|
|
const buildAddressDialogContinuationContractV2 = vi.fn(() => ({
|
|
schema_version: "address_dialog_continuation_contract_v2"
|
|
}));
|
|
|
|
return {
|
|
userMessage: "сырой вопрос",
|
|
sessionItems: [],
|
|
llmProvider: "openai",
|
|
useMock: false,
|
|
featureAddressLlmPredecomposeV1: true,
|
|
runAddressLlmPreDecompose,
|
|
buildAddressLlmPredecomposeContractV1: () => ({ schema_version: "address_llm_predecompose_contract_v1" }),
|
|
sanitizeAddressMessageForFallback: () => "sanitized",
|
|
toNonEmptyString: (value: unknown) => {
|
|
if (typeof value !== "string") {
|
|
return null;
|
|
}
|
|
const trimmed = value.trim();
|
|
return trimmed.length > 0 ? trimmed : null;
|
|
},
|
|
resolveAddressFollowupCarryoverContext,
|
|
resolveAssistantOrchestrationDecision,
|
|
buildAddressDialogContinuationContractV2,
|
|
__spies: {
|
|
runAddressLlmPreDecompose,
|
|
resolveAddressFollowupCarryoverContext,
|
|
resolveAssistantOrchestrationDecision,
|
|
buildAddressDialogContinuationContractV2
|
|
},
|
|
...overrides
|
|
} as any;
|
|
}
|
|
|
|
describe("assistant address orchestration runtime adapter", () => {
|
|
it("uses llm predecompose payload when feature is enabled", async () => {
|
|
const input = buildInput();
|
|
|
|
const output = await buildAssistantAddressOrchestrationRuntime(input);
|
|
|
|
expect(output.addressPreDecompose.reason).toBe("normalized_fragment_applied");
|
|
expect(output.addressInputMessage).toBe("канон");
|
|
expect(output.orchestrationDecision.runAddressLane).toBe(true);
|
|
expect(output.livingModeDecision.mode).toBe("deep_analysis");
|
|
expect(output.addressRuntimeMeta.toolGateDecision).toBe("run_address_lane");
|
|
expect(output.addressRuntimeMeta.dialogContinuationContract).toEqual({
|
|
schema_version: "address_dialog_continuation_contract_v2"
|
|
});
|
|
expect(input.__spies.runAddressLlmPreDecompose).toHaveBeenCalledTimes(1);
|
|
expect(input.__spies.resolveAddressFollowupCarryoverContext).toHaveBeenCalledTimes(1);
|
|
expect(input.__spies.resolveAssistantOrchestrationDecision).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("builds deterministic fallback predecompose payload when feature is disabled", async () => {
|
|
const input = buildInput({
|
|
featureAddressLlmPredecomposeV1: false,
|
|
llmProvider: "local",
|
|
runAddressLlmPreDecompose: vi.fn(async () => {
|
|
throw new Error("must not be called");
|
|
}),
|
|
resolveAssistantOrchestrationDecision: vi.fn(() => ({
|
|
runAddressLane: false,
|
|
livingMode: "chat",
|
|
livingReason: "predecompose_unsupported_mode",
|
|
toolGateDecision: "skip_address_lane",
|
|
toolGateReason: "llm_predecompose_unsupported_mode",
|
|
orchestrationContract: { schema_version: "assistant_orchestration_contract_v1" }
|
|
}))
|
|
});
|
|
|
|
const output = await buildAssistantAddressOrchestrationRuntime(input);
|
|
|
|
expect(output.addressPreDecompose.attempted).toBe(false);
|
|
expect(output.addressPreDecompose.applied).toBe(false);
|
|
expect(output.addressPreDecompose.provider).toBe("local");
|
|
expect(output.addressPreDecompose.reason).toBe("disabled_by_feature_flag");
|
|
expect(output.addressPreDecompose.sanitizedUserMessage).toBe("sanitized");
|
|
expect(output.addressInputMessage).toBe("сырой вопрос");
|
|
expect(output.livingModeDecision.mode).toBe("chat");
|
|
expect(output.addressRuntimeMeta.toolGateDecision).toBe("skip_address_lane");
|
|
});
|
|
});
|
|
|