From e15f2b185c4555f723cbbff482360d4ec5480c9e Mon Sep 17 00:00:00 2001 From: Etan Joseph Heyman Date: Mon, 10 Aug 2026 14:32:02 +0300 Subject: [PATCH] fix: remove automatic context compaction Replace the quality-sweep /compact submission with a warning log and an unsubmitted, route-guarded nudge while preserving degraded detection. Co-Authored-By: cmuxlayerCodex running gpt-5.6-sol --- src/agent-engine.ts | 37 +++++++++------- tests/agent-engine.test.ts | 40 +++++------------- tests/quality-tracking.test.ts | 77 ++++++++++++++++++++++++++-------- 3 files changed, 93 insertions(+), 61 deletions(-) diff --git a/src/agent-engine.ts b/src/agent-engine.ts index b56fbf10..ce25dd8f 100644 --- a/src/agent-engine.ts +++ b/src/agent-engine.ts @@ -3830,23 +3830,32 @@ export class AgentEngine { }); this.registry.set(agentId, updated); - if (agent.spawn_depth === 0) { - // Root agent: send /compact - const compactRoute = await this.resolveAgentIoRoute(agentId); - await this.client.send(compactRoute.surface_id, "/compact", { - workspace: compactRoute.workspace_id ?? undefined, - ...this.stableSurfaceWriteOptions(compactRoute.surface_uuid), - }); - const returnRoute = await this.resolveAgentIoRoute(agentId); - await this.client.sendKey(returnRoute.surface_id, "return", { - workspace: returnRoute.workspace_id ?? undefined, - ...this.stableSurfaceWriteOptions(returnRoute.surface_uuid), - }); - } else { + try { await this.client.log( - `context-limit: depth ${agent.spawn_depth} agent ${agent.repo} degraded; leaving pane running for orchestrator decision`, + `context-limit: depth ${agent.spawn_depth} agent ${agent.repo} degraded at ${contextPct}%; leaving pane running for orchestrator decision`, { level: "warning", source: "cmuxlayer" }, ); + } catch { + // Logging is advisory; a root-agent nudge must still be attempted. + } + + if (agent.spawn_depth === 0) { + const nudgeRoute = await this.resolveAgentIoRoute(agentId); + await this.client.send( + nudgeRoute.surface_id, + `[cmuxlayer] context at ${contextPct}% — checkpoint at-risk work and /compact when safe`, + { + workspace: nudgeRoute.workspace_id ?? undefined, + ...this.stableSurfaceWriteOptions(nudgeRoute.surface_uuid), + beforeMutation: async () => { + await this.resolveUnchangedAgentIoRoute( + agentId, + nudgeRoute, + "context-limit nudge", + ); + }, + }, + ); } } } catch { diff --git a/tests/agent-engine.test.ts b/tests/agent-engine.test.ts index 0c78c3eb..f6babc77 100644 --- a/tests/agent-engine.test.ts +++ b/tests/agent-engine.test.ts @@ -3462,9 +3462,8 @@ describe("AgentEngine", () => { expect(mockClient.readScreen).toHaveBeenCalledTimes(1); }); - it("auto-compacts with workspace scope and re-resolves before Return", async () => { + it("sends an unsubmitted context nudge with workspace scope", async () => { const stableUuid = "11111111-2222-4333-8444-555555555555"; - const recycledUuid = "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee"; const record = makeRecord({ agent_id: "agent-auto-compact-route", state: "ready", @@ -3490,41 +3489,22 @@ describe("AgentEngine", () => { lines: 20, scrollback_used: false, }); - (mockClient.send as ReturnType).mockImplementation( - async (_surface: string, text: string) => { - if (text !== "/compact") return; - liveSurfaces = [ - { - ...makeSurface("surface:compact-old"), - id: recycledUuid, - workspace_ref: "workspace:compact-old", - }, - { - ...makeSurface("surface:compact-final"), - id: stableUuid, - workspace_ref: "workspace:compact-final", - }, - ]; - }, - ); - await engine.runSweep(); expect(mockClient.send).toHaveBeenCalledWith( "surface:compact-old", - "/compact", - { workspace: "workspace:compact-old" }, - ); - expect(mockClient.sendKey).toHaveBeenCalledWith( - "surface:compact-final", - "return", - { workspace: "workspace:compact-final" }, + "[cmuxlayer] context at 95% — checkpoint at-risk work and /compact when safe", + expect.objectContaining({ + workspace: "workspace:compact-old", + beforeMutation: expect.any(Function), + }), ); - expect(mockClient.sendKey).not.toHaveBeenCalledWith( - "surface:compact-old", - "return", + expect(mockClient.send).not.toHaveBeenCalledWith( + expect.anything(), + "/compact", expect.anything(), ); + expect(mockClient.sendKey).not.toHaveBeenCalled(); }); it("respawns a crashed agent with its captured session id when crash recovery is enabled", async () => { diff --git a/tests/quality-tracking.test.ts b/tests/quality-tracking.test.ts index 564b2e06..e7433718 100644 --- a/tests/quality-tracking.test.ts +++ b/tests/quality-tracking.test.ts @@ -1,6 +1,6 @@ /** * TDD tests for Task 19 — Quality Tracking. - * Tests parseContextPercent, quality field, /compact at 80%, warn for depth>0. + * Tests parseContextPercent and quality warnings/nudges at high context usage. */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { mkdirSync, rmSync } from "node:fs"; @@ -191,7 +191,7 @@ describe("Quality Tracking (sweep)", () => { expect(agent!.quality).toBe("unknown"); }); - it("at 80% context, depth-0 agent sends /compact command", async () => { + it("at 80% context, depth-0 agent is degraded and nudged without submitting /compact", async () => { stateMgr.writeState( makeRecord({ agent_id: "a1", @@ -213,16 +213,60 @@ describe("Quality Tracking (sweep)", () => { await engine.runSweep(); - // Should send /compact + return - expect(mockClient.send).toHaveBeenCalledWith("s:1", "/compact", { - workspace: "workspace:quality", - }); - expect(mockClient.sendKey).toHaveBeenCalledWith("s:1", "return", { - workspace: "workspace:quality", + expect(engine.getAgentState("a1")?.quality).toBe("degraded"); + expect(mockClient.log).toHaveBeenCalledWith( + expect.stringContaining("context-limit: depth 0 agent brainlayer degraded at 80%"), + { level: "warning", source: "cmuxlayer" }, + ); + expect(mockClient.send).toHaveBeenCalledWith( + "s:1", + "[cmuxlayer] context at 80% — checkpoint at-risk work and /compact when safe", + expect.objectContaining({ + workspace: "workspace:quality", + beforeMutation: expect.any(Function), + }), + ); + expect(mockClient.send).not.toHaveBeenCalledWith( + "s:1", + "/compact", + expect.anything(), + ); + expect(mockClient.sendKey).not.toHaveBeenCalled(); + }); + + it("still nudges a depth-0 agent when warning logging fails", async () => { + stateMgr.writeState( + makeRecord({ + agent_id: "log-failure", + state: "working", + surface_id: "s:log-failure", + spawn_depth: 0, + }), + ); + liveSurfaces = [makeSurface("s:log-failure")]; + await engine.getRegistry().reconstitute(); + (mockClient.readScreen as ReturnType).mockResolvedValue({ + surface: "s:log-failure", + text: "gpt-5.5 · 5% left · ~/Gits/cmuxlayer\nWorking (1m • esc to interrupt)", + lines: 5, + scrollback_used: false, }); + (mockClient.log as ReturnType).mockRejectedValue( + new Error("log unavailable"), + ); + + await engine.runSweep(); + + expect(engine.getAgentState("log-failure")?.quality).toBe("degraded"); + expect(mockClient.send).toHaveBeenCalledWith( + "s:log-failure", + "[cmuxlayer] context at 95% — checkpoint at-risk work and /compact when safe", + expect.objectContaining({ workspace: "workspace:quality" }), + ); + expect(mockClient.sendKey).not.toHaveBeenCalled(); }); - it("auto-compact follows a stable UUID after its cached surface ref is recycled", async () => { + it("context nudge follows a stable UUID after its cached surface ref is recycled", async () => { const stableUuid = "11111111-2222-4333-8444-555555555555"; stateMgr.writeState( makeRecord({ @@ -262,19 +306,18 @@ describe("Quality Tracking (sweep)", () => { expect(mockClient.send).toHaveBeenCalledWith( "surface:new", - "/compact", - { workspace: "workspace:quality" }, - ); - expect(mockClient.sendKey).toHaveBeenCalledWith( - "surface:new", - "return", - { workspace: "workspace:quality" }, + "[cmuxlayer] context at 95% — checkpoint at-risk work and /compact when safe", + expect.objectContaining({ + workspace: "workspace:quality", + beforeMutation: expect.any(Function), + }), ); expect(mockClient.send).not.toHaveBeenCalledWith( - "surface:old", + expect.anything(), "/compact", expect.anything(), ); + expect(mockClient.sendKey).not.toHaveBeenCalled(); }); it("at 80% context, depth-1 agent is warned but not killed", async () => {