11import { Injectable , Inject , NotFoundException , BadRequestException } from '@nestjs/common' ;
22import { eq , and , desc } from 'drizzle-orm' ;
3- import { agentConfigs , agentDecisions , agentTrainingSnapshots } from '@haip/database' ;
3+ import { agentConfigs , agentDecisions , agentTrainingSnapshots , auditLogs } from '@haip/database' ;
44import { DRIZZLE } from '../../database/database.module' ;
55import { WebhookService } from '../webhook/webhook.service' ;
66import type {
@@ -165,6 +165,17 @@ export class AgentService {
165165 . where ( eq ( agentDecisions . id , decisionId ) )
166166 . returning ( ) ;
167167
168+ await this . db . insert ( auditLogs ) . values ( {
169+ propertyId,
170+ action : 'update' ,
171+ entityType : 'agent_decision' ,
172+ entityId : decisionId ,
173+ userId : userId ?? null ,
174+ previousValue : { status : 'pending' } ,
175+ newValue : { status : 'approved' , agentType : decision . agentType , decisionType : decision . decisionType } ,
176+ description : `Agent decision approved and executed: ${ decision . agentType } /${ decision . decisionType } ` ,
177+ } ) ;
178+
168179 await this . webhookService . emit (
169180 'agent.decision_executed' ,
170181 'agent_decision' ,
@@ -194,6 +205,17 @@ export class AgentService {
194205 . where ( eq ( agentDecisions . id , decisionId ) )
195206 . returning ( ) ;
196207
208+ await this . db . insert ( auditLogs ) . values ( {
209+ propertyId,
210+ action : 'update' ,
211+ entityType : 'agent_decision' ,
212+ entityId : decisionId ,
213+ userId : userId ?? null ,
214+ previousValue : { status : 'pending' } ,
215+ newValue : { status : 'rejected' , reason : reason ?? null } ,
216+ description : `Agent decision rejected: ${ decision . agentType } /${ decision . decisionType } ` ,
217+ } ) ;
218+
197219 return updated ;
198220 }
199221
@@ -260,8 +282,13 @@ export class AgentService {
260282 return config ;
261283 }
262284
263- /** Update agent config. */
264- async updateConfig ( propertyId : string , agentType : string , updates : Record < string , unknown > ) {
285+ /** Update agent config — writes an audit log row describing the diff. */
286+ async updateConfig (
287+ propertyId : string ,
288+ agentType : string ,
289+ updates : Record < string , unknown > ,
290+ userId ?: string ,
291+ ) {
265292 const config = await this . getOrCreateConfig ( propertyId , agentType ) ;
266293
267294 const setValues : Record < string , unknown > = { updatedAt : new Date ( ) } ;
@@ -277,6 +304,36 @@ export class AgentService {
277304 . where ( eq ( agentConfigs . id , config . id ) )
278305 . returning ( ) ;
279306
307+ // Build diff of the fields the user actually changed (sensitive config only).
308+ const auditFields = [ 'isEnabled' , 'mode' , 'autopilotConfidenceThreshold' , 'config' ] ;
309+ const diff : Record < string , { old : unknown ; new : unknown } > = { } ;
310+ for ( const field of auditFields ) {
311+ if ( updates [ field ] === undefined ) continue ;
312+ const oldValue = ( config as any ) [ field ] ;
313+ const newValue = ( updated as any ) [ field ] ;
314+ // Only record if actually changed (string-compare to handle numeric thresholds).
315+ if ( JSON . stringify ( oldValue ) !== JSON . stringify ( newValue ) ) {
316+ diff [ field ] = { old : oldValue , new : newValue } ;
317+ }
318+ }
319+
320+ if ( Object . keys ( diff ) . length > 0 ) {
321+ await this . db . insert ( auditLogs ) . values ( {
322+ propertyId,
323+ action : 'update' ,
324+ entityType : 'agent_config' ,
325+ entityId : config . id ,
326+ userId : userId ?? null ,
327+ previousValue : Object . fromEntries (
328+ Object . entries ( diff ) . map ( ( [ k , v ] ) => [ k , v . old ] ) ,
329+ ) ,
330+ newValue : Object . fromEntries (
331+ Object . entries ( diff ) . map ( ( [ k , v ] ) => [ k , v . new ] ) ,
332+ ) ,
333+ description : `Agent config updated: ${ agentType } (${ Object . keys ( diff ) . join ( ', ' ) } )` ,
334+ } ) ;
335+ }
336+
280337 return updated ;
281338 }
282339
0 commit comments