feat(FN-1049): add per-agent heartbeat configuration via runtimeConfig

- Define AgentHeartbeatConfig interface in core types (heartbeatIntervalMs, heartbeatTimeoutMs, maxConcurrentRuns)
- Update HeartbeatMonitor to resolve per-agent config from AgentStore with validated min/max clamping
- Wire AgentStore into HeartbeatMonitor via InProcessRuntime initialization
- Add heartbeat settings section to dashboard AgentDetailView ConfigTab
- Add PATCH /api/agents/:id endpoint accepting runtimeConfig updates
- Add comprehensive tests for per-agent heartbeat config resolution and validation
- Document per-agent heartbeat configuration in AGENTS.md
This commit is contained in:
gsxdsm
2026-04-07 11:50:17 -07:00
parent 39f4f4929f
commit 825ae1061b
10 changed files with 579 additions and 40 deletions

View File

@@ -10,7 +10,7 @@
*/
import { mkdir, readFile, writeFile, readdir, unlink } from "node:fs/promises";
import { existsSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { randomUUID } from "node:crypto";
import { EventEmitter } from "node:events";
@@ -732,6 +732,21 @@ export class AgentStore extends EventEmitter {
return JSON.parse(content) as AgentData;
}
/**
* Synchronously read an agent from disk (for use in synchronous hot paths).
* Returns null if the agent file does not exist or cannot be parsed.
* @param agentId - The agent ID
*/
getCachedAgent(agentId: string): Agent | null {
try {
const path = join(this.agentsDir, `${agentId}.json`);
const content = readFileSync(path, "utf-8");
return this.parseAgent(JSON.parse(content) as AgentData);
} catch {
return null;
}
}
private parseAgent(data: AgentData): Agent {
return {
id: data.id,