@@ -236,6 +236,13 @@ func (a *App) runAgentLoop(conversationId string, messages []AIChatMessage, prom
236236
237237 // Agentic loop
238238 for round := 0 ; round < maxRounds ; round ++ {
239+ // Compress old tool results to prevent context window bloat
240+ // Keep system prompt + user messages + recent tool interactions intact,
241+ // but shorten tool results from rounds older than the last 2
242+ if round > 2 {
243+ compressOldToolResults (aiMessages )
244+ }
245+
239246 // Check if cancelled before each round
240247 if ctx .Err () != nil {
241248 a .emitEvent ("ai-chat-chunk" , map [string ]string {
@@ -372,6 +379,39 @@ func (a *App) runAgentLoop(conversationId string, messages []AIChatMessage, prom
372379 })
373380 return nil
374381}
382+
383+ // compressOldToolResults shortens tool result messages beyond the most recent round
384+ // to prevent context window bloat over many rounds.
385+ // It keeps the last 4 tool-role messages at full length and compresses older ones.
386+ func compressOldToolResults (messages []ai.Message ) {
387+ const maxCompressedLen = 200
388+ const keepRecentToolMessages = 4
389+
390+ // Count total tool messages
391+ toolCount := 0
392+ for i := range messages {
393+ if messages [i ].Role == "tool" {
394+ toolCount ++
395+ }
396+ }
397+ if toolCount <= keepRecentToolMessages {
398+ return
399+ }
400+
401+ // Compress older tool messages (keep last keepRecentToolMessages intact)
402+ skipCount := toolCount - keepRecentToolMessages
403+ compressed := 0
404+ for i := 0 ; i < len (messages ); i ++ {
405+ if messages [i ].Role == "tool" && compressed < skipCount {
406+ content := messages [i ].Content
407+ if len (content ) > maxCompressedLen {
408+ messages [i ].Content = content [:maxCompressedLen ] + "... (compressed)"
409+ }
410+ compressed ++
411+ }
412+ }
413+ }
414+
375415func (a * App ) gatherRunningCasesInfo () (string , int ) {
376416 a .mu .Lock ()
377417 project := a .project
0 commit comments