feat(gateway): add sender presence tracking

This commit is contained in:
William Valentin
2026-02-15 19:28:16 -08:00
parent 421942f66d
commit c6e3d09ecc
11 changed files with 358 additions and 8 deletions
+34
View File
@@ -11,6 +11,16 @@ export interface TokenUsageEntry {
total: { inputTokens: number; outputTokens: number; calls: number; estimatedCost: number };
}
export interface PresenceEntry {
channel: string;
senderId: string;
senderName?: string;
firstSeenAt: number;
lastSeenAt: number;
messageCount: number;
status: 'online' | 'offline';
}
export interface SystemHandlerDeps {
startTime: number;
version: string;
@@ -31,6 +41,8 @@ export interface SystemHandlerDeps {
getActiveRequests?: () => ActiveRequestInfo[];
/** Optional callback to retrieve all services (channels + automation). */
getServices?: () => ServiceInfo[];
/** Optional callback to retrieve tracked sender presence. */
getPresence?: (opts?: { channel?: string; status?: 'online' | 'offline'; limit?: number }) => PresenceEntry[];
}
export function createSystemHandlers(deps: SystemHandlerDeps) {
@@ -78,6 +90,28 @@ export function createSystemHandlers(deps: SystemHandlerDeps) {
return makeResponse(request.id, { services: deps.getServices() });
},
'system.presence': async (request: GatewayRequest): Promise<OutboundMessage> => {
if (!deps.getPresence) {
return makeResponse(request.id, { presence: [], summary: { total: 0, online: 0, offline: 0 } });
}
const params = request.params as { channel?: string; status?: 'online' | 'offline'; limit?: number } | undefined;
const presence = deps.getPresence({
channel: params?.channel,
status: params?.status,
limit: params?.limit,
});
const online = presence.filter((entry) => entry.status === 'online').length;
return makeResponse(request.id, {
presence,
summary: {
total: presence.length,
online,
offline: presence.length - online,
},
});
},
'system.usage': async (request: GatewayRequest): Promise<OutboundMessage> => {
const uptime = Math.floor((Date.now() - deps.startTime) / 1000);
const usage = deps.getUsage?.() ?? { totalSessions: 0, activeConnections: 0 };