mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-30 01:06:11 +00:00
refactor(test): share server chat event harness
This commit is contained in:
@@ -7,15 +7,18 @@ import {
|
||||
} from "./server-chat.js";
|
||||
|
||||
describe("agent event handler", () => {
|
||||
it("emits chat delta for assistant text-only events", () => {
|
||||
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
|
||||
function createHarness(params?: {
|
||||
now?: number;
|
||||
resolveSessionKeyForRun?: (runId: string) => string | undefined;
|
||||
}) {
|
||||
const nowSpy =
|
||||
params?.now === undefined ? undefined : vi.spyOn(Date, "now").mockReturnValue(params.now);
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
chatRunState.registry.add("run-1", { sessionKey: "session-1", clientRunId: "client-1" });
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
@@ -23,11 +26,29 @@ describe("agent event handler", () => {
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => undefined,
|
||||
resolveSessionKeyForRun: params?.resolveSessionKeyForRun ?? (() => undefined),
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
return {
|
||||
nowSpy,
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
toolEventRecipients,
|
||||
handler,
|
||||
};
|
||||
}
|
||||
|
||||
it("emits chat delta for assistant text-only events", () => {
|
||||
const { broadcast, nodeSendToSession, chatRunState, handler, nowSpy } = createHarness({
|
||||
now: 1_000,
|
||||
});
|
||||
chatRunState.registry.add("run-1", { sessionKey: "session-1", clientRunId: "client-1" });
|
||||
|
||||
handler({
|
||||
runId: "run-1",
|
||||
seq: 1,
|
||||
@@ -46,29 +67,14 @@ describe("agent event handler", () => {
|
||||
expect(payload.message?.content?.[0]?.text).toBe("Hello world");
|
||||
const sessionChatCalls = nodeSendToSession.mock.calls.filter(([, event]) => event === "chat");
|
||||
expect(sessionChatCalls).toHaveLength(1);
|
||||
nowSpy.mockRestore();
|
||||
nowSpy?.mockRestore();
|
||||
});
|
||||
|
||||
it("does not emit chat delta for NO_REPLY streaming text", () => {
|
||||
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(1_000);
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
chatRunState.registry.add("run-1", { sessionKey: "session-1", clientRunId: "client-1" });
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => undefined,
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
const { broadcast, nodeSendToSession, chatRunState, handler, nowSpy } = createHarness({
|
||||
now: 1_000,
|
||||
});
|
||||
chatRunState.registry.add("run-1", { sessionKey: "session-1", clientRunId: "client-1" });
|
||||
|
||||
handler({
|
||||
runId: "run-1",
|
||||
@@ -82,29 +88,14 @@ describe("agent event handler", () => {
|
||||
expect(chatCalls).toHaveLength(0);
|
||||
const sessionChatCalls = nodeSendToSession.mock.calls.filter(([, event]) => event === "chat");
|
||||
expect(sessionChatCalls).toHaveLength(0);
|
||||
nowSpy.mockRestore();
|
||||
nowSpy?.mockRestore();
|
||||
});
|
||||
|
||||
it("does not include NO_REPLY text in chat final message", () => {
|
||||
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(2_000);
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
chatRunState.registry.add("run-2", { sessionKey: "session-2", clientRunId: "client-2" });
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => undefined,
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
const { broadcast, nodeSendToSession, chatRunState, handler, nowSpy } = createHarness({
|
||||
now: 2_000,
|
||||
});
|
||||
chatRunState.registry.add("run-2", { sessionKey: "session-2", clientRunId: "client-2" });
|
||||
|
||||
handler({
|
||||
runId: "run-2",
|
||||
@@ -128,33 +119,16 @@ describe("agent event handler", () => {
|
||||
expect(payload.message).toBeUndefined();
|
||||
const sessionChatCalls = nodeSendToSession.mock.calls.filter(([, event]) => event === "chat");
|
||||
expect(sessionChatCalls).toHaveLength(1);
|
||||
nowSpy.mockRestore();
|
||||
nowSpy?.mockRestore();
|
||||
});
|
||||
|
||||
it("cleans up agent run sequence tracking when lifecycle completes", () => {
|
||||
const nowSpy = vi.spyOn(Date, "now").mockReturnValue(2_500);
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
const { agentRunSeq, chatRunState, handler, nowSpy } = createHarness({ now: 2_500 });
|
||||
chatRunState.registry.add("run-cleanup", {
|
||||
sessionKey: "session-cleanup",
|
||||
clientRunId: "client-cleanup",
|
||||
});
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => undefined,
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-cleanup",
|
||||
seq: 1,
|
||||
@@ -174,31 +148,17 @@ describe("agent event handler", () => {
|
||||
|
||||
expect(agentRunSeq.has("run-cleanup")).toBe(false);
|
||||
expect(agentRunSeq.has("client-cleanup")).toBe(false);
|
||||
nowSpy.mockRestore();
|
||||
nowSpy?.mockRestore();
|
||||
});
|
||||
|
||||
it("routes tool events only to registered recipients when verbose is enabled", () => {
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
const { broadcast, broadcastToConnIds, toolEventRecipients, handler } = createHarness({
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
});
|
||||
|
||||
registerAgentRunContext("run-tool", { sessionKey: "session-1", verboseLevel: "on" });
|
||||
toolEventRecipients.add("run-tool", "conn-1");
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-tool",
|
||||
seq: 1,
|
||||
@@ -213,27 +173,13 @@ describe("agent event handler", () => {
|
||||
});
|
||||
|
||||
it("broadcasts tool events to WS recipients even when verbose is off, but skips node send", () => {
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
const { broadcastToConnIds, nodeSendToSession, toolEventRecipients, handler } = createHarness({
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
});
|
||||
|
||||
registerAgentRunContext("run-tool-off", { sessionKey: "session-1", verboseLevel: "off" });
|
||||
toolEventRecipients.add("run-tool-off", "conn-1");
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-tool-off",
|
||||
seq: 1,
|
||||
@@ -251,27 +197,13 @@ describe("agent event handler", () => {
|
||||
});
|
||||
|
||||
it("strips tool output when verbose is on", () => {
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
const { broadcastToConnIds, toolEventRecipients, handler } = createHarness({
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
});
|
||||
|
||||
registerAgentRunContext("run-tool-on", { sessionKey: "session-1", verboseLevel: "on" });
|
||||
toolEventRecipients.add("run-tool-on", "conn-1");
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-tool-on",
|
||||
seq: 1,
|
||||
@@ -294,27 +226,13 @@ describe("agent event handler", () => {
|
||||
});
|
||||
|
||||
it("keeps tool output when verbose is full", () => {
|
||||
const broadcast = vi.fn();
|
||||
const broadcastToConnIds = vi.fn();
|
||||
const nodeSendToSession = vi.fn();
|
||||
const agentRunSeq = new Map<string, number>();
|
||||
const chatRunState = createChatRunState();
|
||||
const toolEventRecipients = createToolEventRecipientRegistry();
|
||||
const { broadcastToConnIds, toolEventRecipients, handler } = createHarness({
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
});
|
||||
|
||||
registerAgentRunContext("run-tool-full", { sessionKey: "session-1", verboseLevel: "full" });
|
||||
toolEventRecipients.add("run-tool-full", "conn-1");
|
||||
|
||||
const handler = createAgentEventHandler({
|
||||
broadcast,
|
||||
broadcastToConnIds,
|
||||
nodeSendToSession,
|
||||
agentRunSeq,
|
||||
chatRunState,
|
||||
resolveSessionKeyForRun: () => "session-1",
|
||||
clearAgentRunContext: vi.fn(),
|
||||
toolEventRecipients,
|
||||
});
|
||||
|
||||
const result = { content: [{ type: "text", text: "secret" }] };
|
||||
handler({
|
||||
runId: "run-tool-full",
|
||||
|
||||
Reference in New Issue
Block a user