import { type AgentStatus } from '../../constants.js'; /** * Agent heartbeat record structure for teamAgentStatus.json */ export interface AgentHeartbeat { /** Agent identifier (e.g., 'orchestrator' or team member ID) */ agentId: string; /** PTY session name */ sessionName: string; /** Team member ID (only for team members, not orchestrator) */ teamMemberId?: string; /** Current agent registration status */ agentStatus: AgentStatus; /** Timestamp of last API activity (proof of life) */ lastActiveTime: string; /** When this agent record was first created */ createdAt: string; /** When this agent record was last updated */ updatedAt: string; } /** * Structure of teamAgentStatus.json file */ export interface TeamAgentStatusFile { /** Orchestrator agent heartbeat */ orchestrator: AgentHeartbeat; /** Team member agent heartbeats indexed by teamMemberId */ teamMembers: Record; /** File metadata */ metadata: { lastUpdated: string; version: string; }; } /** * Batched agent status update for efficient bulk operations */ export interface BatchedStatusUpdate { /** Agent identifier */ agentId: string; /** PTY session name */ sessionName: string; /** Team member ID (optional, only for team members) */ teamMemberId?: string; /** New agent status */ agentStatus: AgentStatus; /** Timestamp when this update was queued */ timestamp: string; } /** * Agent Status Batcher - handles efficient bulk updates with timeout-based flushing * * Batches multiple agent status updates together to reduce file I/O overhead. * Automatically flushes batches after 2 seconds or when batch size reaches 50 items. */ export declare class AgentStatusBatcher { private logger; private pendingUpdates; private flushTimer; private readonly maxBatchSize; private readonly flushTimeoutMs; private readonly heartbeatService; constructor(heartbeatService: AgentHeartbeatService); /** * Add an agent status update to the batch queue * * @param agentId - Agent identifier * @param sessionName - PTY session name * @param agentStatus - New agent status * @param teamMemberId - Team member ID (optional, only for team members) */ addUpdate(agentId: string, sessionName: string, agentStatus: AgentStatus, teamMemberId?: string): void; /** * Schedule a batch flush after the timeout period */ private scheduleFlush; /** * Immediately flush all pending updates */ flushImmediately(): Promise; /** * Get current batch size (for testing/monitoring) */ getBatchSize(): number; /** * Clear all pending updates (for testing/cleanup) */ clear(): void; } /** * Agent Heartbeat Service - manages agent proof-of-life tracking * * This service transforms every API call into an agent heartbeat, * maintaining agent status and last active time in teamAgentStatus.json. * * Key responsibilities: * - Update agent status and lastActiveTime on every API call * - Batch updates for efficiency (2-second timeout, 50-item max) * - Detect stale agents (30-minute threshold) * - Manage separate teamAgentStatus.json file (owned by Agent Registration) */ export declare class AgentHeartbeatService { private logger; private crewlyHome; private teamAgentStatusFile; private fileLocks; private batcher; private static instance; constructor(crewlyHome?: string); /** * Get singleton instance to prevent multiple instances from interfering */ static getInstance(crewlyHome?: string): AgentHeartbeatService; /** * Clear singleton instance (useful for testing) */ static clearInstance(): void; /** * Ensure required directories exist */ private ensureDirectories; /** * Update agent heartbeat - called by every API * * This is the main entry point that transforms API calls into agent heartbeats. * Uses batching for efficiency and error resilience. * * @param sessionName - PTY session name from API call * @param teamMemberId - Team member ID from API call (optional) * @param agentStatus - Current agent status (defaults to 'active') * * @example * ```typescript * // Called by every API handler * await updateAgentHeartbeat('dev-session-1', 'member_123', 'active'); * ``` */ updateAgentHeartbeat(sessionName: string, teamMemberId?: string, agentStatus?: AgentStatus): Promise; /** * Determine agent ID from session name and team member ID */ private determineAgentId; /** * Process batched updates - called by AgentStatusBatcher * * @param updates - Array of batched status updates to process */ processBatchedUpdates(updates: BatchedStatusUpdate[]): Promise; /** * Apply a single heartbeat update to the status data */ private applyHeartbeatUpdate; /** * Load teamAgentStatus.json file with proper initialization */ private loadTeamAgentStatusFile; /** * Save teamAgentStatus.json file with atomic write */ private saveTeamAgentStatusFile; /** * Ensure teamAgentStatus.json file exists with proper structure */ private ensureTeamAgentStatusFile; /** * Create default teamAgentStatus.json structure */ private createDefaultTeamAgentStatusFile; /** * Create default orchestrator heartbeat record */ private createDefaultOrchestratorHeartbeat; /** * Create default team member heartbeat record */ private createDefaultTeamMemberHeartbeat; /** * Detect stale agents based on lastActiveTime threshold * * @param thresholdMinutes - Minutes of inactivity before considering agent stale (default: 30) * @returns Array of stale agent IDs that should be marked as 'potentialInactive' */ detectStaleAgents(thresholdMinutes?: number): Promise; /** * Get current agent status and heartbeat information * * @param agentId - Agent identifier or team member ID * @returns Agent heartbeat information or null if not found */ getAgentHeartbeat(agentId: string): Promise; /** * Get all agent heartbeats * * @returns Complete team agent status data */ getAllAgentHeartbeats(): Promise; /** * Atomic write operation with file locking to prevent race conditions */ private atomicWriteFile; /** * Performs the actual atomic write using a temporary file and rename */ private performAtomicWrite; /** * Flush any pending batched updates immediately * Useful for testing or ensuring all updates are persisted before shutdown */ flushPendingUpdates(): Promise; } /** * Convenience function to update agent heartbeat * Creates a singleton instance and calls updateAgentHeartbeat * * This is the main function that all API handlers should call. * * @param sessionName - PTY session name from API call * @param teamMemberId - Team member ID from API call (optional) * @param agentStatus - Current agent status (defaults to 'active') * * @example * ```typescript * // In API handler: * import { updateAgentHeartbeat } from '../services/agent/agent-heartbeat.service.js'; * * export async function handleSendMessage(params: any) { * try { * // Update heartbeat first * await updateAgentHeartbeat(params.sessionName, params.teamMemberId); * * // Handle the actual API logic * // ... * } catch (error) { * // Handle errors * } * } * ``` */ export declare function updateAgentHeartbeat(sessionName: string, teamMemberId?: string, agentStatus?: AgentStatus): Promise; //# sourceMappingURL=agent-heartbeat.service.d.ts.map