@@ -28,6 +28,47 @@ dotenv.config();
2828
2929@Injectable ( )
3030export class AskService {
31+ private sanitizeToolText ( value : string , maxLength = 1000 ) {
32+ const sanitized = value
33+ . replace (
34+ / d a t a : [ ^ " ' ( ) \s > ] + ; b a s e 6 4 , [ A - Z a - z 0 - 9 + / = \r \n ] + / g,
35+ "[inline base64 omitted]"
36+ )
37+ . replace ( / < i m g \b [ ^ > ] * > / gi, "[image omitted]" )
38+ . replace ( / \s + / g, " " )
39+ . trim ( ) ;
40+
41+ return sanitized . length > maxLength
42+ ? `${ sanitized . slice ( 0 , maxLength ) } ...`
43+ : sanitized ;
44+ }
45+
46+ private compactToolPayload ( value : any , depth = 0 ) : any {
47+ if ( value === null || value === undefined ) return value ;
48+ if ( typeof value === "string" ) return this . sanitizeToolText ( value ) ;
49+ if ( typeof value !== "object" ) return value ;
50+ if ( value instanceof Date ) return value . toISOString ( ) ;
51+ if ( depth >= 6 ) return "[nested data omitted]" ;
52+
53+ if ( Array . isArray ( value ) ) {
54+ const limited = value . slice ( 0 , 100 ) ;
55+ return limited . map ( ( item ) => this . compactToolPayload ( item , depth + 1 ) ) ;
56+ }
57+
58+ const omittedKeys = new Set ( [
59+ "attachments" ,
60+ "avatarUrl" ,
61+ "comments" ,
62+ "phone" ,
63+ "photo" ,
64+ ] ) ;
65+ return Object . fromEntries (
66+ Object . entries ( value )
67+ . filter ( ( [ key ] ) => ! omittedKeys . has ( key ) )
68+ . map ( ( [ key , item ] ) => [ key , this . compactToolPayload ( item , depth + 1 ) ] )
69+ ) ;
70+ }
71+
3172 private emitThinking ( socket : Socket | undefined , message : string ) {
3273 if ( socket ) {
3374 socket . emit ( "ai_thinking" , { type : "thinking" , message } ) ;
@@ -94,7 +135,11 @@ export class AskService {
94135 } else if ( fn === "getDeployTasks" ) {
95136 return await getDeployTasks ( args ?. projectId ) ;
96137 } else if ( fn === "getDoneTasks" ) {
97- return await getDoneTasks ( args ?. projectId , args ?. dateType ) ;
138+ return await getDoneTasks (
139+ args ?. projectId ,
140+ args ?. dateType ,
141+ args ?. daysBack
142+ ) ;
98143 } else if ( fn === "getUnassignedTasks" ) {
99144 return await getUnassignedTasks ( args ?. projectId ) ;
100145 } else if ( fn === "getUrgentTasks" ) {
@@ -126,7 +171,7 @@ export class AskService {
126171 const getMessages = await prisma . chatMessage . findMany ( {
127172 where : { userId : userId || "" } ,
128173 orderBy : { createdAt : "desc" } ,
129- take : 10 ,
174+ take : 6 ,
130175 } ) ;
131176
132177 const userMessages = getMessages . reverse ( ) ;
@@ -146,7 +191,6 @@ export class AskService {
146191 role : "system" ,
147192 content : `User Selected Project ID: ${ data . projectId } ` ,
148193 } ,
149- ...data . messages ,
150194 ] ;
151195
152196 this . emitThinking ( socket , "🧠 Thinking..." ) ;
@@ -205,6 +249,7 @@ export class AskService {
205249 // inject cacheDate for certain read-only tools to improve cache key uniqueness
206250 if ( fn === "getRepos" || fn === "getContributors" ) {
207251 args . cacheDate = new Date ( ) . toISOString ( ) . split ( "T" ) [ 0 ] ;
252+ args . resultShapeVersion = 2 ;
208253 }
209254
210255 // Try cache lookup (aiToolCache stores raw result in 'result' column)
@@ -224,7 +269,7 @@ export class AskService {
224269 let toolResult : any = null ;
225270
226271 if ( cached && cached . result !== null && cached . result !== undefined ) {
227- toolResult = cached . result ;
272+ toolResult = this . compactToolPayload ( cached . result ) ;
228273 this . emitToolCall ( socket , fn , args ) ;
229274 this . emitToolResult ( socket , fn , toolResult ) ;
230275
@@ -237,7 +282,9 @@ export class AskService {
237282 } else {
238283 // Execute actual tool
239284 this . emitToolCall ( socket , fn , args ) ;
240- toolResult = await this . execToolByName ( fn , args ) ;
285+ toolResult = this . compactToolPayload (
286+ await this . execToolByName ( fn , args )
287+ ) ;
241288 this . emitToolResult ( socket , fn , toolResult ) ;
242289
243290 // push tool result into conversation
0 commit comments