Skip to content

Commit 44517a9

Browse files
committed
fix(chat): prune history if it's too large
1 parent b6d4754 commit 44517a9

File tree

1 file changed

+58
-12
lines changed

1 file changed

+58
-12
lines changed

packages/core/src/codewhispererChat/storages/chatHistory.ts

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { ChatMessage, ToolResult, ToolResultStatus, ToolUse } from '@amzn/codewh
66
import { randomUUID } from '../../shared/crypto'
77
import { getLogger } from '../../shared/logger/logger'
88

9-
// Maximum number of messages to keep in history
10-
const MaxConversationHistoryLength = 100
9+
// Maximum number of characters to keep in history
10+
const MaxConversationHistoryCharacters = 600_000
1111

1212
/**
1313
* ChatHistoryManager handles the storage and manipulation of chat history
@@ -118,22 +118,68 @@ export class ChatHistoryManager {
118118
this.clearRecentHistory()
119119
}
120120

121-
if (this.history.length <= MaxConversationHistoryLength) {
122-
return
121+
// Check if we need to trim based on character count
122+
const totalCharacters = this.calculateHistoryCharacterCount()
123+
if (totalCharacters > MaxConversationHistoryCharacters) {
124+
this.logger.debug(
125+
`History size (${totalCharacters} chars) exceeds limit of ${MaxConversationHistoryCharacters} chars`
126+
)
127+
// Keep removing messages from the beginning until we're under the limit
128+
while (
129+
this.calculateHistoryCharacterCount() > MaxConversationHistoryCharacters &&
130+
this.history.length > 2
131+
) {
132+
// Find the next valid user message to start from
133+
const indexToTrim = this.findIndexToTrim()
134+
if (indexToTrim !== undefined && indexToTrim > 0) {
135+
this.logger.debug(
136+
`Removing the first ${indexToTrim} elements in the history due to character count limit`
137+
)
138+
this.history.splice(0, indexToTrim)
139+
} else {
140+
// If we can't find a valid starting point, reset it
141+
this.logger.error('Reset history to reduce character count')
142+
this.history = []
143+
}
144+
}
123145
}
146+
}
124147

125-
const indexToTrim = this.findIndexToTrim()
126-
if (indexToTrim !== undefined) {
127-
this.logger.debug(`Removing the first ${indexToTrim} elements in the history`)
128-
this.history.splice(0, indexToTrim)
129-
} else {
130-
this.logger.debug('No valid starting user message found in the history, clearing')
131-
this.history = []
148+
private calculateHistoryCharacterCount(): number {
149+
let count = 0
150+
for (const message of this.history) {
151+
// Count characters in user messages
152+
if (message.userInputMessage?.content) {
153+
count += message.userInputMessage.content.length
154+
}
155+
156+
// Count characters in assistant messages
157+
if (message.assistantResponseMessage?.content) {
158+
count += message.assistantResponseMessage.content.length
159+
}
160+
161+
try {
162+
// Count characters in tool uses and results
163+
if (message.assistantResponseMessage?.toolUses) {
164+
for (const toolUse of message.assistantResponseMessage.toolUses) {
165+
count += JSON.stringify(toolUse).length
166+
}
167+
}
168+
169+
if (message.userInputMessage?.userInputMessageContext?.toolResults) {
170+
for (const toolResult of message.userInputMessage.userInputMessageContext.toolResults) {
171+
count += JSON.stringify(toolResult).length
172+
}
173+
}
174+
} catch (error: any) {
175+
this.logger.error(`Error calculating character count for tool uses/results: ${error.message}`)
176+
}
132177
}
178+
return count
133179
}
134180

135181
private findIndexToTrim(): number | undefined {
136-
for (let i = 1; i < this.history.length; i++) {
182+
for (let i = 2; i < this.history.length; i++) {
137183
const message = this.history[i]
138184
if (this.isValidUserMessageWithoutToolResults(message)) {
139185
return i

0 commit comments

Comments
 (0)