feat(FN-5053): merge fusion/fn-5053 — align no-task heartbeat prompts

Squash-merge of fusion/fn-5053 (7 commits including retry duplicates).
Drops stale conflict in packages/core/src/index.ts (FN-5053 branch
re-exported symbols that main already exports) and packages/core/src/store.ts
(branch had a stale, narrower updateTask signature; main is authoritative).

Manual CEO recovery after the trailerless-commit attribution bug
(now fixed by FN-5090 in 92be8225e) stranded this task in in-review.

Fusion-Task-Id: FN-5053
This commit is contained in:
gsxdsm
2026-05-18 21:08:04 -07:00
parent 92be8225e4
commit b9d4bd8c1b
3 changed files with 78 additions and 5 deletions

View File

@@ -13,6 +13,9 @@ import {
HEARTBEAT_NO_TASK_SYSTEM_PROMPT,
HEARTBEAT_PROCEDURE,
HEARTBEAT_NO_TASK_PROCEDURE,
HEARTBEAT_NO_TASK_PROCEDURE_STRICT,
HEARTBEAT_NO_TASK_PROCEDURE_LITE,
HEARTBEAT_NO_TASK_PROCEDURE_OFF,
} from "../agent-heartbeat.js";
import { AgentLogger } from "../agent-logger.js";
import * as agentTools from "../agent-tools.js";
@@ -97,9 +100,68 @@ describe("createHeartbeatTools", () => {
it("heartbeat no-task system prompt documents coding-capable workspace access without task-scoped tools", () => {
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("coding-capable workspace tools");
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("fn_task_document_write");
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("fn_task_document_read");
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).not.toContain("fn_task_log");
});
describe("FN-5053 no-task heartbeat prompt/tool alignment", () => {
const FORBIDDEN_NO_TASK_TOOLS = [
"fn_task_log",
"fn_task_document_write",
"fn_task_document_read",
"fn_task_update",
"fn_task_done",
] as const;
const REQUIRED_NO_TASK_TOOLS = [
"fn_task_create",
"fn_list_agents",
"fn_delegate_task",
"fn_get_agent_config",
"fn_update_agent_config",
"fn_agent_create",
"fn_agent_delete",
"fn_send_message",
"fn_read_messages",
"fn_post_room_message",
"fn_memory_search",
"fn_memory_get",
"fn_memory_append",
"fn_web_fetch",
"fn_read_evaluations",
"fn_update_identity",
"fn_reflect_on_performance",
"fn_heartbeat_done",
] as const;
const NO_TASK_PROMPT_VARIANTS = [
HEARTBEAT_NO_TASK_SYSTEM_PROMPT,
HEARTBEAT_NO_TASK_PROCEDURE_STRICT,
HEARTBEAT_NO_TASK_PROCEDURE_LITE,
HEARTBEAT_NO_TASK_PROCEDURE_OFF,
] as const;
it.each(FORBIDDEN_NO_TASK_TOOLS)("FN-5053 excludes forbidden no-task tool reference %s", (toolName) => {
for (const promptText of NO_TASK_PROMPT_VARIANTS) {
expect(promptText).not.toContain(toolName);
}
});
it.each(REQUIRED_NO_TASK_TOOLS)("FN-5053 keeps required no-task tool in inventory: %s", (toolName) => {
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain(toolName);
});
it("FN-5053 keeps no-task procedure persist-progress guidance on ambient tools", () => {
const expectedPersistLine = "fn_task_create, fn_delegate_task, fn_send_message, fn_memory_append.";
expect(HEARTBEAT_NO_TASK_PROCEDURE_STRICT).toContain(expectedPersistLine);
expect(HEARTBEAT_NO_TASK_PROCEDURE_LITE).toContain(expectedPersistLine);
expect(HEARTBEAT_NO_TASK_PROCEDURE_STRICT).toContain("fn_heartbeat_done");
expect(HEARTBEAT_NO_TASK_PROCEDURE_LITE).toContain("fn_heartbeat_done");
expect(HEARTBEAT_NO_TASK_PROCEDURE_OFF).toContain("fn_heartbeat_done");
});
it("FN-5053 keeps task-bound task-scoped guidance intact", () => {
expect(HEARTBEAT_SYSTEM_PROMPT).toContain("fn_task_log");
expect(HEARTBEAT_SYSTEM_PROMPT).toContain("fn_task_document_write");
});
});
it("returns task, delegation, and agent-config tools", () => {

View File

@@ -422,7 +422,7 @@ Your job:
3. Use fn_task_create to spawn follow-up work.
4. Use fn_list_agents and fn_delegate_task to coordinate with other agents.
5. Use fn_get_agent_config and fn_update_agent_config to read/tune direct-report agents for better routing outcomes.
5. Call fn_heartbeat_done when finished with an optional summary of what was accomplished.
6. Call fn_heartbeat_done when finished with an optional summary of what was accomplished.
Examples of ONE useful action:
- DO: create a clearly scoped task for a newly discovered reliability issue.
@@ -436,6 +436,10 @@ You have coding-capable workspace tools (read/write/edit/bash within worktree bo
- fn_task_create
- fn_list_agents and fn_delegate_task
- fn_get_agent_config and fn_update_agent_config (for direct reports only)
- fn_agent_create and fn_agent_delete (for direct reports only)
- fn_read_evaluations and fn_update_identity (available in no-task runs)
- fn_reflect_on_performance when reflection is enabled for this run
- fn_web_fetch
- fn_memory_search, fn_memory_get, and fn_memory_append
- fn_heartbeat_done
- fn_send_message, fn_read_messages, and fn_post_room_message when messaging/room tools are enabled for this run (they may not always be available)
@@ -2142,7 +2146,9 @@ export class HeartbeatMonitor {
// For no-task runs, exclude fn_task_log and document tools (they require a taskId)
let heartbeatTools: ToolDefinition[];
if (isNoTaskRun) {
// No-task runs: fn_task_create, fn_list_agents, fn_delegate_task, fn_get_agent_config, fn_update_agent_config, messaging, memory, fn_heartbeat_done
// No-task runs: task creation/delegation, direct-report config + provisioning,
// optional messaging/room + reflection, evaluation/identity, web fetch,
// memory tools, and fn_heartbeat_done. Task-scoped tools are intentionally excluded.
heartbeatTools = [];
// fn_task_create tool