diff --git a/src/core/sliding-window/__tests__/sliding-window.spec.ts b/src/core/sliding-window/__tests__/sliding-window.spec.ts index 0f2c70c81b..f8a4312d28 100644 --- a/src/core/sliding-window/__tests__/sliding-window.spec.ts +++ b/src/core/sliding-window/__tests__/sliding-window.spec.ts @@ -577,7 +577,7 @@ describe("Sliding Window", () => { maxTokens: modelInfo.maxTokens, apiHandler: mockApiHandler, autoCondenseContext: true, - autoCondenseContextPercent: 100, + autoCondenseContextPercent: 50, // Use a threshold less than 100% systemPrompt: "System prompt", taskId, profileThresholds: {}, @@ -644,7 +644,7 @@ describe("Sliding Window", () => { maxTokens: modelInfo.maxTokens, apiHandler: mockApiHandler, autoCondenseContext: true, - autoCondenseContextPercent: 100, + autoCondenseContextPercent: 50, // Use a threshold less than 100% systemPrompt: "System prompt", taskId, profileThresholds: {}, @@ -821,6 +821,48 @@ describe("Sliding Window", () => { // Clean up summarizeSpy.mockRestore() }) + + it("should not truncate when autoCondenseContext is true and threshold is 100% even if tokens exceed allowedTokens", async () => { + const modelInfo = createModelInfo(100000, 30000) + const totalTokens = 75000 // This exceeds allowedTokens (60000) but should not truncate when disabled + + const messagesWithSmallContent = [ + ...messages.slice(0, -1), + { ...messages[messages.length - 1], content: "" }, + ] + + // Spy on summarizeConversation to ensure it's not called + const summarizeSpy = vi.spyOn(condenseModule, "summarizeConversation") + + const result = await truncateConversationIfNeeded({ + messages: messagesWithSmallContent, + totalTokens, + contextWindow: modelInfo.contextWindow, + maxTokens: modelInfo.maxTokens, + apiHandler: mockApiHandler, + autoCondenseContext: true, // Enabled but with 100% threshold + autoCondenseContextPercent: 100, // 100% threshold means never condense + systemPrompt: "System prompt", + taskId, + profileThresholds: {}, + currentProfileId: "default", + }) + + // Verify summarizeConversation was NOT called when threshold is 100% + expect(summarizeSpy).not.toHaveBeenCalled() + + // Should NOT truncate even though tokens exceed allowedTokens when threshold is 100% + expect(result).toEqual({ + messages: messagesWithSmallContent, + summary: "", + cost: 0, + prevContextTokens: totalTokens, + error: undefined, + }) + + // Clean up + summarizeSpy.mockRestore() + }) }) /** diff --git a/src/core/sliding-window/index.ts b/src/core/sliding-window/index.ts index 1e518c9a56..d83730b8e6 100644 --- a/src/core/sliding-window/index.ts +++ b/src/core/sliding-window/index.ts @@ -142,7 +142,7 @@ export async function truncateConversationIfNeeded({ } // If no specific threshold is found for the profile, fall back to global setting - if (autoCondenseContext) { + if (autoCondenseContext && effectiveThreshold < 100) { const contextPercent = (100 * prevContextTokens) / contextWindow if (contextPercent >= effectiveThreshold || prevContextTokens > allowedTokens) { // Attempt to intelligently condense the context @@ -166,7 +166,15 @@ export async function truncateConversationIfNeeded({ } // Fall back to sliding window truncation if needed + // Exception: When context condensing is explicitly disabled (threshold = 100%), don't truncate if (prevContextTokens > allowedTokens) { + // Check if condensing is explicitly disabled (threshold is 100% and autoCondenseContext is true) + // This means the user has set the threshold to 100% to disable condensing + if (autoCondenseContext && effectiveThreshold >= 100) { + // Context condensing is explicitly disabled by user, don't truncate + return { messages, summary: "", cost, prevContextTokens, error } + } + // Apply sliding window truncation in all other cases const truncatedMessages = truncateConversation(messages, 0.5, taskId) return { messages: truncatedMessages, prevContextTokens, summary: "", cost, error } }