import { eq } from "drizzle-orm"; import { db } from "../../db/db"; import { agentsTable, type Agent, type AgentCapabilities, type AgentKind } from "../../db/schema"; import { LOCAL_AGENT_CAPABILITIES, LOCAL_AGENT_ID, LOCAL_AGENT_KIND, LOCAL_AGENT_NAME } from "./constants"; type AgentConnectionRegistration = { agentId: string; organizationId: string | null; agentName: string; agentKind: AgentKind; capabilities?: AgentCapabilities; connectedAt?: number; }; const listAgents = async (organizationId?: string | null) => { if (organizationId === undefined) { return db.query.agentsTable.findMany({ orderBy: { createdAt: "asc" } }); } if (organizationId === null) { return db.query.agentsTable.findMany({ where: { organizationId: { isNull: true } }, orderBy: { createdAt: "asc" }, }); } return db.query.agentsTable.findMany({ where: { organizationId }, orderBy: { createdAt: "asc" }, }); }; const getAgent = async (agentId: string) => { return db.query.agentsTable.findFirst({ where: { id: agentId } }); }; const ensureLocalAgent = async () => { const existing = await getAgent(LOCAL_AGENT_ID); if (existing) { return existing; } await db.insert(agentsTable).values({ id: LOCAL_AGENT_ID, organizationId: null, name: LOCAL_AGENT_NAME, kind: LOCAL_AGENT_KIND, status: "offline", capabilities: LOCAL_AGENT_CAPABILITIES, updatedAt: Date.now(), }); return getAgent(LOCAL_AGENT_ID); }; const markAgentConnecting = async (params: AgentConnectionRegistration) => { const { agentId, organizationId, agentName, agentKind, capabilities, connectedAt = Date.now() } = params; await db .insert(agentsTable) .values({ id: agentId, organizationId, name: agentName, kind: agentKind, status: "connecting", capabilities: capabilities ?? {}, lastSeenAt: connectedAt, updatedAt: connectedAt, }) .onConflictDoUpdate({ target: agentsTable.id, set: { organizationId, name: agentName, kind: agentKind, status: "connecting", lastSeenAt: connectedAt, updatedAt: connectedAt, capabilities: capabilities ?? {}, }, }); return getAgent(agentId); }; const updateAgentRuntime = async (agentId: string, values: Partial) => { const [updatedAgent] = await db.update(agentsTable).set(values).where(eq(agentsTable.id, agentId)).returning(); if (!updatedAgent) { throw new Error(`Agent ${agentId} not found`); } return updatedAgent; }; const markAgentOnline = async (agentId: string, readyAt = Date.now(), metadata?: AgentCapabilities) => { return updateAgentRuntime(agentId, { status: "online", capabilities: metadata, lastSeenAt: readyAt, lastReadyAt: readyAt, updatedAt: readyAt, }); }; const markAgentSeen = async (agentId: string, seenAt = Date.now()) => { return updateAgentRuntime(agentId, { lastSeenAt: seenAt, updatedAt: seenAt, }); }; const markAgentOffline = async (agentId: string, disconnectedAt = Date.now()) => { return updateAgentRuntime(agentId, { status: "offline", updatedAt: disconnectedAt, }); }; export const agentsService = { listAgents, getAgent, ensureLocalAgent, markAgentConnecting, markAgentOnline, markAgentSeen, markAgentOffline, };