import { eq, and, desc, gte } from "drizzle-orm"; import { agents, agentMetrics, agentHistory, agentAccessControl, type Agent, type InsertAgent, type AgentMetric, type InsertAgentMetric } from "../drizzle/schema"; import { getDb } from "./db"; import { nanoid } from "nanoid"; /** * Создать нового агента */ export async function createAgent(userId: number, data: InsertAgent): Promise { const db = await getDb(); if (!db) return null; try { const result = await db.insert(agents).values({ ...data, userId, }); const agentId = result[0].insertId; const created = await db.select().from(agents).where(eq(agents.id, Number(agentId))).limit(1); return created[0] || null; } catch (error) { console.error("[DB] Failed to create agent:", error); throw error; } } /** * Получить агента по ID */ export async function getAgentById(agentId: number): Promise { const db = await getDb(); if (!db) return null; try { const result = await db.select().from(agents).where(eq(agents.id, agentId)).limit(1); return result[0] || null; } catch (error) { console.error("[DB] Failed to get agent:", error); return null; } } /** * Получить все агенты пользователя */ export async function getUserAgents(userId: number): Promise { const db = await getDb(); if (!db) return []; try { return await db.select().from(agents).where(eq(agents.userId, userId)); } catch (error) { console.error("[DB] Failed to get user agents:", error); return []; } } /** * Обновить конфигурацию агента */ export async function updateAgent(agentId: number, updates: Partial): Promise { const db = await getDb(); if (!db) return null; try { await db.update(agents).set(updates).where(eq(agents.id, agentId)); return getAgentById(agentId); } catch (error) { console.error("[DB] Failed to update agent:", error); throw error; } } /** * Удалить агента */ export async function deleteAgent(agentId: number): Promise { const db = await getDb(); if (!db) return false; try { await db.delete(agents).where(eq(agents.id, agentId)); return true; } catch (error) { console.error("[DB] Failed to delete agent:", error); return false; } } /** * Сохранить метрику запроса */ export async function saveMetric(agentId: number, data: Omit): Promise { const db = await getDb(); if (!db) return null; try { const requestId = nanoid(); const result = await db.insert(agentMetrics).values({ ...data, agentId, requestId, }); const metricId = result[0].insertId; const created = await db.select().from(agentMetrics).where(eq(agentMetrics.id, Number(metricId))).limit(1); return created[0] || null; } catch (error) { console.error("[DB] Failed to save metric:", error); throw error; } } /** * Получить метрики агента за последние N часов */ export async function getAgentMetrics(agentId: number, hoursBack: number = 24): Promise { const db = await getDb(); if (!db) return []; try { const since = new Date(Date.now() - hoursBack * 60 * 60 * 1000); return await db .select() .from(agentMetrics) .where(and(eq(agentMetrics.agentId, agentId), gte(agentMetrics.createdAt, since))) .orderBy(desc(agentMetrics.createdAt)); } catch (error) { console.error("[DB] Failed to get agent metrics:", error); return []; } } /** * Получить статистику агента */ export async function getAgentStats(agentId: number, hoursBack: number = 24) { const db = await getDb(); if (!db) return null; try { const metrics = await getAgentMetrics(agentId, hoursBack); const totalRequests = metrics.length; const successRequests = metrics.filter((m) => m.status === "success").length; const errorRequests = metrics.filter((m) => m.status === "error").length; const avgProcessingTime = metrics.length > 0 ? metrics.reduce((sum, m) => sum + m.processingTimeMs, 0) / metrics.length : 0; const totalTokens = metrics.reduce((sum, m) => sum + (m.totalTokens || 0), 0); const avgTokensPerRequest = metrics.length > 0 ? totalTokens / metrics.length : 0; return { totalRequests, successRequests, errorRequests, successRate: totalRequests > 0 ? (successRequests / totalRequests) * 100 : 0, avgProcessingTime: Math.round(avgProcessingTime), totalTokens, avgTokensPerRequest: Math.round(avgTokensPerRequest), period: `${hoursBack}h`, }; } catch (error) { console.error("[DB] Failed to get agent stats:", error); return null; } } /** * Получить историю запросов агента */ export async function getAgentHistory(agentId: number, limit: number = 50) { const db = await getDb(); if (!db) return []; try { return await db .select() .from(agentHistory) .where(eq(agentHistory.agentId, agentId)) .orderBy(desc(agentHistory.createdAt)) .limit(limit); } catch (error) { console.error("[DB] Failed to get agent history:", error); return []; } } /** * Получить управление доступами для агента */ export async function getAgentAccessControl(agentId: number) { const db = await getDb(); if (!db) return []; try { return await db.select().from(agentAccessControl).where(eq(agentAccessControl.agentId, agentId)); } catch (error) { console.error("[DB] Failed to get agent access control:", error); return []; } } /** * Обновить управление доступами для инструмента */ export async function updateToolAccess(agentId: number, tool: string, updates: Partial) { const db = await getDb(); if (!db) return null; try { const existing = await db .select() .from(agentAccessControl) .where(and(eq(agentAccessControl.agentId, agentId), eq(agentAccessControl.tool, tool))) .limit(1); if (existing.length > 0) { await db .update(agentAccessControl) .set(updates) .where(and(eq(agentAccessControl.agentId, agentId), eq(agentAccessControl.tool, tool))); } else { await db.insert(agentAccessControl).values({ agentId, tool, ...updates, }); } const result = await db .select() .from(agentAccessControl) .where(and(eq(agentAccessControl.agentId, agentId), eq(agentAccessControl.tool, tool))) .limit(1); return result[0] || null; } catch (error) { console.error("[DB] Failed to update tool access:", error); throw error; } }