mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 04:52:43 +00:00
Gateway/TUI: filter heartbeat ACK noise in chat events
This commit is contained in:
@@ -1,12 +1,40 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadConfig } from "../config/config.js";
|
||||
import { registerAgentRunContext, resetAgentRunContextForTest } from "../infra/agent-events.js";
|
||||
import { resolveHeartbeatVisibility } from "../infra/heartbeat-visibility.js";
|
||||
import {
|
||||
createAgentEventHandler,
|
||||
createChatRunState,
|
||||
createToolEventRecipientRegistry,
|
||||
} from "./server-chat.js";
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: vi.fn(() => ({})),
|
||||
}));
|
||||
|
||||
vi.mock("../infra/heartbeat-visibility.js", () => ({
|
||||
resolveHeartbeatVisibility: vi.fn(() => ({
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
})),
|
||||
}));
|
||||
|
||||
describe("agent event handler", () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(loadConfig).mockReturnValue({});
|
||||
vi.mocked(resolveHeartbeatVisibility).mockReturnValue({
|
||||
showOk: false,
|
||||
showAlerts: true,
|
||||
useIndicator: true,
|
||||
});
|
||||
resetAgentRunContextForTest();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetAgentRunContextForTest();
|
||||
});
|
||||
|
||||
function createHarness(params?: {
|
||||
now?: number;
|
||||
resolveSessionKeyForRun?: (runId: string) => string | undefined;
|
||||
@@ -393,4 +421,93 @@ describe("agent event handler", () => {
|
||||
expect(payload.runId).toBe("run-tool-client");
|
||||
resetAgentRunContextForTest();
|
||||
});
|
||||
|
||||
it("suppresses heartbeat ack-like chat output when showOk is false", () => {
|
||||
const { broadcast, nodeSendToSession, chatRunState, handler } = createHarness({
|
||||
now: 2_000,
|
||||
});
|
||||
chatRunState.registry.add("run-heartbeat", {
|
||||
sessionKey: "session-heartbeat",
|
||||
clientRunId: "client-heartbeat",
|
||||
});
|
||||
registerAgentRunContext("run-heartbeat", {
|
||||
sessionKey: "session-heartbeat",
|
||||
isHeartbeat: true,
|
||||
verboseLevel: "off",
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-heartbeat",
|
||||
seq: 1,
|
||||
stream: "assistant",
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
text: "HEARTBEAT_OK Read HEARTBEAT.md if it exists (workspace context). Follow it strictly.",
|
||||
},
|
||||
});
|
||||
|
||||
expect(chatBroadcastCalls(broadcast)).toHaveLength(0);
|
||||
expect(sessionChatCalls(nodeSendToSession)).toHaveLength(0);
|
||||
|
||||
handler({
|
||||
runId: "run-heartbeat",
|
||||
seq: 2,
|
||||
stream: "lifecycle",
|
||||
ts: Date.now(),
|
||||
data: { phase: "end" },
|
||||
});
|
||||
|
||||
const chatCalls = chatBroadcastCalls(broadcast);
|
||||
expect(chatCalls).toHaveLength(1);
|
||||
const finalPayload = chatCalls[0]?.[1] as { state?: string; message?: unknown };
|
||||
expect(finalPayload.state).toBe("final");
|
||||
expect(finalPayload.message).toBeUndefined();
|
||||
expect(sessionChatCalls(nodeSendToSession)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("keeps heartbeat alert text in final chat output when remainder exceeds ackMaxChars", () => {
|
||||
vi.mocked(loadConfig).mockReturnValue({
|
||||
agents: { defaults: { heartbeat: { ackMaxChars: 10 } } },
|
||||
});
|
||||
|
||||
const { broadcast, chatRunState, handler } = createHarness({ now: 3_000 });
|
||||
chatRunState.registry.add("run-heartbeat-alert", {
|
||||
sessionKey: "session-heartbeat-alert",
|
||||
clientRunId: "client-heartbeat-alert",
|
||||
});
|
||||
registerAgentRunContext("run-heartbeat-alert", {
|
||||
sessionKey: "session-heartbeat-alert",
|
||||
isHeartbeat: true,
|
||||
verboseLevel: "off",
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-heartbeat-alert",
|
||||
seq: 1,
|
||||
stream: "assistant",
|
||||
ts: Date.now(),
|
||||
data: {
|
||||
text: "HEARTBEAT_OK Disk usage crossed 95 percent on /data and needs cleanup now.",
|
||||
},
|
||||
});
|
||||
|
||||
handler({
|
||||
runId: "run-heartbeat-alert",
|
||||
seq: 2,
|
||||
stream: "lifecycle",
|
||||
ts: Date.now(),
|
||||
data: { phase: "end" },
|
||||
});
|
||||
|
||||
const chatCalls = chatBroadcastCalls(broadcast);
|
||||
expect(chatCalls).toHaveLength(1);
|
||||
const payload = chatCalls[0]?.[1] as {
|
||||
state?: string;
|
||||
message?: { content?: Array<{ text?: string }> };
|
||||
};
|
||||
expect(payload.state).toBe("final");
|
||||
expect(payload.message?.content?.[0]?.text).toBe(
|
||||
"Disk usage crossed 95 percent on /data and needs cleanup now.",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user