@@ -8,6 +8,7 @@ import type {
88 ChatCompletionTool ,
99} from "openai/resources.mjs" ;
1010
11+ import { pruneLastMessage } from "../compaction.js" ;
1112import { services } from "../services/index.js" ;
1213import { posthogService } from "../telemetry/posthogService.js" ;
1314import { telemetryService } from "../telemetry/telemetryService.js" ;
@@ -130,6 +131,7 @@ interface ProcessStreamingResponseOptions {
130131}
131132
132133// Process a single streaming response and return whether we need to continue
134+ // eslint-disable-next-line max-statements
133135export async function processStreamingResponse (
134136 options : ProcessStreamingResponseOptions ,
135137) : Promise < {
@@ -138,18 +140,22 @@ export async function processStreamingResponse(
138140 toolCalls : ToolCall [ ] ;
139141 shouldContinue : boolean ;
140142} > {
141- const {
142- chatHistory,
143- model,
144- llmApi,
145- abortController,
146- callbacks,
147- isHeadless,
148- tools,
149- } = options ;
143+ const { model, llmApi, abortController, callbacks, isHeadless, tools } =
144+ options ;
145+
146+ let chatHistory = options . chatHistory ;
150147
151148 // Validate context length before making the request
152- const validation = validateContextLength ( chatHistory , model ) ;
149+ let validation = validateContextLength ( chatHistory , model ) ;
150+
151+ // Prune last messages until valid
152+ while ( chatHistory . length > 1 && ! validation . isValid ) {
153+ const prunedChatHistory = pruneLastMessage ( chatHistory ) ;
154+ if ( prunedChatHistory . length === chatHistory . length ) break ;
155+ chatHistory = prunedChatHistory ;
156+ validation = validateContextLength ( chatHistory , model ) ;
157+ }
158+
153159 if ( ! validation . isValid ) {
154160 throw new Error ( `Context length validation failed: ${ validation . error } ` ) ;
155161 }
@@ -323,13 +329,14 @@ export async function processStreamingResponse(
323329}
324330
325331// Main function that handles the conversation loop
326- // eslint-disable-next-line complexity
332+ // eslint-disable-next-line complexity, max-params
327333export async function streamChatResponse (
328334 chatHistory : ChatHistoryItem [ ] ,
329335 model : ModelConfig ,
330336 llmApi : BaseLlmApi ,
331337 abortController : AbortController ,
332338 callbacks ?: StreamCallbacks ,
339+ isCompacting = false ,
333340) {
334341 logger . debug ( "streamChatResponse called" , {
335342 model,
@@ -350,33 +357,43 @@ export async function streamChatResponse(
350357 chatHistorySvc . isReady ( )
351358 ) {
352359 try {
353- chatHistory = chatHistorySvc . getHistory ( ) ;
360+ // use chat history from params when isCompacting is true
361+ // otherwise use the full history
362+ if ( ! isCompacting ) {
363+ chatHistory = chatHistorySvc . getHistory ( ) ;
364+ }
354365 } catch { }
355366 }
356367 logger . debug ( "Starting conversation iteration" ) ;
357368
358- // Pre-API auto-compaction checkpoint
359- const { wasCompacted : preCompacted , chatHistory : preCompactHistory } =
360- await handleAutoCompaction ( chatHistory , model , llmApi , {
361- isHeadless,
362- callbacks : {
363- onSystemMessage : callbacks ?. onSystemMessage ,
364- onContent : callbacks ?. onContent ,
365- } ,
366- } ) ;
369+ logger . debug ( "debug1 streamChatResponse history" , { chatHistory } ) ;
370+
371+ // avoid pre-compaction when compaction is in progress
372+ // this also avoids infinite compaction call stacks
373+ if ( ! isCompacting ) {
374+ // Pre-API auto-compaction checkpoint
375+ const { wasCompacted : preCompacted , chatHistory : preCompactHistory } =
376+ await handleAutoCompaction ( chatHistory , model , llmApi , {
377+ isHeadless,
378+ callbacks : {
379+ onSystemMessage : callbacks ?. onSystemMessage ,
380+ onContent : callbacks ?. onContent ,
381+ } ,
382+ } ) ;
367383
368- if ( preCompacted ) {
369- logger . debug ( "Pre-API compaction occurred, updating chat history" ) ;
370- // Update chat history after pre-compaction
371- const chatHistorySvc2 = services . chatHistory ;
372- if (
373- typeof chatHistorySvc2 ?. isReady === "function" &&
374- chatHistorySvc2 . isReady ( )
375- ) {
376- chatHistorySvc2 . setHistory ( preCompactHistory ) ;
377- chatHistory = chatHistorySvc2 . getHistory ( ) ;
378- } else {
379- chatHistory = [ ...preCompactHistory ] ;
384+ if ( preCompacted ) {
385+ logger . debug ( "Pre-API compaction occurred, updating chat history" ) ;
386+ // Update chat history after pre-compaction
387+ const chatHistorySvc2 = services . chatHistory ;
388+ if (
389+ typeof chatHistorySvc2 ?. isReady === "function" &&
390+ chatHistorySvc2 . isReady ( )
391+ ) {
392+ chatHistorySvc2 . setHistory ( preCompactHistory ) ;
393+ chatHistory = chatHistorySvc2 . getHistory ( ) ;
394+ } else {
395+ chatHistory = [ ...preCompactHistory ] ;
396+ }
380397 }
381398 }
382399
0 commit comments