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:
Charlie Greenman
2026-02-14 18:32:45 -05:00
committed by GitHub
parent 2547514b47
commit dec6859702
23 changed files with 403 additions and 39 deletions

View File

@@ -221,6 +221,28 @@ describe("exec tool backgrounding", () => {
expect(status).toBe("completed");
});
it("defaults process log to a bounded tail when no window is provided", async () => {
const lines = Array.from({ length: 260 }, (_value, index) => `line-${index + 1}`);
const result = await execTool.execute("call1", {
command: echoLines(lines),
background: true,
});
const sessionId = (result.details as { sessionId: string }).sessionId;
await waitForCompletion(sessionId);
const log = await processTool.execute("call2", {
action: "log",
sessionId,
});
const textBlock = log.content.find((c) => c.type === "text")?.text ?? "";
const firstLine = textBlock.split("\n")[0]?.trim();
expect(textBlock).toContain("showing last 200 of 260 lines");
expect(firstLine).toBe("line-61");
expect(textBlock).toContain("line-61");
expect(textBlock).toContain("line-260");
expect((log.details as { totalLines?: number }).totalLines).toBe(260);
});
it("supports line offsets for log slices", async () => {
const result = await execTool.execute("call1", {
command: echoLines(["alpha", "beta", "gamma"]),
@@ -239,6 +261,29 @@ describe("exec tool backgrounding", () => {
expect(normalizeText(textBlock?.text)).toBe("beta");
});
it("keeps offset-only log requests unbounded by default tail mode", async () => {
const lines = Array.from({ length: 260 }, (_value, index) => `line-${index + 1}`);
const result = await execTool.execute("call1", {
command: echoLines(lines),
background: true,
});
const sessionId = (result.details as { sessionId: string }).sessionId;
await waitForCompletion(sessionId);
const log = await processTool.execute("call2", {
action: "log",
sessionId,
offset: 30,
});
const textBlock = log.content.find((c) => c.type === "text")?.text ?? "";
const renderedLines = textBlock.split("\n");
expect(renderedLines[0]?.trim()).toBe("line-31");
expect(renderedLines[renderedLines.length - 1]?.trim()).toBe("line-260");
expect(textBlock).not.toContain("showing last 200");
expect((log.details as { totalLines?: number }).totalLines).toBe(260);
});
it("scopes process sessions by scopeKey", async () => {
const bashA = createExecTool({ backgroundMs: 10, scopeKey: "agent:alpha" });
const processA = createProcessTool({ scopeKey: "agent:alpha" });
@@ -300,6 +345,49 @@ describe("exec notifyOnExit", () => {
expect(finished).toBeTruthy();
expect(hasEvent).toBe(true);
});
it("skips no-op completion events when command succeeds without output", async () => {
const tool = createExecTool({
allowBackground: true,
backgroundMs: 0,
notifyOnExit: true,
sessionKey: "agent:main:main",
});
const result = await tool.execute("call2", {
command: shortDelayCmd,
background: true,
});
expect(result.details.status).toBe("running");
const sessionId = (result.details as { sessionId: string }).sessionId;
const status = await waitForCompletion(sessionId);
expect(status).toBe("completed");
expect(peekSystemEvents("agent:main:main")).toEqual([]);
});
it("can re-enable no-op completion events via notifyOnExitEmptySuccess", async () => {
const tool = createExecTool({
allowBackground: true,
backgroundMs: 0,
notifyOnExit: true,
notifyOnExitEmptySuccess: true,
sessionKey: "agent:main:main",
});
const result = await tool.execute("call3", {
command: shortDelayCmd,
background: true,
});
expect(result.details.status).toBe("running");
const sessionId = (result.details as { sessionId: string }).sessionId;
const status = await waitForCompletion(sessionId);
expect(status).toBe("completed");
const events = peekSystemEvents("agent:main:main");
expect(events.length).toBeGreaterThan(0);
expect(events.some((event) => event.includes("Exec completed"))).toBe(true);
});
});
describe("exec PATH handling", () => {