Skip to content

Commit 88c33ee

Browse files
encapsulate ContextManager (RooCodeInc#2337)
Co-authored-by: Saoud Rizwan <[email protected]>
1 parent 23a0d41 commit 88c33ee

File tree

3 files changed

+52
-100
lines changed

3 files changed

+52
-100
lines changed

src/core/Cline.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import { ClineIgnoreController, LOCK_TEXT_SYMBOL } from "./ignore/ClineIgnoreCon
5757
import { parseMentions } from "./mentions"
5858
import { formatResponse } from "./prompts/responses"
5959
import { addUserInstructions, SYSTEM_PROMPT } from "./prompts/system"
60-
import { getNextTruncationRange, getTruncatedMessages } from "./sliding-window"
60+
import { ContextManager } from "./context-management/ContextManager"
6161
import { OpenAiHandler } from "../api/providers/openai"
6262
import { ApiStream } from "../api/transform/stream"
6363
import { ClineHandler } from "../api/providers/cline"
@@ -78,6 +78,7 @@ export class Cline {
7878
private terminalManager: TerminalManager
7979
private urlContentFetcher: UrlContentFetcher
8080
browserSession: BrowserSession
81+
contextManager: ContextManager
8182
private didEditFile: boolean = false
8283
customInstructions?: string
8384
autoApprovalSettings: AutoApprovalSettings
@@ -139,6 +140,7 @@ export class Cline {
139140
this.terminalManager = new TerminalManager()
140141
this.urlContentFetcher = new UrlContentFetcher(provider.context)
141142
this.browserSession = new BrowserSession(provider.context, browserSettings)
143+
this.contextManager = new ContextManager()
142144
this.diffViewProvider = new DiffViewProvider(cwd)
143145
this.customInstructions = customInstructions
144146
this.autoApprovalSettings = autoApprovalSettings
@@ -1380,7 +1382,7 @@ export class Cline {
13801382
const keep = totalTokens / 2 > maxAllowedSize ? "quarter" : "half"
13811383

13821384
// NOTE: it's okay that we overwriteConversationHistory in resume task since we're only ever removing the last user message and not anything in the middle which would affect this range
1383-
this.conversationHistoryDeletedRange = getNextTruncationRange(
1385+
this.conversationHistoryDeletedRange = this.contextManager.getNextTruncationRange(
13841386
this.apiConversationHistory,
13851387
this.conversationHistoryDeletedRange,
13861388
keep,
@@ -1392,7 +1394,7 @@ export class Cline {
13921394
}
13931395

13941396
// conversationHistoryDeletedRange is updated only when we're close to hitting the context window, so we don't continuously break the prompt cache
1395-
const truncatedConversationHistory = getTruncatedMessages(
1397+
const truncatedConversationHistory = this.contextManager.getTruncatedMessages(
13961398
this.apiConversationHistory,
13971399
this.conversationHistoryDeletedRange,
13981400
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Anthropic } from "@anthropic-ai/sdk"
2+
3+
export class ContextManager {
4+
getNextTruncationRange(
5+
messages: Anthropic.Messages.MessageParam[],
6+
currentDeletedRange: [number, number] | undefined = undefined,
7+
keep: "half" | "quarter" = "half",
8+
): [number, number] {
9+
// Since we always keep the first message, currentDeletedRange[0] will always be 1 (for now until we have a smarter truncation algorithm)
10+
const rangeStartIndex = 1
11+
const startOfRest = currentDeletedRange ? currentDeletedRange[1] + 1 : 1
12+
13+
let messagesToRemove: number
14+
if (keep === "half") {
15+
// Remove half of user-assistant pairs
16+
messagesToRemove = Math.floor((messages.length - startOfRest) / 4) * 2 // Keep even number
17+
} else {
18+
// Remove 3/4 of user-assistant pairs
19+
messagesToRemove = Math.floor((messages.length - startOfRest) / 8) * 3 * 2
20+
}
21+
22+
let rangeEndIndex = startOfRest + messagesToRemove - 1
23+
24+
// Make sure the last message being removed is a user message, so that the next message after the initial task message is an assistant message. This preservers the user-assistant-user-assistant structure.
25+
// NOTE: anthropic format messages are always user-assistant-user-assistant, while openai format messages can have multiple user messages in a row (we use anthropic format throughout cline)
26+
if (messages[rangeEndIndex].role !== "user") {
27+
rangeEndIndex -= 1
28+
}
29+
30+
// this is an inclusive range that will be removed from the conversation history
31+
return [rangeStartIndex, rangeEndIndex]
32+
}
33+
34+
getTruncatedMessages(
35+
messages: Anthropic.Messages.MessageParam[],
36+
deletedRange: [number, number] | undefined,
37+
): Anthropic.Messages.MessageParam[] {
38+
if (!deletedRange) {
39+
return messages
40+
}
41+
42+
const [start, end] = deletedRange
43+
// the range is inclusive - both start and end indices and everything in between will be removed from the final result.
44+
// NOTE: if you try to console log these, don't forget that logging a reference to an array may not provide the same result as logging a slice() snapshot of that array at that exact moment. The following DOES in fact include the latest assistant message.
45+
return [...messages.slice(0, start), ...messages.slice(end + 1)]
46+
}
47+
}

src/core/sliding-window/index.ts

Lines changed: 0 additions & 97 deletions
This file was deleted.

0 commit comments

Comments
 (0)