Skip to main content
Glama
agent-action-logger.js5.93 kB
// AGENT ACTION LOGGER // Logs every action taken by agents for rollback/undo capability // Creates snapshots and maintains action history import { promises as fs } from 'fs'; import path from 'path'; import crypto from 'crypto'; export class AgentActionLogger { constructor() { this.logPath = 'C:/MCP/logs/agent-actions'; this.rollbackPath = 'C:/MCP/logs/rollback'; this.currentSession = null; this.sessionActions = []; } // Start a new logging session async startSession(agentName, taskDescription) { const sessionId = this.generateSessionId(); this.currentSession = { id: sessionId, agentName: agentName, taskDescription: taskDescription, startTime: new Date().toISOString(), actions: [], status: 'active' }; console.log(`📝 Session started: ${sessionId} - ${agentName}`); return sessionId; } // Log an action with before/after state async logAction(actionType, details, beforeState = null, afterState = null) { if (!this.currentSession) { throw new Error('No active session - call startSession() first'); } const action = { id: this.generateActionId(), timestamp: new Date().toISOString(), type: actionType, details: details, beforeState: beforeState, afterState: afterState, rollbackable: this.isRollbackable(actionType) }; this.currentSession.actions.push(action); this.sessionActions.push(action); // Save incremental log await this.saveIncrementalLog(action); console.log(` ✓ Action logged: ${actionType}`); return action.id; } // Log file creation async logFileCreation(filePath, content) { return await this.logAction('file_create', { description: `Created file: ${filePath}`, filePath: filePath, fileSize: content.length }, null, { filePath: filePath, content: content, hash: this.hashContent(content) }); } // Log file modification async logFileModification(filePath, oldContent, newContent) { return await this.logAction('file_modify', { description: `Modified file: ${filePath}`, filePath: filePath, changeSize: newContent.length - oldContent.length }, { filePath: filePath, content: oldContent, hash: this.hashContent(oldContent) }, { filePath: filePath, content: newContent, hash: this.hashContent(newContent) }); } // End session and save complete log async endSession(status = 'completed') { if (!this.currentSession) { throw new Error('No active session to end'); } this.currentSession.endTime = new Date().toISOString(); this.currentSession.status = status; this.currentSession.totalActions = this.currentSession.actions.length; const start = new Date(this.currentSession.startTime); const end = new Date(this.currentSession.endTime); this.currentSession.duration = (end - start) / 1000; await this.saveCompleteSessionLog(); if (this.hasRollbackableActions()) { await this.createRollbackSnapshot(); } console.log(`✅ Session ended: ${this.currentSession.id}`); const completedSession = this.currentSession; this.currentSession = null; this.sessionActions = []; return completedSession; } // Create rollback snapshot async createRollbackSnapshot() { const snapshotId = `snapshot_${Date.now()}`; const snapshot = { id: snapshotId, sessionId: this.currentSession.id, createdAt: new Date().toISOString(), agentName: this.currentSession.agentName, rollbackableActions: this.currentSession.actions.filter(a => a.rollbackable) }; const snapshotPath = path.join(this.rollbackPath, `${snapshotId}.json`); await fs.writeFile(snapshotPath, JSON.stringify(snapshot, null, 2)); console.log(`📸 Rollback snapshot: ${snapshotId}`); return snapshotId; } // Helper methods isRollbackable(actionType) { return ['file_create', 'file_modify', 'file_delete', 'dir_create'].includes(actionType); } hasRollbackableActions() { return this.currentSession.actions.some(a => a.rollbackable); } generateSessionId() { return `${Date.now()}_${Math.random().toString(36).substring(7)}`; } generateActionId() { return crypto.randomBytes(8).toString('hex'); } hashContent(content) { return crypto.createHash('sha256').update(content).digest('hex'); } getDailyLogFileName() { const date = new Date().toISOString().split('T')[0]; return `actions_${date}.log`; } async saveIncrementalLog(action) { const dailyLogFile = this.getDailyLogFileName(); const logPath = path.join(this.logPath, dailyLogFile); const logEntry = JSON.stringify(action) + '\n'; await fs.appendFile(logPath, logEntry).catch(async () => { await fs.writeFile(logPath, logEntry); }); } async saveCompleteSessionLog() { const sessionLogPath = path.join( this.logPath, `session_${this.currentSession.id}.json` ); await fs.writeFile( sessionLogPath, JSON.stringify(this.currentSession, null, 2) ); } } export const actionLogger = new AgentActionLogger();

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bermingham85/mcp-puppet-pipeline'

If you have feedback or need assistance with the MCP directory API, please join our Discord server