@@ -6,8 +6,8 @@ import { ChatMessage, ToolResult, ToolResultStatus, ToolUse } from '@amzn/codewh
66import { randomUUID } from '../../shared/crypto'
77import { 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
@@ -70,9 +70,6 @@ export class ChatHistoryManager {
7070 */
7171 public appendUserMessage ( newMessage : ChatMessage ) : void {
7272 this . lastUserMessage = newMessage
73- if ( ! newMessage . userInputMessage ?. content || newMessage . userInputMessage ?. content . trim ( ) === '' ) {
74- this . logger . warn ( 'input must not be empty when adding new messages' )
75- }
7673 this . history . push ( this . formatChatHistoryMessage ( this . lastUserMessage ) )
7774 }
7875
@@ -118,22 +115,81 @@ export class ChatHistoryManager {
118115 this . clearRecentHistory ( )
119116 }
120117
121- if ( this . history . length <= MaxConversationHistoryLength ) {
122- return
118+ // Check if we need to trim based on character count
119+ const totalCharacters = this . calculateHistoryCharacterCount ( )
120+ if ( totalCharacters > MaxConversationHistoryCharacters ) {
121+ this . logger . debug (
122+ `History size (${ totalCharacters } chars) exceeds limit of ${ MaxConversationHistoryCharacters } chars`
123+ )
124+ // Keep removing messages from the beginning until we're under the limit
125+ do {
126+ // Find the next valid user message to start from
127+ const indexToTrim = this . findIndexToTrim ( )
128+ if ( indexToTrim !== undefined && indexToTrim > 0 ) {
129+ this . logger . debug (
130+ `Removing the first ${ indexToTrim } elements in the history due to character count limit`
131+ )
132+ this . history . splice ( 0 , indexToTrim )
133+ } else {
134+ // If we can't find a valid starting point, reset it
135+ this . logger . debug ( 'Could not find a valid point to trim, reset history to reduce character count' )
136+ this . history = [ ]
137+ }
138+ } while (
139+ this . calculateHistoryCharacterCount ( ) > MaxConversationHistoryCharacters &&
140+ this . history . length > 2
141+ )
123142 }
143+ }
124144
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 = [ ]
145+ private calculateHistoryCharacterCount ( ) : number {
146+ let count = 0
147+ for ( const message of this . history ) {
148+ // Count characters in user messages
149+ if ( message . userInputMessage ?. content ) {
150+ count += message . userInputMessage . content . length
151+ count += message . userInputMessage . userInputMessageContext ?. editorState ?. document ?. text ?. length ?? 0
152+ if ( message . userInputMessage . userInputMessageContext ?. editorState ?. relevantDocuments ) {
153+ for ( const document of message . userInputMessage . userInputMessageContext . editorState
154+ . relevantDocuments ) {
155+ count += document . text ?. length ?? 0
156+ }
157+ }
158+ if ( message . userInputMessage . userInputMessageContext ?. additionalContext ) {
159+ for ( const document of message . userInputMessage . userInputMessageContext . additionalContext ) {
160+ count += document . innerContext ?. length ?? 0
161+ }
162+ }
163+ }
164+
165+ // Count characters in assistant messages
166+ if ( message . assistantResponseMessage ?. content ) {
167+ count += message . assistantResponseMessage . content . length
168+ }
169+
170+ try {
171+ // Count characters in tool uses and results
172+ if ( message . assistantResponseMessage ?. toolUses ) {
173+ for ( const toolUse of message . assistantResponseMessage . toolUses ) {
174+ count += JSON . stringify ( toolUse ) . length
175+ }
176+ }
177+
178+ if ( message . userInputMessage ?. userInputMessageContext ?. toolResults ) {
179+ for ( const toolResult of message . userInputMessage . userInputMessageContext . toolResults ) {
180+ count += JSON . stringify ( toolResult ) . length
181+ }
182+ }
183+ } catch ( error : any ) {
184+ this . logger . error ( `Error calculating character count for tool uses/results: ${ error . message } ` )
185+ }
132186 }
187+ this . logger . debug ( `Current history characters: ${ count } ` )
188+ return count
133189 }
134190
135191 private findIndexToTrim ( ) : number | undefined {
136- for ( let i = 1 ; i < this . history . length ; i ++ ) {
192+ for ( let i = 2 ; i < this . history . length ; i ++ ) {
137193 const message = this . history [ i ]
138194 if ( this . isValidUserMessageWithoutToolResults ( message ) ) {
139195 return i
@@ -162,6 +218,12 @@ export class ChatHistoryManager {
162218 private ensureCurrentMessageIsValid ( newUserMessage : ChatMessage ) : void {
163219 const lastHistoryMessage = this . history [ this . history . length - 1 ]
164220 if ( ! lastHistoryMessage ) {
221+ if ( newUserMessage . userInputMessage ?. userInputMessageContext ?. toolResults ) {
222+ this . logger . error (
223+ 'No history message found, but new user message has tool results. This is unexpected.'
224+ )
225+ newUserMessage . userInputMessage . userInputMessageContext . toolResults = undefined
226+ }
165227 return
166228 }
167229
0 commit comments