/** * SQLite implementation of IEventStore — thin facade. * * Delegates to focused repository classes (Story S-7.5): * - EventRepository — event CRUD * - SessionRepository — session CRUD * - AgentRepository — agent CRUD * - AlertRepository — alert rules + history * - AnalyticsRepository — analytics and stats * - RetentionService — data retention/cleanup */ import type { AgentLensEvent, EventQuery, EventQueryResult, Session, SessionQuery, Agent, AlertRule, AlertHistory, } from '@agentkitai/agentlens-core'; import type { IEventStore, AnalyticsResult, StorageStats } from '@agentkitai/agentlens-core'; import type { SqliteDb } from './index.js'; import { EventRepository } from './repositories/event-repository.js'; import { SessionRepository } from './repositories/session-repository.js'; import { AgentRepository } from './repositories/agent-repository.js'; import { AlertRepository } from './repositories/alert-repository.js'; import { AnalyticsRepository } from './repositories/analytics-repository.js'; import { RetentionService } from './services/retention-service.js'; // Re-export for backward compatibility export { safeJsonParse } from './shared/query-helpers.js'; export class SqliteEventStore implements IEventStore { private eventRepo: EventRepository; private sessionRepo: SessionRepository; private agentRepo: AgentRepository; private alertRepo: AlertRepository; private analyticsRepo: AnalyticsRepository; private retentionService: RetentionService; constructor(private db: SqliteDb) { this.eventRepo = new EventRepository(db); this.sessionRepo = new SessionRepository(db); this.agentRepo = new AgentRepository(db); this.alertRepo = new AlertRepository(db); this.analyticsRepo = new AnalyticsRepository(db); this.retentionService = new RetentionService(db); } // ─── Events ──────────────────────────────────────────────── async insertEvents(eventList: AgentLensEvent[]): Promise { this.eventRepo.insertEvents( eventList, (tx, event, tenantId) => this.sessionRepo.handleSessionUpdate(tx, event, tenantId), (tx, event, tenantId) => this.agentRepo.handleAgentUpsert(tx, event, tenantId), ); } async queryEvents(query: EventQuery): Promise { return this.eventRepo.queryEvents(query); } async getEvent(id: string, tenantId?: string, orgId?: string, projectId?: string): Promise { return this.eventRepo.getEvent(id, tenantId, orgId, projectId); } async getSessionTimeline(sessionId: string, tenantId?: string, orgId?: string, projectId?: string): Promise { return this.eventRepo.getSessionTimeline(sessionId, tenantId, orgId, projectId); } async getLastEventHash(sessionId: string, tenantId?: string, orgId?: string, projectId?: string): Promise { return this.eventRepo.getLastEventHash(sessionId, tenantId, orgId, projectId); } async countEvents(query: Omit): Promise { return this.eventRepo.countEvents(query); } async countEventsBatch( query: { agentId: string; from: string; to: string; tenantId?: string }, ): Promise<{ total: number; error: number; critical: number; toolError: number }> { return this.eventRepo.countEventsBatch(query); } // ─── Sessions ────────────────────────────────────────────── async upsertSession(session: Partial & { id: string }): Promise { return this.sessionRepo.upsertSession(session); } async querySessions(query: SessionQuery): Promise<{ sessions: Session[]; total: number }> { return this.sessionRepo.querySessions(query); } async getSession(id: string, tenantId?: string, orgId?: string, projectId?: string): Promise { return this.sessionRepo.getSession(id, tenantId, orgId, projectId); } async sumSessionCost( query: { agentId: string; from: string; tenantId?: string }, ): Promise { return this.sessionRepo.sumSessionCost(query); } // ─── Agents ──────────────────────────────────────────────── async upsertAgent(agent: Partial & { id: string }): Promise { return this.agentRepo.upsertAgent(agent); } async pauseAgent(tenantId: string, agentId: string, reason: string): Promise { return this.agentRepo.pauseAgent(tenantId, agentId, reason); } async unpauseAgent(tenantId: string, agentId: string, clearModelOverride?: boolean): Promise { return this.agentRepo.unpauseAgent(tenantId, agentId, clearModelOverride); } async setModelOverride(tenantId: string, agentId: string, model: string): Promise { return this.agentRepo.setModelOverride(tenantId, agentId, model); } async listAgents(tenantId?: string, orgId?: string, projectId?: string): Promise { return this.agentRepo.listAgents(tenantId, orgId, projectId); } async getAgent(id: string, tenantId?: string, orgId?: string, projectId?: string): Promise { return this.agentRepo.getAgent(id, tenantId, orgId, projectId); } // ─── Alerts ──────────────────────────────────────────────── async createAlertRule(rule: AlertRule): Promise { return this.alertRepo.createAlertRule(rule); } async updateAlertRule(id: string, updates: Partial, tenantId?: string): Promise { return this.alertRepo.updateAlertRule(id, updates, tenantId); } async deleteAlertRule(id: string, tenantId?: string): Promise { return this.alertRepo.deleteAlertRule(id, tenantId); } async listAlertRules(tenantId?: string): Promise { return this.alertRepo.listAlertRules(tenantId); } async getAlertRule(id: string, tenantId?: string): Promise { return this.alertRepo.getAlertRule(id, tenantId); } async insertAlertHistory(entry: AlertHistory): Promise { return this.alertRepo.insertAlertHistory(entry); } async listAlertHistory(opts?: { ruleId?: string; limit?: number; offset?: number; tenantId?: string; }): Promise<{ entries: AlertHistory[]; total: number }> { return this.alertRepo.listAlertHistory(opts); } // ─── Analytics & Stats ───────────────────────────────────── async getAnalytics(params: { from: string; to: string; agentId?: string; granularity: 'hour' | 'day' | 'week'; tenantId?: string; excludeMetrics?: boolean; }): Promise { return this.analyticsRepo.getAnalytics(params); } async getStats(tenantId?: string): Promise { return this.analyticsRepo.getStats(tenantId); } // ─── Maintenance ─────────────────────────────────────────── async applyRetention( olderThan: string, tenantId?: string, ): Promise<{ deletedCount: number }> { return this.retentionService.applyRetention(olderThan, tenantId); } }