Skip to content

Commit 395640c

Browse files
committed
fix: prevent context condensing from triggering too early in new conversations
- Added MIN_TOKENS_FOR_PERCENTAGE_TRIGGER constant (1000 tokens) - Modified percentage-based condensing logic to require minimum token threshold - Prevents condensing on brand new conversations with low percentage thresholds - Added comprehensive tests for the new behavior Fixes #8158
1 parent 87b45de commit 395640c

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

src/core/sliding-window/__tests__/sliding-window.spec.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as condenseModule from "../../condense"
1111

1212
import {
1313
TOKEN_BUFFER_PERCENTAGE,
14+
MIN_TOKENS_FOR_PERCENTAGE_TRIGGER,
1415
estimateTokenCount,
1516
truncateConversation,
1617
truncateConversationIfNeeded,
@@ -821,6 +822,109 @@ describe("Sliding Window", () => {
821822
// Clean up
822823
summarizeSpy.mockRestore()
823824
})
825+
826+
it("should not trigger percentage-based condensing when tokens are below MIN_TOKENS_FOR_PERCENTAGE_TRIGGER", async () => {
827+
// Reset any previous mock calls
828+
vi.clearAllMocks()
829+
const summarizeSpy = vi.spyOn(condenseModule, "summarizeConversation")
830+
831+
const modelInfo = createModelInfo(100000, 30000)
832+
const contextWindow = modelInfo.contextWindow
833+
// Set tokens to be below MIN_TOKENS_FOR_PERCENTAGE_TRIGGER (1000)
834+
// Even though percentage would be high (90%), it shouldn't trigger
835+
const totalTokens = 900 // Below MIN_TOKENS_FOR_PERCENTAGE_TRIGGER
836+
const messagesWithSmallContent = [
837+
...messages.slice(0, -1),
838+
{ ...messages[messages.length - 1], content: "" },
839+
]
840+
841+
const result = await truncateConversationIfNeeded({
842+
messages: messagesWithSmallContent,
843+
totalTokens,
844+
contextWindow,
845+
maxTokens: modelInfo.maxTokens,
846+
apiHandler: mockApiHandler,
847+
autoCondenseContext: true,
848+
autoCondenseContextPercent: 5, // Very low threshold - would normally trigger at 5%
849+
systemPrompt: "System prompt",
850+
taskId,
851+
profileThresholds: {},
852+
currentProfileId: "default",
853+
})
854+
855+
// Verify summarizeConversation was not called even though percentage (0.9%) would exceed threshold (5%)
856+
// This is because totalTokens (900) < MIN_TOKENS_FOR_PERCENTAGE_TRIGGER (1000)
857+
expect(summarizeSpy).not.toHaveBeenCalled()
858+
859+
// Verify no truncation or summarization occurred
860+
expect(result).toEqual({
861+
messages: messagesWithSmallContent,
862+
summary: "",
863+
cost: 0,
864+
prevContextTokens: totalTokens,
865+
})
866+
867+
// Clean up
868+
summarizeSpy.mockRestore()
869+
})
870+
871+
it("should trigger percentage-based condensing when tokens exceed MIN_TOKENS_FOR_PERCENTAGE_TRIGGER and percentage threshold", async () => {
872+
// Mock the summarizeConversation function
873+
const mockSummary = "Summary after meeting minimum token requirement"
874+
const mockCost = 0.02
875+
const mockSummarizeResponse: condenseModule.SummarizeResponse = {
876+
messages: [
877+
{ role: "user", content: "First message" },
878+
{ role: "assistant", content: mockSummary, isSummary: true },
879+
{ role: "user", content: "Last message" },
880+
],
881+
summary: mockSummary,
882+
cost: mockCost,
883+
newContextTokens: 150,
884+
}
885+
886+
const summarizeSpy = vi
887+
.spyOn(condenseModule, "summarizeConversation")
888+
.mockResolvedValue(mockSummarizeResponse)
889+
890+
const modelInfo = createModelInfo(100000, 30000)
891+
const contextWindow = modelInfo.contextWindow
892+
// Set tokens to be just above MIN_TOKENS_FOR_PERCENTAGE_TRIGGER
893+
// and above the percentage threshold
894+
const totalTokens = MIN_TOKENS_FOR_PERCENTAGE_TRIGGER + 100 // 1100 tokens
895+
const messagesWithSmallContent = [
896+
...messages.slice(0, -1),
897+
{ ...messages[messages.length - 1], content: "" },
898+
]
899+
900+
const result = await truncateConversationIfNeeded({
901+
messages: messagesWithSmallContent,
902+
totalTokens,
903+
contextWindow,
904+
maxTokens: modelInfo.maxTokens,
905+
apiHandler: mockApiHandler,
906+
autoCondenseContext: true,
907+
autoCondenseContextPercent: 1, // Very low threshold - 1% of 100000 = 1000 tokens
908+
systemPrompt: "System prompt",
909+
taskId,
910+
profileThresholds: {},
911+
currentProfileId: "default",
912+
})
913+
914+
// Should use summarization because:
915+
// 1. totalTokens (1100) >= MIN_TOKENS_FOR_PERCENTAGE_TRIGGER (1000)
916+
// 2. percentage (1.1%) >= threshold (1%)
917+
expect(summarizeSpy).toHaveBeenCalled()
918+
expect(result).toMatchObject({
919+
messages: mockSummarizeResponse.messages,
920+
summary: mockSummary,
921+
cost: mockCost,
922+
prevContextTokens: totalTokens,
923+
})
924+
925+
// Clean up
926+
summarizeSpy.mockRestore()
927+
})
824928
})
825929

826930
/**

src/core/sliding-window/index.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
1212
*/
1313
export const TOKEN_BUFFER_PERCENTAGE = 0.1
1414

15+
/**
16+
* Minimum number of tokens required before percentage-based condensing can trigger.
17+
* This prevents condensing from happening too early in new conversations.
18+
*/
19+
export const MIN_TOKENS_FOR_PERCENTAGE_TRIGGER = 1000
20+
1521
/**
1622
* Counts tokens for user content using the provider's token counting implementation.
1723
*
@@ -144,7 +150,12 @@ export async function truncateConversationIfNeeded({
144150

145151
if (autoCondenseContext) {
146152
const contextPercent = (100 * prevContextTokens) / contextWindow
147-
if (contextPercent >= effectiveThreshold || prevContextTokens > allowedTokens) {
153+
// Only trigger percentage-based condensing if we have enough context
154+
// This prevents condensing from happening on brand new conversations
155+
const shouldCondenseByPercentage =
156+
contextPercent >= effectiveThreshold && prevContextTokens >= MIN_TOKENS_FOR_PERCENTAGE_TRIGGER
157+
158+
if (shouldCondenseByPercentage || prevContextTokens > allowedTokens) {
148159
// Attempt to intelligently condense the context
149160
const result = await summarizeConversation(
150161
messages,

0 commit comments

Comments
 (0)