fix(FN-2098): align no-task heartbeat guidance and stabilize flaky tests
- Update HEARTBEAT_NO_TASK_SYSTEM_PROMPT copy to emphasize inbox, memory, delegation, and heartbeat_done usage - Expand heartbeat monitor tests to assert no-task prompt/tool alignment and preserve task-scoped prompt behavior - Harden first-run and App view tests by using a safe cwd fallback and more robust async UI waits - Add best-effort dashboard performance reporting hooks in App and useProjects via a new reportDashboardPerf API helper
This commit is contained in:
@@ -1361,6 +1361,33 @@ describe("HeartbeatMonitor", () => {
|
||||
expect(toolNames).not.toContain("task_document_read");
|
||||
});
|
||||
|
||||
it("no-task run system prompt uses HEARTBEAT_NO_TASK_SYSTEM_PROMPT and does not reference task-scoped tools", async () => {
|
||||
const store = createStoreWithAgentForExec({ taskId: undefined, soul: "I am a coordinator" });
|
||||
const mockSession = createMockAgentSession();
|
||||
mockedCreateKbAgent.mockResolvedValue({ session: mockSession as any });
|
||||
|
||||
const monitor = new HeartbeatMonitor({ store, taskStore: mockTaskStore, rootDir: "/tmp" });
|
||||
|
||||
await monitor.executeHeartbeat({ agentId: "agent-001", source: "timer" });
|
||||
|
||||
expect(mockedCreateKbAgent).toHaveBeenCalledOnce();
|
||||
const callArgs = mockedCreateKbAgent.mock.calls[0]![0]!;
|
||||
const systemPrompt = callArgs.systemPrompt;
|
||||
|
||||
expect(systemPrompt).toContain(HEARTBEAT_NO_TASK_SYSTEM_PROMPT);
|
||||
expect(systemPrompt).not.toContain("task_log");
|
||||
expect(systemPrompt).not.toContain("task_document_write");
|
||||
expect(systemPrompt).not.toContain("task_document_read");
|
||||
expect(systemPrompt).toContain("task_create");
|
||||
expect(systemPrompt).toContain("list_agents");
|
||||
expect(systemPrompt).toContain("delegate_task");
|
||||
expect(systemPrompt).toContain("read_messages");
|
||||
expect(systemPrompt).toContain("send_message");
|
||||
expect(systemPrompt).toContain("memory_search");
|
||||
expect(systemPrompt).toContain("memory_append");
|
||||
expect(systemPrompt).toContain("heartbeat_done");
|
||||
});
|
||||
|
||||
it("identity agent without task receives no-task execution prompt mentioning 'no assigned task'", async () => {
|
||||
const store = createStoreWithAgentForExec({ taskId: undefined, soul: "I am a coordinator" });
|
||||
const mockSession = createMockAgentSession();
|
||||
@@ -1373,6 +1400,7 @@ describe("HeartbeatMonitor", () => {
|
||||
expect(mockedCreateKbAgent).toHaveBeenCalledOnce();
|
||||
const callArgs = mockedCreateKbAgent.mock.calls[0]![0]!;
|
||||
const systemPrompt = callArgs.systemPrompt;
|
||||
expect(systemPrompt).toContain(HEARTBEAT_NO_TASK_SYSTEM_PROMPT);
|
||||
expect(systemPrompt).not.toContain("task_log");
|
||||
expect(systemPrompt).not.toContain("task_document_write");
|
||||
expect(systemPrompt).not.toContain("task_document_read");
|
||||
@@ -1398,7 +1426,7 @@ describe("HeartbeatMonitor", () => {
|
||||
expect(executionPrompt).not.toContain("Task description:");
|
||||
});
|
||||
|
||||
it("task-scoped heartbeat run receives full system prompt with task_log and task Documents", async () => {
|
||||
it("task-scoped run system prompt uses original HEARTBEAT_SYSTEM_PROMPT", async () => {
|
||||
const store = createStoreWithAgentForExec({ taskId: "FN-001" });
|
||||
const mockSession = createMockAgentSession();
|
||||
mockedCreateKbAgent.mockResolvedValue({ session: mockSession as any });
|
||||
@@ -1411,6 +1439,7 @@ describe("HeartbeatMonitor", () => {
|
||||
const callArgs = mockedCreateKbAgent.mock.calls[0]![0]!;
|
||||
const systemPrompt = callArgs.systemPrompt;
|
||||
|
||||
expect(systemPrompt).toContain(HEARTBEAT_SYSTEM_PROMPT);
|
||||
expect(systemPrompt).toContain("task_log");
|
||||
expect(systemPrompt).toContain("task_document_write");
|
||||
expect(systemPrompt).toContain("Task Documents:");
|
||||
@@ -2220,11 +2249,19 @@ describe("HeartbeatMonitor", () => {
|
||||
});
|
||||
|
||||
describe("execution", () => {
|
||||
it("no-task heartbeat system prompt does not reference task-scoped tools", () => {
|
||||
it("HEARTBEAT_NO_TASK_SYSTEM_PROMPT does not mention task_log or task_document tools", () => {
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("task_log");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("task_document_write");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("task_document_read");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("task_document");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("task_create");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("list_agents");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("delegate_task");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("read_messages");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("send_message");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("memory_search");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("memory_append");
|
||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("heartbeat_done");
|
||||
});
|
||||
|
||||
it("creates session with enriched system prompt and expected tools", async () => {
|
||||
|
||||
@@ -169,12 +169,15 @@ When sending messages:
|
||||
export const HEARTBEAT_NO_TASK_SYSTEM_PROMPT = `You are a heartbeat agent running in a short execution window.
|
||||
|
||||
Your job:
|
||||
1. Do ONE useful action: analyze, review, create follow-up tasks, or log findings.
|
||||
2. Use task_create to spawn follow-up work.
|
||||
3. Call heartbeat_done when finished with an optional summary of what was accomplished.
|
||||
1. Review your context — check messages, memory, and project state.
|
||||
2. Do ONE useful action: analyze, create follow-up tasks, or update memory.
|
||||
3. Use task_create to spawn follow-up work.
|
||||
4. Use list_agents and delegate_task to assign work to other agents.
|
||||
5. Call heartbeat_done when finished with an optional summary of what was accomplished.
|
||||
|
||||
Keep work lightweight — this is a single-pass check, not a full implementation run.
|
||||
You have readonly file access plus task_create, list_agents, delegate_task, messaging, and memory tools (memory_search, memory_get, memory_append).
|
||||
You have readonly file access plus task_create, list_agents, delegate_task, messaging, memory, and heartbeat_done tools.
|
||||
Use read_messages and send_message for inbox processing, and memory_search, memory_get, and memory_append for memory workflows.
|
||||
|
||||
## Memory Boundaries
|
||||
|
||||
@@ -189,9 +192,9 @@ When you are woken by an incoming message (source includes "wake-on-message"), y
|
||||
1. Use read_messages to check your inbox for unread messages.
|
||||
2. Review each message and determine the appropriate action:
|
||||
- If the message requires a response, use send_message to reply.
|
||||
- If the message is informational, acknowledge it with a brief response or note it in memory.
|
||||
- If the message is informational, acknowledge it and respond via send_message if appropriate.
|
||||
- If the message requests work, create a follow-up task with task_create or handle it directly.
|
||||
3. After processing messages, continue with your normal heartbeat duties.
|
||||
3. After processing messages, continue with your ambient work.
|
||||
|
||||
When sending messages:
|
||||
- Be concise and clear about what you need or what you've done.
|
||||
|
||||
Reference in New Issue
Block a user