@@ -6,7 +6,6 @@ import { homedir } from "os"
66export class Logger {
77 private logDir : string
88 public enabled : boolean
9- private fileCounter : number = 0
109
1110 constructor ( enabled : boolean ) {
1211 this . enabled = enabled
@@ -109,181 +108,4 @@ export class Logger {
109108 const component = this . getCallerFile ( 2 )
110109 return this . write ( "ERROR" , component , message , data )
111110 }
112-
113- private parseJanitorPrompt ( prompt : string ) : {
114- instructions : string
115- availableToolCallIds : string [ ]
116- sessionHistory : any [ ]
117- responseSchema : any
118- } | null {
119- try {
120- const idsMatch = prompt . match ( / A v a i l a b l e t o o l c a l l I D s f o r a n a l y s i s : \s * ( [ ^ \n ] + ) / )
121- const availableToolCallIds = idsMatch
122- ? idsMatch [ 1 ] . split ( ',' ) . map ( id => id . trim ( ) )
123- : [ ]
124-
125- const historyMatch = prompt . match ( / S e s s i o n h i s t o r y [ ^ \n ] * : \s * \n ( [ \s \S ] * ?) \n \n Y o u M U S T r e s p o n d / )
126- let sessionHistory : any [ ] = [ ]
127-
128- if ( historyMatch ) {
129- const historyText = historyMatch [ 1 ]
130-
131- const fixedJson = this . escapeNewlinesInJson ( historyText )
132- sessionHistory = JSON . parse ( fixedJson )
133- }
134-
135- const instructionsMatch = prompt . match ( / ( [ \s \S ] * ?) \n \n I M P O R T A N T : A v a i l a b l e t o o l c a l l I D s / )
136- const instructions = instructionsMatch
137- ? instructionsMatch [ 1 ] . trim ( )
138- : ''
139-
140- const schemaMatch = prompt . match ( / m a t c h i n g t h i s e x a c t s c h e m a : \s * \n ( \{ [ \s \S ] * ?\} ) \s * $ / )
141- const responseSchema = schemaMatch
142- ? schemaMatch [ 1 ]
143- : null
144-
145- return {
146- instructions,
147- availableToolCallIds,
148- sessionHistory,
149- responseSchema
150- }
151- } catch ( error ) {
152- return null
153- }
154- }
155-
156- private escapeNewlinesInJson ( jsonText : string ) : string {
157- let result = ''
158- let inString = false
159-
160- for ( let i = 0 ; i < jsonText . length ; i ++ ) {
161- const char = jsonText [ i ]
162- const prevChar = i > 0 ? jsonText [ i - 1 ] : ''
163-
164- if ( char === '"' && prevChar !== '\\' ) {
165- inString = ! inString
166- result += char
167- } else if ( char === '\n' && inString ) {
168- result += '\\n'
169- } else {
170- result += char
171- }
172- }
173-
174- return result
175- }
176-
177- private extractReasoningBlocks ( sessionMessages : any [ ] ) : any [ ] {
178- const reasoningBlocks : any [ ] = [ ]
179-
180- for ( const msg of sessionMessages ) {
181- if ( ! msg . parts ) continue
182-
183- for ( const part of msg . parts ) {
184- if ( part . type === "reasoning" ) {
185- // Calculate encrypted content size for different providers
186- let encryptedContentLength = 0
187- if ( part . metadata ?. openai ?. reasoningEncryptedContent ) {
188- encryptedContentLength = part . metadata . openai . reasoningEncryptedContent . length
189- } else if ( part . metadata ?. anthropic ?. signature ) {
190- encryptedContentLength = part . metadata . anthropic . signature . length
191- } else if ( part . metadata ?. google ?. thoughtSignature ) {
192- encryptedContentLength = part . metadata . google . thoughtSignature . length
193- }
194-
195- reasoningBlocks . push ( {
196- messageId : msg . id ,
197- messageRole : msg . role ,
198- text : part . text ,
199- textLength : part . text ?. length || 0 ,
200- encryptedContentLength,
201- time : part . time ,
202- hasMetadata : ! ! part . metadata ,
203- metadataKeys : part . metadata ? Object . keys ( part . metadata ) : [ ]
204- } )
205- }
206- }
207- }
208-
209- return reasoningBlocks
210- }
211-
212- async saveWrappedContext ( sessionID : string , messages : any [ ] , metadata : any , sessionMessages ?: any [ ] ) {
213- if ( ! this . enabled ) return
214-
215- try {
216- await this . ensureLogDir ( )
217-
218- const aiContextDir = join ( this . logDir , "ai-context" )
219- if ( ! existsSync ( aiContextDir ) ) {
220- await mkdir ( aiContextDir , { recursive : true } )
221- }
222-
223- const timestamp = new Date ( ) . toISOString ( ) . replace ( / : / g, '-' ) . replace ( / \. / g, '-' )
224- const counter = ( this . fileCounter ++ ) . toString ( ) . padStart ( 3 , '0' )
225- const filename = `${ timestamp } _${ counter } _${ sessionID . substring ( 0 , 15 ) } .json`
226- const filepath = join ( aiContextDir , filename )
227-
228- const isJanitorShadow = sessionID === "janitor-shadow" &&
229- messages . length === 1 &&
230- messages [ 0 ] ?. role === 'user' &&
231- typeof messages [ 0 ] ?. content === 'string'
232-
233- let content : any
234-
235- if ( isJanitorShadow ) {
236- const parsed = this . parseJanitorPrompt ( messages [ 0 ] . content )
237-
238- if ( parsed ) {
239- content = {
240- timestamp : new Date ( ) . toISOString ( ) ,
241- sessionID,
242- metadata,
243- janitorAnalysis : {
244- instructions : parsed . instructions ,
245- availableToolCallIds : parsed . availableToolCallIds ,
246- protectedTools : [ "task" , "todowrite" , "todoread" ] ,
247- sessionHistory : parsed . sessionHistory ,
248- responseSchema : parsed . responseSchema
249- } ,
250- rawPrompt : messages [ 0 ] . content
251- }
252- } else {
253- content = {
254- timestamp : new Date ( ) . toISOString ( ) ,
255- sessionID,
256- metadata,
257- messages,
258- note : "Failed to parse janitor prompt structure"
259- }
260- }
261- } else {
262- // Extract reasoning blocks from session messages if available
263- const reasoningBlocks = sessionMessages
264- ? this . extractReasoningBlocks ( sessionMessages )
265- : [ ]
266-
267- content = {
268- timestamp : new Date ( ) . toISOString ( ) ,
269- sessionID,
270- metadata,
271- messages,
272- ...( reasoningBlocks . length > 0 && {
273- reasoning : {
274- count : reasoningBlocks . length ,
275- totalTextCharacters : reasoningBlocks . reduce ( ( sum , b ) => sum + b . textLength , 0 ) ,
276- totalEncryptedCharacters : reasoningBlocks . reduce ( ( sum , b ) => sum + b . encryptedContentLength , 0 ) ,
277- blocks : reasoningBlocks
278- }
279- } )
280- }
281- }
282-
283- const jsonString = JSON . stringify ( content , null , 2 )
284-
285- await writeFile ( filepath , jsonString )
286- } catch ( error ) {
287- }
288- }
289111}
0 commit comments