Skip to content

Commit 19c4439

Browse files
ContextManager Tests (RooCodeInc#2415)
* add tests around truncating context * remove comments
1 parent ec01e1f commit 19c4439

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { ContextManager } from "./ContextManager"
2+
import { Anthropic } from "@anthropic-ai/sdk"
3+
import { expect } from "chai"
4+
5+
describe("ContextManager", () => {
6+
function createMessages(count: number): Anthropic.Messages.MessageParam[] {
7+
const messages: Anthropic.Messages.MessageParam[] = []
8+
9+
messages.push({
10+
role: "user",
11+
content: "Initial task message",
12+
})
13+
14+
let role: "user" | "assistant" = "assistant"
15+
for (let i = 1; i < count; i++) {
16+
messages.push({
17+
role,
18+
content: `Message ${i}`,
19+
})
20+
role = role === "user" ? "assistant" : "user"
21+
}
22+
23+
return messages
24+
}
25+
26+
describe("getNextTruncationRange", () => {
27+
let contextManager: ContextManager
28+
29+
beforeEach(() => {
30+
contextManager = new ContextManager()
31+
})
32+
33+
it("first truncation with half keep", () => {
34+
const messages = createMessages(11)
35+
const result = contextManager.getNextTruncationRange(messages)
36+
37+
expect(result).to.deep.equal([1, 4])
38+
})
39+
40+
it("first truncation with quarter keep", () => {
41+
const messages = createMessages(11)
42+
const result = contextManager.getNextTruncationRange(messages, undefined, "quarter")
43+
44+
expect(result).to.deep.equal([1, 6])
45+
})
46+
47+
it("sequential truncation with half keep", () => {
48+
const messages = createMessages(21)
49+
const firstRange = contextManager.getNextTruncationRange(messages)
50+
expect(firstRange).to.deep.equal([1, 10])
51+
52+
// Pass the previous range for sequential truncation
53+
const secondRange = contextManager.getNextTruncationRange(messages, firstRange)
54+
expect(secondRange).to.deep.equal([1, 14])
55+
})
56+
57+
it("sequential truncation with quarter keep", () => {
58+
const messages = createMessages(41)
59+
const firstRange = contextManager.getNextTruncationRange(messages, undefined, "quarter")
60+
61+
const secondRange = contextManager.getNextTruncationRange(messages, firstRange, "quarter")
62+
63+
expect(secondRange[0]).to.equal(1)
64+
expect(secondRange[1]).to.be.greaterThan(firstRange[1])
65+
})
66+
67+
it("ensures the last message in range is a user message", () => {
68+
const messages = createMessages(14)
69+
const result = contextManager.getNextTruncationRange(messages)
70+
71+
// Check if the message at the end of range is a user message
72+
const lastRemovedMessage = messages[result[1]]
73+
expect(lastRemovedMessage.role).to.equal("user")
74+
75+
// Check if the next message after the range is an assistant message
76+
const nextMessage = messages[result[1] + 1]
77+
expect(nextMessage.role).to.equal("assistant")
78+
})
79+
80+
it("handles small message arrays", () => {
81+
const messages = createMessages(3)
82+
const result = contextManager.getNextTruncationRange(messages)
83+
84+
expect(result).to.deep.equal([1, 0])
85+
})
86+
87+
it("preserves the message structure when truncating", () => {
88+
const messages = createMessages(20)
89+
const result = contextManager.getNextTruncationRange(messages)
90+
91+
// Get messages after removing the range
92+
const effectiveMessages = [...messages.slice(0, result[0]), ...messages.slice(result[1] + 1)]
93+
94+
// Check first message and alternating pattern
95+
expect(effectiveMessages[0].role).to.equal("user")
96+
for (let i = 1; i < effectiveMessages.length; i++) {
97+
const expectedRole = i % 2 === 1 ? "assistant" : "user"
98+
expect(effectiveMessages[i].role).to.equal(expectedRole)
99+
}
100+
})
101+
})
102+
103+
describe("getTruncatedMessages", () => {
104+
let contextManager: ContextManager
105+
106+
beforeEach(() => {
107+
contextManager = new ContextManager()
108+
})
109+
110+
it("returns original messages when no range is provided", () => {
111+
const messages = createMessages(3)
112+
113+
const result = contextManager.getTruncatedMessages(messages, undefined)
114+
expect(result).to.deep.equal(messages)
115+
})
116+
117+
it("correctly removes messages in the specified range", () => {
118+
const messages = createMessages(5)
119+
120+
const range: [number, number] = [1, 3]
121+
const result = contextManager.getTruncatedMessages(messages, range)
122+
123+
expect(result).to.have.lengthOf(2)
124+
expect(result[0]).to.deep.equal(messages[0])
125+
expect(result[1]).to.deep.equal(messages[4])
126+
})
127+
128+
it("works with a range that starts at the first message after task", () => {
129+
const messages = createMessages(4)
130+
131+
const range: [number, number] = [1, 2]
132+
const result = contextManager.getTruncatedMessages(messages, range)
133+
134+
expect(result).to.have.lengthOf(2)
135+
expect(result[0]).to.deep.equal(messages[0])
136+
expect(result[1]).to.deep.equal(messages[3])
137+
})
138+
139+
it("correctly handles removing a range while preserving alternation pattern", () => {
140+
const messages = createMessages(5)
141+
142+
const range: [number, number] = [1, 2]
143+
const result = contextManager.getTruncatedMessages(messages, range)
144+
145+
expect(result).to.have.lengthOf(3)
146+
expect(result[0]).to.deep.equal(messages[0])
147+
expect(result[1]).to.deep.equal(messages[3])
148+
expect(result[2]).to.deep.equal(messages[4])
149+
150+
expect(result[0].role).to.equal("user")
151+
expect(result[1].role).to.equal("assistant")
152+
expect(result[2].role).to.equal("user")
153+
})
154+
})
155+
})

0 commit comments

Comments
 (0)