190 lines
5.7 KiB
TypeScript
190 lines
5.7 KiB
TypeScript
/**
|
|
* HarborForge Calendar Scheduler
|
|
*
|
|
* PLG-CAL-002: Plugin-side handling for pending slot execution.
|
|
*
|
|
* Responsibilities:
|
|
* - Run calendar heartbeat every minute
|
|
* - Detect when agent is Idle and slots are pending
|
|
* - Wake agent with task context
|
|
* - Handle slot status transitions (attended, ongoing, deferred)
|
|
* - Manage agent status transitions (idle → busy/on_call)
|
|
*
|
|
* Design reference: NEXT_WAVE_DEV_DIRECTION.md §6 (Agent wakeup mechanism)
|
|
*/
|
|
import { CalendarBridgeClient } from './calendar-bridge';
|
|
import { CalendarSlotResponse, AgentStatusValue } from './types';
|
|
export interface CalendarSchedulerConfig {
|
|
/** Calendar bridge client for backend communication */
|
|
bridge: CalendarBridgeClient;
|
|
/** Function to get current agent status from backend */
|
|
getAgentStatus: () => Promise<AgentStatusValue | null>;
|
|
/** Function to wake/spawn agent with task context */
|
|
wakeAgent: (context: AgentWakeContext) => Promise<boolean>;
|
|
/** Logger instance */
|
|
logger: {
|
|
info: (...args: any[]) => void;
|
|
error: (...args: any[]) => void;
|
|
debug: (...args: any[]) => void;
|
|
warn: (...args: any[]) => void;
|
|
};
|
|
/** Heartbeat interval in milliseconds (default: 60000) */
|
|
heartbeatIntervalMs?: number;
|
|
/** Enable verbose debug logging */
|
|
debug?: boolean;
|
|
}
|
|
/**
|
|
* Context passed to agent when waking for slot execution.
|
|
* This is the payload the agent receives to understand what to do.
|
|
*/
|
|
export interface AgentWakeContext {
|
|
/** The slot to execute */
|
|
slot: CalendarSlotResponse;
|
|
/** Human-readable task description */
|
|
taskDescription: string;
|
|
/** Prompt/instructions for the agent */
|
|
prompt: string;
|
|
/** Whether this is a virtual slot (needs materialization) */
|
|
isVirtual: boolean;
|
|
}
|
|
/**
|
|
* Current execution state tracked by the scheduler.
|
|
*/
|
|
interface SchedulerState {
|
|
/** Whether scheduler is currently running */
|
|
isRunning: boolean;
|
|
/** Currently executing slot (null if idle) */
|
|
currentSlot: CalendarSlotResponse | null;
|
|
/** Last heartbeat timestamp */
|
|
lastHeartbeatAt: Date | null;
|
|
/** Interval handle for cleanup */
|
|
intervalHandle: ReturnType<typeof setInterval> | null;
|
|
/** Set of slot IDs that have been deferred in current session */
|
|
deferredSlotIds: Set<string>;
|
|
/** Whether agent is currently processing a slot */
|
|
isProcessing: boolean;
|
|
}
|
|
/**
|
|
* CalendarScheduler manages the periodic heartbeat and slot execution lifecycle.
|
|
*/
|
|
export declare class CalendarScheduler {
|
|
private config;
|
|
private state;
|
|
constructor(config: CalendarSchedulerConfig);
|
|
/**
|
|
* Start the calendar scheduler.
|
|
* Begins periodic heartbeat to check for pending slots.
|
|
*/
|
|
start(): void;
|
|
/**
|
|
* Stop the calendar scheduler.
|
|
* Cleans up intervals and resets state.
|
|
*/
|
|
stop(): void;
|
|
/**
|
|
* Execute a single heartbeat cycle.
|
|
* Fetches pending slots and handles execution logic.
|
|
*/
|
|
runHeartbeat(): Promise<void>;
|
|
/**
|
|
* Handle slots when agent is not idle.
|
|
* Defer all pending slots with priority boost.
|
|
*/
|
|
private handleNonIdleAgent;
|
|
/**
|
|
* Handle slots when agent is idle.
|
|
* Select highest priority slot and wake agent.
|
|
*/
|
|
private handleIdleAgent;
|
|
/**
|
|
* Execute a slot by waking the agent.
|
|
*/
|
|
private executeSlot;
|
|
/**
|
|
* Build the wake context for an agent based on slot details.
|
|
*/
|
|
private buildWakeContext;
|
|
/**
|
|
* Build prompt for job-type slots.
|
|
*/
|
|
private buildJobPrompt;
|
|
/**
|
|
* Build prompt for system event slots.
|
|
*/
|
|
private buildSystemPrompt;
|
|
/**
|
|
* Build prompt for entertainment slots.
|
|
*/
|
|
private buildEntertainmentPrompt;
|
|
/**
|
|
* Build generic prompt for slots without specific event data.
|
|
*/
|
|
private buildGenericPrompt;
|
|
/**
|
|
* Mark a slot as deferred with priority boost.
|
|
*/
|
|
private deferSlot;
|
|
/**
|
|
* Revert a slot to not_started status after failed execution attempt.
|
|
*/
|
|
private revertSlot;
|
|
/**
|
|
* Complete the current slot execution.
|
|
* Call this when the agent finishes the task.
|
|
*/
|
|
completeCurrentSlot(actualDurationMinutes: number): Promise<void>;
|
|
/**
|
|
* Abort the current slot execution.
|
|
* Call this when the agent cannot complete the task.
|
|
*/
|
|
abortCurrentSlot(reason?: string): Promise<void>;
|
|
/**
|
|
* Pause the current slot execution.
|
|
* Call this when the agent needs to temporarily pause.
|
|
*/
|
|
pauseCurrentSlot(): Promise<void>;
|
|
/**
|
|
* Resume a paused slot.
|
|
*/
|
|
resumeCurrentSlot(): Promise<void>;
|
|
/**
|
|
* Trigger an immediate replanning pass after the current slot lifecycle ends.
|
|
* This lets previously deferred/not-started slots compete again as soon as
|
|
* the agent becomes idle.
|
|
*/
|
|
private triggerReplan;
|
|
/**
|
|
* Get a stable ID for a slot (real or virtual).
|
|
*/
|
|
private getSlotId;
|
|
/**
|
|
* Format a Date as ISO time string (HH:MM:SS).
|
|
*/
|
|
private formatTime;
|
|
/**
|
|
* Debug logging helper.
|
|
*/
|
|
private logDebug;
|
|
/**
|
|
* Get current scheduler state (for introspection).
|
|
*/
|
|
getState(): Readonly<SchedulerState>;
|
|
/**
|
|
* Check if scheduler is running.
|
|
*/
|
|
isRunning(): boolean;
|
|
/**
|
|
* Check if currently processing a slot.
|
|
*/
|
|
isProcessing(): boolean;
|
|
/**
|
|
* Get the current slot being executed (if any).
|
|
*/
|
|
getCurrentSlot(): CalendarSlotResponse | null;
|
|
}
|
|
/**
|
|
* Factory function to create a CalendarScheduler from plugin context.
|
|
*/
|
|
export declare function createCalendarScheduler(config: CalendarSchedulerConfig): CalendarScheduler;
|
|
export {};
|
|
//# sourceMappingURL=scheduler.d.ts.map
|