From 9f9a185b86629ee7139a583f0307c4f94256f4eb Mon Sep 17 00:00:00 2001 From: LHMQ878 <72402929@cityu-dg.edu.cn> Date: Sat, 8 Aug 2026 16:47:12 +0800 Subject: [PATCH 1/2] fix: reset compress-pending manual mode after compression After /dcp-compress, finalizeSession must not treat compress-pending as active manual mode, which permanently blocked automatic compression. --- lib/compress/pipeline.ts | 2 +- tests/finalize-session.test.ts | 96 ++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/finalize-session.test.ts diff --git a/lib/compress/pipeline.ts b/lib/compress/pipeline.ts index 30f1b33b..2bf6ec1e 100644 --- a/lib/compress/pipeline.ts +++ b/lib/compress/pipeline.ts @@ -85,7 +85,7 @@ export async function finalizeSession( entries: NotificationEntry[], batchTopic: string | undefined, ): Promise { - ctx.state.manualMode = ctx.state.manualMode ? "active" : false + ctx.state.manualMode = ctx.state.manualMode === "active" ? "active" : false applyPendingCompressionDurations(ctx.state) await saveSessionState(ctx.state, ctx.logger) diff --git a/tests/finalize-session.test.ts b/tests/finalize-session.test.ts new file mode 100644 index 00000000..ee70133c --- /dev/null +++ b/tests/finalize-session.test.ts @@ -0,0 +1,96 @@ +import assert from "node:assert/strict" +import test from "node:test" +import { finalizeSession } from "../lib/compress/pipeline" +import type { PluginConfig } from "../lib/config" +import { Logger } from "../lib/logger" +import { + createSessionState, + loadManualModeSetting, + type WithParts, +} from "../lib/state" + +function buildConfig(): PluginConfig { + return { + enabled: true, + debug: false, + pruneNotification: "off", + pruneNotificationType: "chat", + commands: { enabled: true, protectedTools: [] }, + manualMode: { enabled: false, automaticStrategies: true }, + turnProtection: { enabled: false, turns: 4 }, + experimental: { allowSubAgents: false, customPrompts: false }, + protectedFilePatterns: [], + compress: { + mode: "message", + permission: "allow", + showCompression: false, + maxContextLimit: 150000, + minContextLimit: 50000, + nudgeFrequency: 5, + iterationNudgeThreshold: 15, + nudgeForce: "soft", + protectedTools: ["task"], + protectTags: false, + protectUserMessages: false, + }, + strategies: { + deduplication: { enabled: true, protectedTools: [] }, + purgeErrors: { enabled: true, turns: 4, protectedTools: [] }, + }, + } as PluginConfig +} + +function buildToolContext(state: ReturnType) { + return { + client: { session: { get: async () => ({}) } }, + state, + logger: new Logger(false), + config: buildConfig(), + prompts: { + reload() {}, + getRuntimePrompts() { + return {} as any + }, + }, + } +} + +test("finalizeSession resets compress-pending to auto mode", async () => { + const sessionId = `finalize-compress-pending-${Date.now()}` + const state = createSessionState() + state.sessionId = sessionId + state.manualMode = "compress-pending" + + await finalizeSession( + buildToolContext(state) as any, + { sessionID: sessionId, metadata: () => {}, ask: async () => {} }, + [] as WithParts[], + [], + undefined, + ) + + assert.equal(state.manualMode, false) + + const persisted = await loadManualModeSetting(sessionId, new Logger(false)) + assert.equal(persisted, false) +}) + +test("finalizeSession preserves explicit active manual mode", async () => { + const sessionId = `finalize-active-manual-${Date.now()}` + const state = createSessionState() + state.sessionId = sessionId + state.manualMode = "active" + + await finalizeSession( + buildToolContext(state) as any, + { sessionID: sessionId, metadata: () => {}, ask: async () => {} }, + [] as WithParts[], + [], + undefined, + ) + + assert.equal(state.manualMode, "active") + + const persisted = await loadManualModeSetting(sessionId, new Logger(false)) + assert.equal(persisted, true) +}) From 42ac1a0e77a78c8fa8d37e104fe2346f55ed5bec Mon Sep 17 00:00:00 2001 From: Daniel Smolsky Date: Sat, 15 Aug 2026 23:29:18 -0400 Subject: [PATCH 2/2] fix: restore manual mode after compression --- lib/compress/pipeline.ts | 10 ++++++++- tests/finalize-session.test.ts | 38 +++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/lib/compress/pipeline.ts b/lib/compress/pipeline.ts index 2bf6ec1e..cddb2be4 100644 --- a/lib/compress/pipeline.ts +++ b/lib/compress/pipeline.ts @@ -85,7 +85,15 @@ export async function finalizeSession( entries: NotificationEntry[], batchTopic: string | undefined, ): Promise { - ctx.state.manualMode = ctx.state.manualMode === "active" ? "active" : false + if (ctx.state.manualMode === "compress-pending") { + ctx.state.manualMode = false + await refreshManualMode( + ctx.state, + toolCtx.sessionID, + ctx.logger, + ctx.config.manualMode.enabled, + ) + } applyPendingCompressionDurations(ctx.state) await saveSessionState(ctx.state, ctx.logger) diff --git a/tests/finalize-session.test.ts b/tests/finalize-session.test.ts index ee70133c..6d5f70f7 100644 --- a/tests/finalize-session.test.ts +++ b/tests/finalize-session.test.ts @@ -6,17 +6,18 @@ import { Logger } from "../lib/logger" import { createSessionState, loadManualModeSetting, + saveManualModeSetting, type WithParts, } from "../lib/state" -function buildConfig(): PluginConfig { +function buildConfig(manualMode = false): PluginConfig { return { enabled: true, debug: false, pruneNotification: "off", pruneNotificationType: "chat", commands: { enabled: true, protectedTools: [] }, - manualMode: { enabled: false, automaticStrategies: true }, + manualMode: { enabled: manualMode, automaticStrategies: true }, turnProtection: { enabled: false, turns: 4 }, experimental: { allowSubAgents: false, customPrompts: false }, protectedFilePatterns: [], @@ -40,12 +41,12 @@ function buildConfig(): PluginConfig { } as PluginConfig } -function buildToolContext(state: ReturnType) { +function buildToolContext(state: ReturnType, manualMode = false) { return { client: { session: { get: async () => ({}) } }, state, logger: new Logger(false), - config: buildConfig(), + config: buildConfig(manualMode), prompts: { reload() {}, getRuntimePrompts() { @@ -75,11 +76,14 @@ test("finalizeSession resets compress-pending to auto mode", async () => { assert.equal(persisted, false) }) -test("finalizeSession preserves explicit active manual mode", async () => { - const sessionId = `finalize-active-manual-${Date.now()}` +test("finalizeSession restores persisted manual mode after compression", async () => { + const sessionId = `finalize-persisted-manual-${Date.now()}` + const logger = new Logger(false) + await saveManualModeSetting(sessionId, true, logger) + const state = createSessionState() state.sessionId = sessionId - state.manualMode = "active" + state.manualMode = "compress-pending" await finalizeSession( buildToolContext(state) as any, @@ -91,6 +95,26 @@ test("finalizeSession preserves explicit active manual mode", async () => { assert.equal(state.manualMode, "active") + const persisted = await loadManualModeSetting(sessionId, logger) + assert.equal(persisted, true) +}) + +test("finalizeSession restores configured manual mode after compression", async () => { + const sessionId = `finalize-configured-manual-${Date.now()}` + const state = createSessionState() + state.sessionId = sessionId + state.manualMode = "compress-pending" + + await finalizeSession( + buildToolContext(state, true) as any, + { sessionID: sessionId, metadata: () => {}, ask: async () => {} }, + [] as WithParts[], + [], + undefined, + ) + + assert.equal(state.manualMode, "active") + const persisted = await loadManualModeSetting(sessionId, new Logger(false)) assert.equal(persisted, true) })