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

This commit is contained in:
gsxdsm
2026-04-18 21:52:21 -07:00
parent dc9f5c68f9
commit 5d65667a5a
2 changed files with 26 additions and 8 deletions

View File

@@ -1376,8 +1376,9 @@ describe("HeartbeatMonitor", () => {
expect(systemPrompt).not.toContain("task_log");
expect(systemPrompt).not.toContain("task_document_write");
expect(systemPrompt).not.toContain("task_document_read");
expect(systemPrompt).not.toContain("Task Documents:");
expect(systemPrompt).toContain("task_create");
expect(systemPrompt).toContain("heartbeat_done");
expect(systemPrompt).toContain("memory_append");
// The execution prompt is passed to session.prompt by promptWithFallback mock
const promptCalls = mockSession.prompt.mock.calls;
@@ -1396,6 +1397,24 @@ describe("HeartbeatMonitor", () => {
expect(executionPrompt).not.toContain("Task description:");
});
it("task-scoped heartbeat run receives full system prompt with task_log and task Documents", async () => {
const store = createStoreWithAgentForExec({ taskId: "FN-001" });
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("task_log");
expect(systemPrompt).toContain("task_document_write");
expect(systemPrompt).toContain("Task Documents:");
});
it("identity agent without task gets soul in system prompt", async () => {
const store = createStoreWithAgentForExec({ taskId: undefined, soul: "I am a CEO who prioritizes high-impact work" });
const mockSession = createMockAgentSession();

View File

@@ -169,14 +169,12 @@ 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 communicate findings.
2. Use task_create to spawn follow-up work as needed.
3. Use send_message and read_messages to process inter-agent communication.
4. Use memory_search and memory_append to leverage and persist useful memory context.
5. Call heartbeat_done when finished with an optional summary of what was accomplished.
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.
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, memory_search, memory_append, send_message, read_messages, and heartbeat_done tools.
You have readonly file access plus task_create, list_agents, delegate_task, messaging, and memory tools (memory_search, memory_get, memory_append).
## Memory Boundaries
@@ -191,7 +189,7 @@ 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 via send_message.
- If the message is informational, acknowledge it briefly and move on.
- 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.
@@ -1121,6 +1119,7 @@ export class HeartbeatMonitor {
[agentInstructions, memoryInstructions].filter((part) => part.trim()).join("\n\n"),
);
} catch (instructionError) {
systemPrompt = baseHeartbeatSystemPrompt;
const message = instructionError instanceof Error ? instructionError.message : String(instructionError);
heartbeatLog.warn(`Failed to enrich heartbeat system prompt for ${agentId}: ${message}`);
}