@@ -25,6 +25,8 @@ import { OutputArtifactWriter } from "./artifacts.js";
2525import { recordDiagnosticEvent } from "./diagnostics.js" ;
2626
2727type JsonObject = Record < string , unknown > ;
28+
29+ const maxPendingJsonLineChars = 1_000_000 ;
2830type AppServerRequestMethod =
2931 | "initialize"
3032 | "thread/start"
@@ -213,6 +215,7 @@ export class CodexAppServerSession {
213215 private readonly closedPromise : Promise < void > ;
214216 private resolveClosed : ( ( ) => void ) | undefined ;
215217 private lineBuffer = "" ;
218+ private lineBufferOverflowReported = false ;
216219 private requestCounter = 0 ;
217220 private activeTurn ?: ActiveTurnState ;
218221 private acceptingStartNotifications = false ;
@@ -719,11 +722,29 @@ export class CodexAppServerSession {
719722 chunk : summarizeRawTrafficForLog ( chunk ) ,
720723 } ) ;
721724 this . lineBuffer += chunk ;
725+ if ( this . lineBuffer . length > maxPendingJsonLineChars ) {
726+ const dropped = this . lineBuffer . length - maxPendingJsonLineChars ;
727+ this . lineBuffer = this . lineBuffer . slice ( - maxPendingJsonLineChars ) ;
728+ if ( ! this . lineBufferOverflowReported ) {
729+ this . lineBufferOverflowReported = true ;
730+ const error = `Codex app-server stdout JSON line exceeded ${ maxPendingJsonLineChars } chars; dropped leading data from an unterminated line.` ;
731+ logger . warn ( "codex.app_server.stdout_line_oversized" , {
732+ ...this . logContext ,
733+ appServerId : this . id ,
734+ threadId : this . threadId || undefined ,
735+ activeTurnId : this . activeTurnId ,
736+ droppedChars : dropped ,
737+ maxPendingJsonLineChars,
738+ } ) ;
739+ this . recordBufferedLineError ( error ) ;
740+ }
741+ }
722742 let newlineIndex = this . lineBuffer . indexOf ( "\n" ) ;
723743 while ( newlineIndex >= 0 ) {
724744 const line = this . lineBuffer . slice ( 0 , newlineIndex ) ;
725745 this . lineBuffer = this . lineBuffer . slice ( newlineIndex + 1 ) ;
726746 this . handleLine ( line ) ;
747+ this . lineBufferOverflowReported = false ;
727748 newlineIndex = this . lineBuffer . indexOf ( "\n" ) ;
728749 }
729750 }
@@ -982,6 +1003,19 @@ export class CodexAppServerSession {
9821003 this . activeTurn ?. publishSnapshot ( true ) ;
9831004 }
9841005
1006+ private recordBufferedLineError ( error : string ) : void {
1007+ this . lastError = error ;
1008+ if ( this . activeTurn ) {
1009+ this . activeTurn . summary . errors . push ( error ) ;
1010+ this . activeTurn . publishSnapshot ( true ) ;
1011+ } else if ( this . acceptingStartNotifications ) {
1012+ this . queuePendingStartNotification ( {
1013+ method : "internal/unparseableLine" ,
1014+ params : { error, line : "" } ,
1015+ } ) ;
1016+ }
1017+ }
1018+
9851019 private async probeThreadRead ( timeoutMs : number ) : Promise < void > {
9861020 try {
9871021 await this . request ( "thread/read" , {
0 commit comments