mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 06:31:24 +00:00
agents: reduce prompt token bloat from exec and context (#16539)
Merged via /review-pr -> /prepare-pr -> /merge-pr.
Prepared head SHA: 8e1635fa3f
Co-authored-by: CharlieGreenman <8540141+CharlieGreenman@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -83,6 +83,42 @@ describe("node exec events", () => {
|
||||
expect(requestHeartbeatNowMock).toHaveBeenCalledWith({ reason: "exec-event" });
|
||||
});
|
||||
|
||||
it("suppresses noisy exec.finished success events with empty output", async () => {
|
||||
const ctx = buildCtx();
|
||||
await handleNodeEvent(ctx, "node-2", {
|
||||
event: "exec.finished",
|
||||
payloadJSON: JSON.stringify({
|
||||
runId: "run-quiet",
|
||||
exitCode: 0,
|
||||
timedOut: false,
|
||||
output: " ",
|
||||
}),
|
||||
});
|
||||
|
||||
expect(enqueueSystemEventMock).not.toHaveBeenCalled();
|
||||
expect(requestHeartbeatNowMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("truncates long exec.finished output in system events", async () => {
|
||||
const ctx = buildCtx();
|
||||
await handleNodeEvent(ctx, "node-2", {
|
||||
event: "exec.finished",
|
||||
payloadJSON: JSON.stringify({
|
||||
runId: "run-long",
|
||||
exitCode: 0,
|
||||
timedOut: false,
|
||||
output: "x".repeat(600),
|
||||
}),
|
||||
});
|
||||
|
||||
const [[text]] = enqueueSystemEventMock.mock.calls;
|
||||
expect(typeof text).toBe("string");
|
||||
expect(text.startsWith("Exec finished (node=node-2 id=run-long, code 0)\n")).toBe(true);
|
||||
expect(text.endsWith("…")).toBe(true);
|
||||
expect(text.length).toBeLessThan(280);
|
||||
expect(requestHeartbeatNowMock).toHaveBeenCalledWith({ reason: "exec-event" });
|
||||
});
|
||||
|
||||
it("enqueues exec.denied events with reason", async () => {
|
||||
const ctx = buildCtx();
|
||||
await handleNodeEvent(ctx, "node-3", {
|
||||
|
||||
@@ -15,6 +15,20 @@ import {
|
||||
} from "./session-utils.js";
|
||||
import { formatForLog } from "./ws-log.js";
|
||||
|
||||
const MAX_EXEC_EVENT_OUTPUT_CHARS = 180;
|
||||
|
||||
function compactExecEventOutput(raw: string) {
|
||||
const normalized = raw.replace(/\s+/g, " ").trim();
|
||||
if (!normalized) {
|
||||
return "";
|
||||
}
|
||||
if (normalized.length <= MAX_EXEC_EVENT_OUTPUT_CHARS) {
|
||||
return normalized;
|
||||
}
|
||||
const safe = Math.max(1, MAX_EXEC_EVENT_OUTPUT_CHARS - 1);
|
||||
return `${normalized.slice(0, safe)}…`;
|
||||
}
|
||||
|
||||
export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt: NodeEvent) => {
|
||||
switch (evt.event) {
|
||||
case "voice.transcript": {
|
||||
@@ -244,9 +258,14 @@ export const handleNodeEvent = async (ctx: NodeEventContext, nodeId: string, evt
|
||||
}
|
||||
} else if (evt.event === "exec.finished") {
|
||||
const exitLabel = timedOut ? "timeout" : `code ${exitCode ?? "?"}`;
|
||||
const compactOutput = compactExecEventOutput(output);
|
||||
const shouldNotify = timedOut || exitCode !== 0 || compactOutput.length > 0;
|
||||
if (!shouldNotify) {
|
||||
return;
|
||||
}
|
||||
text = `Exec finished (node=${nodeId}${runId ? ` id=${runId}` : ""}, ${exitLabel})`;
|
||||
if (output) {
|
||||
text += `\n${output}`;
|
||||
if (compactOutput) {
|
||||
text += `\n${compactOutput}`;
|
||||
}
|
||||
} else {
|
||||
text = `Exec denied (node=${nodeId}${runId ? ` id=${runId}` : ""}${reason ? `, ${reason}` : ""})`;
|
||||
|
||||
Reference in New Issue
Block a user