218 lines
7.2 KiB
TypeScript
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);
|
|
});
|
|
});
|