feat(FN-2113): merge fusion/fn-2113

This commit is contained in:
gsxdsm
2026-04-19 05:07:00 -07:00
parent a956ce5a4f
commit 59fbdc8dab
4 changed files with 22 additions and 22 deletions

View File

@@ -1132,7 +1132,7 @@ describe("HeartbeatMonitor", () => {
const config = monitor.getAgentHeartbeatConfig("agent-001"); const config = monitor.getAgentHeartbeatConfig("agent-001");
expect(config.heartbeatTimeoutMs).toBe(5000); expect(config.heartbeatTimeoutMs).toBe(5000);
expect(config.pollIntervalMs).toBe(30000); // default expect(config.pollIntervalMs).toBe(3_600_000); // default
expect(config.maxConcurrentRuns).toBe(1); // default expect(config.maxConcurrentRuns).toBe(1); // default
}); });
@@ -3834,45 +3834,45 @@ describe("HeartbeatTriggerScheduler", () => {
expect(scheduler.getRegisteredAgents()).not.toContain("agent-001"); expect(scheduler.getRegisteredAgents()).not.toContain("agent-001");
}); });
it("applies default 30-second interval when intervalMs is undefined", async () => { it("applies default 3600-second interval when intervalMs is undefined", async () => {
vi.useFakeTimers(); vi.useFakeTimers();
scheduler.registerAgent("agent-001", {}); scheduler.registerAgent("agent-001", {});
expect(scheduler.getRegisteredAgents()).toContain("agent-001"); expect(scheduler.getRegisteredAgents()).toContain("agent-001");
// Verify the default 30-second interval fires // Verify the default 3600-second interval fires
expect(callback).not.toHaveBeenCalled(); expect(callback).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(30_000); await vi.advanceTimersByTimeAsync(3_600_000);
expect(callback).toHaveBeenCalledOnce(); expect(callback).toHaveBeenCalledOnce();
vi.useRealTimers(); vi.useRealTimers();
}); });
it("applies default 30-second interval when intervalMs is 0", async () => { it("applies default 3600-second interval when intervalMs is 0", async () => {
vi.useFakeTimers(); vi.useFakeTimers();
scheduler.registerAgent("agent-001", { heartbeatIntervalMs: 0 }); scheduler.registerAgent("agent-001", { heartbeatIntervalMs: 0 });
expect(scheduler.getRegisteredAgents()).toContain("agent-001"); expect(scheduler.getRegisteredAgents()).toContain("agent-001");
// Verify the default 30-second interval fires // Verify the default 3600-second interval fires
expect(callback).not.toHaveBeenCalled(); expect(callback).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(30_000); await vi.advanceTimersByTimeAsync(3_600_000);
expect(callback).toHaveBeenCalledOnce(); expect(callback).toHaveBeenCalledOnce();
vi.useRealTimers(); vi.useRealTimers();
}); });
it("applies default 30-second interval when heartbeatIntervalMs is not set", async () => { it("applies default 3600-second interval when heartbeatIntervalMs is not set", async () => {
vi.useFakeTimers(); vi.useFakeTimers();
scheduler.registerAgent("agent-001", { enabled: true }); scheduler.registerAgent("agent-001", { enabled: true });
expect(scheduler.getRegisteredAgents()).toContain("agent-001"); expect(scheduler.getRegisteredAgents()).toContain("agent-001");
// Should fire at exactly 30 seconds (default interval) // Should fire at exactly 3600 seconds (default interval)
await vi.advanceTimersByTimeAsync(29_999); await vi.advanceTimersByTimeAsync(3_599_999);
expect(callback).not.toHaveBeenCalled(); expect(callback).not.toHaveBeenCalled();
await vi.advanceTimersByTimeAsync(1); // Now at exactly 30 seconds await vi.advanceTimersByTimeAsync(1); // Now at exactly 3600 seconds
expect(callback).toHaveBeenCalledOnce(); expect(callback).toHaveBeenCalledOnce();
expect(callback).toHaveBeenCalledWith("agent-001", "timer", { expect(callback).toHaveBeenCalledWith("agent-001", "timer", {
wakeReason: "timer", wakeReason: "timer",
triggerDetail: "scheduled", triggerDetail: "scheduled",
intervalMs: 30_000, intervalMs: 3_600_000,
}); });
vi.useRealTimers(); vi.useRealTimers();
}); });
@@ -3882,7 +3882,7 @@ describe("HeartbeatTriggerScheduler", () => {
scheduler.registerAgent("agent-001", { heartbeatIntervalMs: 15_000, enabled: true }); scheduler.registerAgent("agent-001", { heartbeatIntervalMs: 15_000, enabled: true });
expect(scheduler.getRegisteredAgents()).toContain("agent-001"); expect(scheduler.getRegisteredAgents()).toContain("agent-001");
// Should fire at 15 seconds (explicit), not 30 // Should fire at 15 seconds (explicit), not 3600
await vi.advanceTimersByTimeAsync(14_999); await vi.advanceTimersByTimeAsync(14_999);
expect(callback).not.toHaveBeenCalled(); expect(callback).not.toHaveBeenCalled();

View File

@@ -46,7 +46,7 @@ export interface HeartbeatMonitorOptions {
agentStore?: AgentStore; agentStore?: AgentStore;
/** Optional MessageStore for wake-on-message behavior */ /** Optional MessageStore for wake-on-message behavior */
messageStore?: MessageStore; messageStore?: MessageStore;
/** Polling interval in milliseconds (default: 30000) */ /** Polling interval in milliseconds (default: 3600000) */
pollIntervalMs?: number; pollIntervalMs?: number;
/** Heartbeat timeout in milliseconds (default: 60000) */ /** Heartbeat timeout in milliseconds (default: 60000) */
heartbeatTimeoutMs?: number; heartbeatTimeoutMs?: number;
@@ -247,7 +247,7 @@ export class HeartbeatMonitor {
constructor(options: HeartbeatMonitorOptions) { constructor(options: HeartbeatMonitorOptions) {
this.store = options.store; this.store = options.store;
this.configStore = options.agentStore ?? options.store; this.configStore = options.agentStore ?? options.store;
this.pollIntervalMs = options.pollIntervalMs ?? 30000; this.pollIntervalMs = options.pollIntervalMs ?? 3_600_000;
this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 60000; this.heartbeatTimeoutMs = options.heartbeatTimeoutMs ?? 60000;
this.maxConcurrentRuns = options.maxConcurrentRuns ?? 1; this.maxConcurrentRuns = options.maxConcurrentRuns ?? 1;
this.onMissed = options.onMissed; this.onMissed = options.onMissed;
@@ -1641,7 +1641,7 @@ interface AgentTimer {
* const scheduler = new HeartbeatTriggerScheduler(agentStore, async (agentId, source, ctx) => { * const scheduler = new HeartbeatTriggerScheduler(agentStore, async (agentId, source, ctx) => {
* await heartbeatMonitor.startRun(agentId, { source, triggerDetail: ctx.triggerDetail, contextSnapshot: { ...ctx } }); * await heartbeatMonitor.startRun(agentId, { source, triggerDetail: ctx.triggerDetail, contextSnapshot: { ...ctx } });
* }); * });
* scheduler.registerAgent("agent-123", { heartbeatIntervalMs: 30000, enabled: true }); * scheduler.registerAgent("agent-123", { heartbeatIntervalMs: 3600000, enabled: true });
* scheduler.start(); * scheduler.start();
* ``` * ```
*/ */
@@ -1701,8 +1701,8 @@ export class HeartbeatTriggerScheduler {
return this.running; return this.running;
} }
/** Default heartbeat interval when not explicitly configured (30 seconds) */ /** Default heartbeat interval when not explicitly configured (3600 seconds / 1 hour) */
private static readonly DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000; private static readonly DEFAULT_HEARTBEAT_INTERVAL_MS = 3_600_000;
/** /**
* Register an agent for timer-based heartbeat triggers. * Register an agent for timer-based heartbeat triggers.

View File

@@ -789,14 +789,14 @@ describe("InProcessRuntime", () => {
expect(scheduler!.getRegisteredAgents()).toContain(agent.id); expect(scheduler!.getRegisteredAgents()).toContain(agent.id);
}); });
it("registers agent without explicit heartbeatIntervalMs using default 30s interval", async () => { it("registers agent without explicit heartbeatIntervalMs using default 3600s interval", async () => {
// Create a new agent with only enabled: true (no heartbeatIntervalMs) // Create a new agent with only enabled: true (no heartbeatIntervalMs)
// This tests that the default 30-second interval is applied // This tests that the default 3600-second interval (1 hour) is applied
const store = getAgentStore(runtime); const store = getAgentStore(runtime);
const agent = await store.createAgent({ const agent = await store.createAgent({
name: "test-agent-default-interval", name: "test-agent-default-interval",
role: "executor", role: "executor",
runtimeConfig: { enabled: true }, // No heartbeatIntervalMs - should use default 30s runtimeConfig: { enabled: true }, // No heartbeatIntervalMs - should use default 3600s (1 hour)
}); });
// Verify the agent was registered with the trigger scheduler // Verify the agent was registered with the trigger scheduler

View File

@@ -497,7 +497,7 @@ export class InProcessRuntime
this.agentStore.on("agent:updated", this.agentUpdatedListener); this.agentStore.on("agent:updated", this.agentUpdatedListener);
// Register existing agents with heartbeat monitoring not explicitly disabled // Register existing agents with heartbeat monitoring not explicitly disabled
// Agents without explicit heartbeat config will use the default 30-second interval // Agents without explicit heartbeat config will use the default 3600-second interval (1 hour)
try { try {
const agents = await this.agentStore.listAgents(); const agents = await this.agentStore.listAgents();
let registeredCount = 0; let registeredCount = 0;