NODEDC_1C/llm_normalizer/backend/tests/assistantTurnRuntimeDepsAda...

218 lines
7.2 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { buildAssistantTurnRuntimeDeps } from "../src/services/assistantTurnRuntimeDepsAdapter";
describe("assistant turn runtime deps adapter", () => {
it("builds runtime deps with service wrappers and static flags/defaults", async () => {
const sessions = {
ensureSession: vi.fn(() => ({ session_id: "asst-1" })),
appendItem: vi.fn(),
getSession: vi.fn(() => ({ session_id: "asst-1" })),
setInvestigationState: vi.fn()
};
const sessionLogger = {
persistSession: vi.fn()
};
const normalizerService = {
normalize: vi.fn(async () => ({ trace_id: "trace-1" }))
};
const dataLayer = {
executeRouteRuntime: vi.fn(async () => ({ status: "ok" }))
};
const addressQueryService = {
tryHandle: vi.fn(async () => ({ response_type: "READY" }))
};
const logEvent = vi.fn();
const helperFn = vi.fn(() => "ok");
const deps = buildAssistantTurnRuntimeDeps({
sessions,
sessionLogger,
normalizerService,
dataLayer,
addressQueryService,
chatClient: { kind: "chat" },
messageIdFactory: () => "msg-1",
nowIso: () => "2026-04-11T00:00:00.000Z",
defaultApiKey: "api-key",
logEvent,
flags: {
featureAssistantAddressQueryV1: true,
featureAddressLlmPredecomposeV1: true,
featureInvestigationStateV1: true,
featureStateFollowupBindingV1: false,
featureContractsV11: true,
featureAnswerPolicyV11: true,
featureProblemCentricAnswerV1: true,
featureLifecycleAnswerV1: false
},
defaults: {
defaultModel: "gpt-5",
defaultBaseUrl: "http://localhost"
},
helpers: {
compactWhitespace: helperFn
} as any
});
deps.ensureSession("asst-1");
deps.appendItem("asst-1", { role: "assistant" } as any);
deps.getSession("asst-1");
deps.persistSession({ session_id: "asst-1" } as any);
deps.setInvestigationState("asst-1", { scope: "x" });
await deps.normalize({ user_message: "q" });
await deps.executeRouteRuntime("store_canonical", "fragment");
await deps.tryAddressQueryHandle("message", { analysisDateHint: "2020-07-31" });
deps.logEvent({ event: "ok" });
expect(sessions.ensureSession).toHaveBeenCalledWith("asst-1");
expect(sessions.appendItem).toHaveBeenCalledWith("asst-1", { role: "assistant" });
expect(sessions.getSession).toHaveBeenCalledWith("asst-1");
expect(sessionLogger.persistSession).toHaveBeenCalledWith({ session_id: "asst-1" });
expect(sessions.setInvestigationState).toHaveBeenCalledWith("asst-1", { scope: "x" });
expect(normalizerService.normalize).toHaveBeenCalledWith({ user_message: "q" });
expect(dataLayer.executeRouteRuntime).toHaveBeenCalledWith("store_canonical", "fragment", undefined);
expect(addressQueryService.tryHandle).toHaveBeenCalledWith("message", { analysisDateHint: "2020-07-31" });
expect(logEvent).toHaveBeenCalledWith({ event: "ok" });
expect(deps.featureContractsV11).toBe(true);
expect(deps.featureLifecycleAnswerV1).toBe(false);
expect(deps.defaultModel).toBe("gpt-5");
expect(deps.defaultBaseUrl).toBe("http://localhost");
expect(deps.defaultApiKey).toBe("api-key");
});
it("preserves helper functions in merged deps payload", () => {
const helperCompactWhitespace = vi.fn((value: unknown) => String(value ?? "").trim());
const deps = buildAssistantTurnRuntimeDeps({
sessions: {
ensureSession: () => null,
appendItem: () => {},
getSession: () => null,
setInvestigationState: () => {}
},
sessionLogger: {
persistSession: () => {}
},
normalizerService: {
normalize: async () => ({})
},
dataLayer: {
executeRouteRuntime: async () => ({})
},
addressQueryService: {
tryHandle: async () => null
},
chatClient: {},
messageIdFactory: () => "msg-2",
nowIso: () => "2026-04-11T00:00:00.000Z",
defaultApiKey: "",
logEvent: () => {},
flags: {
featureAssistantAddressQueryV1: false,
featureAddressLlmPredecomposeV1: false,
featureInvestigationStateV1: false,
featureStateFollowupBindingV1: false,
featureContractsV11: false,
featureAnswerPolicyV11: false,
featureProblemCentricAnswerV1: false,
featureLifecycleAnswerV1: false
},
defaults: {
defaultModel: "model",
defaultBaseUrl: "base"
},
helpers: {
compactWhitespace: helperCompactWhitespace
} as any
});
expect(deps.compactWhitespace(" value ")).toBe("value");
expect(helperCompactWhitespace).toHaveBeenCalledWith(" value ");
});
it("preserves method context for stateful service instances", async () => {
class SessionStoreLike {
public calls: string[] = [];
public ensureSession(sessionId: string) {
this.calls.push(`ensure:${sessionId}`);
return { session_id: sessionId } as any;
}
public appendItem(sessionId: string) {
this.calls.push(`append:${sessionId}`);
}
public getSession(sessionId: string) {
this.calls.push(`get:${sessionId}`);
return null;
}
public setInvestigationState(sessionId: string) {
this.calls.push(`state:${sessionId}`);
return null;
}
}
class SessionLoggerLike {
public persisted = 0;
public persistSession() {
this.persisted += 1;
}
}
class NormalizerLike {
public normalized = 0;
public async normalize() {
this.normalized += 1;
return {};
}
}
const sessions = new SessionStoreLike();
const sessionLogger = new SessionLoggerLike();
const normalizerService = new NormalizerLike();
const deps = buildAssistantTurnRuntimeDeps({
sessions,
sessionLogger,
normalizerService,
dataLayer: {
executeRouteRuntime: async () => ({})
},
addressQueryService: {
tryHandle: async () => null
},
chatClient: {},
messageIdFactory: () => "msg-ctx",
nowIso: () => "2026-04-11T00:00:00.000Z",
defaultApiKey: "",
logEvent: () => {},
flags: {
featureAssistantAddressQueryV1: false,
featureAddressLlmPredecomposeV1: false,
featureInvestigationStateV1: false,
featureStateFollowupBindingV1: false,
featureContractsV11: false,
featureAnswerPolicyV11: false,
featureProblemCentricAnswerV1: false,
featureLifecycleAnswerV1: false
},
defaults: {
defaultModel: "model",
defaultBaseUrl: "base"
},
helpers: {
compactWhitespace: (value: unknown) => String(value ?? "")
} as any
});
deps.ensureSession("asst-ctx");
deps.appendItem("asst-ctx", { role: "user" } as any);
deps.getSession("asst-ctx");
deps.setInvestigationState("asst-ctx", null);
deps.persistSession({ session_id: "asst-ctx" } as any);
await deps.normalize({ user_message: "ctx" } as any);
expect(sessions.calls).toEqual(["ensure:asst-ctx", "append:asst-ctx", "get:asst-ctx", "state:asst-ctx"]);
expect(sessionLogger.persisted).toBe(1);
expect(normalizerService.normalized).toBe(1);
});
});