@@ -107,4 +107,99 @@ export class Logger {
107107 const component = this . getCallerFile ( 2 )
108108 return this . write ( "ERROR" , component , message , data )
109109 }
110+
111+ /**
112+ * Strips unnecessary metadata from messages for cleaner debug logs.
113+ *
114+ * Removed:
115+ * - All IDs (id, sessionID, messageID, parentID, callID on parts)
116+ * - summary, path, cost, model, agent, mode, finish, providerID, modelID
117+ * - step-start and step-finish parts entirely
118+ * - snapshot fields
119+ * - ignored text parts
120+ *
121+ * Kept:
122+ * - role, time (created only), tokens (input, output, reasoning, cache)
123+ * - text, reasoning, tool parts with content
124+ * - tool calls with: tool, callID, input, output
125+ */
126+ private minimizeForDebug ( messages : any [ ] ) : any [ ] {
127+ return messages . map ( ( msg ) => {
128+ const minimized : any = {
129+ role : msg . info ?. role ,
130+ }
131+
132+ if ( msg . info ?. time ?. created ) {
133+ minimized . time = msg . info . time . created
134+ }
135+
136+ if ( msg . info ?. tokens ) {
137+ minimized . tokens = {
138+ input : msg . info . tokens . input ,
139+ output : msg . info . tokens . output ,
140+ reasoning : msg . info . tokens . reasoning ,
141+ cache : msg . info . tokens . cache ,
142+ }
143+ }
144+
145+ if ( msg . parts ) {
146+ minimized . parts = msg . parts
147+ . map ( ( part : any ) => {
148+ if ( part . type === "step-start" || part . type === "step-finish" ) {
149+ return null
150+ }
151+
152+ if ( part . type === "text" ) {
153+ if ( part . ignored ) return null
154+ return { type : "text" , text : part . text }
155+ }
156+
157+ if ( part . type === "reasoning" ) {
158+ return {
159+ type : "reasoning" ,
160+ text : part . text ,
161+ }
162+ }
163+
164+ if ( part . type === "tool" ) {
165+ const toolPart : any = {
166+ type : "tool" ,
167+ tool : part . tool ,
168+ callID : part . callID ,
169+ }
170+
171+ if ( part . state ?. input ) {
172+ toolPart . input = part . state . input
173+ }
174+ if ( part . state ?. output ) {
175+ toolPart . output = part . state . output
176+ }
177+
178+ return toolPart
179+ }
180+
181+ return null
182+ } )
183+ . filter ( Boolean )
184+ }
185+
186+ return minimized
187+ } )
188+ }
189+
190+ async saveContext ( sessionId : string , messages : any [ ] ) {
191+ if ( ! this . enabled ) return
192+
193+ try {
194+ const contextDir = join ( this . logDir , "context" , sessionId )
195+ if ( ! existsSync ( contextDir ) ) {
196+ await mkdir ( contextDir , { recursive : true } )
197+ }
198+
199+ const minimized = this . minimizeForDebug ( messages )
200+ const timestamp = new Date ( ) . toISOString ( ) . replace ( / [: .] / g, "-" )
201+ const contextFile = join ( contextDir , `${ timestamp } .json` )
202+ await writeFile ( contextFile , JSON . stringify ( minimized , null , 2 ) )
203+ } catch ( error ) { }
204+ }
110205}
0 commit comments