feat(FN-1085): align agent routing and runtime contracts

- Harden core AgentStore lifecycle behavior and heartbeat runtime integration paths
- Align dashboard agent APIs, server routes, and agent UI flows with the updated contract
- Tighten CLI agent/message command routing and validate payload handling semantics
- Expand test coverage across core, dashboard, engine, and CLI for route, heartbeat, and instruction regressions
This commit is contained in:
gsxdsm
2026-04-08 00:44:33 -07:00
parent 73bcbfd386
commit 750911a809
19 changed files with 942 additions and 169 deletions

View File

@@ -352,6 +352,40 @@ describe("InProcessRuntime", () => {
expect(scheduler!.getRegisteredAgents().length).toBeGreaterThanOrEqual(0);
}
});
it("routes assignment triggers through executeHeartbeat", async () => {
await runtime.start();
const monitor = runtime.getHeartbeatMonitor();
expect(monitor).toBeDefined();
const executeSpy = vi
.spyOn(monitor!, "executeHeartbeat")
.mockResolvedValue({ id: "run-test" } as any);
const store = (runtime as any).agentStore;
expect(store).toBeDefined();
const agent = await store.createAgent({
name: "Assignable",
role: "executor",
});
await store.assignTask(agent.id, "FN-001");
await vi.waitFor(() => {
expect(executeSpy).toHaveBeenCalledWith(
expect.objectContaining({
agentId: agent.id,
source: "assignment",
taskId: "FN-001",
contextSnapshot: expect.objectContaining({
taskId: "FN-001",
wakeReason: "assignment",
}),
}),
);
});
});
});
describe("configuration", () => {

View File

@@ -234,14 +234,13 @@ export class InProcessRuntime
async (agentId, source, context: WakeContext) => {
if (!this.heartbeatMonitor) return;
// Convert WakeContext to WakeupOptions
const options = {
await this.heartbeatMonitor.executeHeartbeat({
agentId,
source,
triggerDetail: context.triggerDetail,
taskId: typeof context.taskId === "string" ? context.taskId : undefined,
contextSnapshot: { ...context },
};
await this.heartbeatMonitor.startRun(agentId, options);
});
},
);
this.triggerScheduler.start();
@@ -469,7 +468,7 @@ export class InProcessRuntime
async executeHeartbeat(
agentId: string,
source: HeartbeatInvocationSource,
options?: { taskId?: string; triggerDetail?: string }
options?: { taskId?: string; triggerDetail?: string; contextSnapshot?: Record<string, unknown> }
): Promise<AgentHeartbeatRun | null> {
if (this.status !== "active") {
throw new Error(`Cannot execute heartbeat: runtime status is ${this.status}`);