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

- Add task `source` provenance field tracking how tasks enter the system (e.g. `"manual"`, `"heartbeat"`, `"executor"`, `"triage"`, `"cron"`, `"routine"`)
- Wire `source` into shared create-task tools, executor agent, triage agent, cron runner, and routine runner
- Add `source` to heartbeat task creation in `agent-heartbeat.ts` and mission execution loop in `mission-execution-loop.ts`
- Wire `source` field into dashboard routes (`register-planning-subtask-routes.ts`, `register-task-workflow-routes.ts`) and GitHub integration (`register-git-github.ts`)
- Add `source` to the API layer and task store handlers in the dashboard
- Expose `source` in the `fn` CLI task command and `task-plan` extension tool
- Add integration tests for provenance across engine (agent-tools, agent-heartbeat, cron-runner, triage, pr-comment-handler) and dashboard routes
- Update existing tests to assert the correct source values
- Bulk-revert stale changeset files that were superseded by the v0.9.1 release commit

Commits merged:
- test(FN-2923): complete Step 14 — align tests with task source provenance
- test(FN-2923): complete Steps 12-13 — update and add provenance tests
- feat(FN-2923): complete Step 10 — wire CLI task provenance
- feat(FN-2923): complete Step 9 — wire dashboard UI and API source fields
- feat(FN-2923): complete Step 8 — wire dashboard route provenance
- feat(FN-2923): complete Step 7 — wire remaining engine provenance
- feat(FN-2923): complete Step 6 — add routine create-task provenance
- feat(FN-2923): complete Step 5 — add cron create-task provenance
- feat(FN-2923): complete Step 4 — add triage subtask source
- feat(FN-2923): complete Step 3 — add executor create-task source
- feat(FN-2923): complete Step 2 — add heartbeat task provenance
- feat(FN-2923): complete Step 1 — add provenance to shared create-task tools
- feat(FN-2945): merge fusion/fn-2945
- chore(release): v0.9.1

Files changed:
.changeset/active-agents-no-stuck-connecting.md    | 13 ---
 .changeset/active-agents-panel-hoist-heartbeat.md  | 13 ---
 .changeset/fix-agent-heartbeat-terminal-links.md   |  5 --
 .changeset/fix-experimental-defaults.md            |  5 --
 .changeset/improve-git-manager-diff-pane.md        |  5 --
 .changeset/insights-two-pane-layout.md             |  5 --
 .changeset/show-planning-tasks-immediately.md      |  5 --
 CHANGELOG.md                                       | 92 ++++++++++++++++++++++
 package.json                                       |  2 +-
 packages/cli-alias/CHANGELOG.md                    | 15 ++++
 packages/cli-alias/package.json                    |  2 +-
 packages/cli/CHANGELOG.md                          | 12 +++
 packages/cli/package.json                          |  2 +-
 packages/cli/src/__tests__/task-plan.test.ts       |  1 +
 packages/cli/src/commands/__tests__/task.test.ts   | 15 +++-
 packages/cli/src/commands/task.ts                  | 15 +++-
 packages/cli/src/extension.ts                      |  9 +++
 packages/core/CHANGELOG.md                         |  7 ++
 packages/core/package.json                         |  2 +-
 packages/dashboard/CHANGELOG.md                    | 14 ++++
 .../app/__tests__/agent-css-classes.test.ts        |  3 +-
 packages/dashboard/app/__tests__/api.test.ts       | 13 +++
 packages/dashboard/app/api/legacy.ts               |  2 +
 packages/dashboard/app/components/AgentsView.css   | 22 +++---
 .../app/components/ModelOnboardingModal.tsx        |  5 +-
 packages/dashboard/app/components/TodoView.tsx     |  2 +
 .../__tests__/ModelOnboardingModal.test.tsx        |  4 +-
 .../app/components/__tests__/QuickChatFAB.test.tsx | 14 +---
 .../app/components/__tests__/TodoView.test.tsx     |  4 +-
 .../__tests__/agents-view-mobile.test.tsx          |  5 +-
 .../components/__tests__/onboarding-flow.test.tsx  |  2 +-
 .../app/hooks/__tests__/useTaskHandlers.test.ts    |  4 +-
 packages/dashboard/app/hooks/useTaskHandlers.ts    |  4 +-
 packages/dashboard/package.json                    |  2 +-
 packages/dashboard/src/__tests__/routes.test.ts    | 14 ++++
 packages/dashboard/src/routes.ts                   |  4 +
 .../dashboard/src/routes/register-git-github.ts    | 12 +++
 .../src/routes/register-planning-subtask-routes.ts |  3 +
 .../src/routes/register-task-workflow-routes.ts    |  7 ++
 packages/desktop/CHANGELOG.md                      |  7 ++
 packages/desktop/package.json                      |  2 +-
 packages/engine/CHANGELOG.md                       | 11 +++
 packages/engine/package.json                       |  2 +-
 .../engine/src/__tests__/agent-heartbeat.test.ts   | 10 +++
 .../src/__tests__/agent-tools-delegation.test.ts   |  2 +
 packages/engine/src/__tests__/agent-tools.test.ts  | 37 +++++++++
 packages/engine/src/__tests__/cron-runner.test.ts  |  4 +
 .../src/__tests__/pr-comment-handler.test.ts       |  8 ++
 packages/engine/src/__tests__/triage.test.ts       |  2 +
 packages/engine/src/agent-heartbeat.ts             | 13 ++-
 packages/engine/src/agent-tools.ts                 | 13 ++-
 packages/engine/src/cron-runner.ts                 |  7 +-
 packages/engine/src/executor.ts                    |  2 +-
 packages/engine/src/mission-execution-loop.ts      |  8 ++
 packages/engine/src/pr-comment-handler.ts          |  5 ++
 packages/engine/src/project-engine.ts              |  8 ++
 packages/engine/src/routine-runner.ts              |  4 +
 packages/engine/src/triage.ts                      |  4 +
 packages/mobile/CHANGELOG.md                       |  7 ++
 packages/mobile/package.json                       |  2 +-
 packages/pi-claude-cli/CHANGELOG.md                |  7 ++
 packages/pi-claude-cli/package.json                |  2 +-
 packages/plugin-sdk/CHANGELOG.md                   | 10 +++
 packages/plugin-sdk/package.json                   |  2 +-
 .../examples/fusion-plugin-auto-label/CHANGELOG.md |  8 ++
 .../examples/fusion-plugin-auto-label/package.json |  2 +-
 .../examples/fusion-plugin-ci-status/CHANGELOG.md  |  8 ++
 .../examples/fusion-plugin-ci-status/package.json  |  2 +-
 .../fusion-plugin-notification/CHANGELOG.md        |  8 ++
 .../fusion-plugin-notification/package.json        |  2 +-
 .../fusion-plugin-settings-demo/CHANGELOG.md       |  8 ++
 .../fusion-plugin-settings-demo/package.json       |  2 +-
 plugins/fusion-plugin-hermes-runtime/CHANGELOG.md  |  8 ++
 plugins/fusion-plugin-hermes-runtime/package.json  |  2 +-
 .../fusion-plugin-openclaw-runtime/CHANGELOG.md    |  8 ++
 .../fusion-plugin-openclaw-runtime/package.json    |  2 +-
 .../fusion-plugin-paperclip-runtime/CHANGELOG.md   |  8 ++
 .../fusion-plugin-paperclip-runtime/package.json   |  2 +-
 78 files changed, 499 insertions(+), 115 deletions(-)

Fusion-Task-Id: FN-2923
This commit is contained in:
Fusion
2026-04-29 17:20:39 -07:00
committed by gsxdsm
parent 8a1dabb81e
commit b0cda2398b
34 changed files with 229 additions and 32 deletions

View File

@@ -3229,6 +3229,11 @@ describe("HeartbeatMonitor", () => {
description: "Follow-up task",
dependencies: undefined,
column: "triage",
source: {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-001",
sourceRunId: undefined,
},
});
});
});
@@ -3744,6 +3749,11 @@ describe("HeartbeatMonitor", () => {
description: "Follow-up task",
dependencies: undefined,
column: "triage",
source: {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-001",
sourceRunId: undefined,
},
});
const responseText = result.content[0] && "text" in result.content[0] ? result.content[0].text : "";

View File

@@ -187,6 +187,7 @@ describe("createDelegateTaskTool", () => {
dependencies: undefined,
column: "todo",
assignedAgentId: "agent-001",
source: { sourceType: "api" },
});
const text = (result.content[0] as { text: string }).text;
@@ -281,6 +282,7 @@ describe("createDelegateTaskTool", () => {
dependencies: ["FN-010"],
column: "todo",
assignedAgentId: "agent-001",
source: { sourceType: "api" },
});
const text = (result.content[0] as { text: string }).text;

View File

@@ -7,6 +7,7 @@ import {
buildQmdAgentMemorySearchArgs,
createMemoryTools,
createTaskCreateTool,
createDelegateTaskTool,
createSendMessageTool,
createReadMessagesTool,
qmdAgentMemoryCollectionName,
@@ -82,12 +83,48 @@ describe("createTaskCreateTool", () => {
description: "Follow-up task",
dependencies: ["PROJ-001"],
column: "triage",
source: undefined,
});
expect(result.details).toEqual({ taskId: "PROJ-042" });
const responseText = result.content[0]?.type === "text" ? result.content[0].text : "";
expect(responseText).toContain("Created PROJ-042: Follow-up task");
expect(responseText).toContain("(depends on: PROJ-001)");
});
it("passes explicit provenance to store.createTask", async () => {
const store = {
createTask: vi.fn().mockResolvedValue({ id: "PROJ-099", description: "Test", dependencies: [], column: "triage" }),
};
const tool = createTaskCreateTool(store as any, {
sourceType: "agent_heartbeat",
sourceAgentId: "agent-123",
});
await tool.execute("call-1", { description: "Test" } as any, undefined, undefined, {} as any);
expect(store.createTask).toHaveBeenCalledWith(expect.objectContaining({
source: { sourceType: "agent_heartbeat", sourceAgentId: "agent-123", sourceRunId: undefined },
}));
});
});
describe("createDelegateTaskTool", () => {
it("creates delegated tasks with api source provenance", async () => {
const agentStore = {
getAgent: vi.fn().mockResolvedValue({ id: "agent-1", name: "Worker", role: "executor", state: "idle" }),
};
const taskStore = {
createTask: vi.fn().mockResolvedValue({ id: "FN-100", dependencies: [], description: "Delegated" }),
};
const tool = createDelegateTaskTool(agentStore as any, taskStore as any);
await tool.execute("call-1", { agent_id: "agent-1", description: "Delegated" } as any, undefined, undefined, {} as any);
expect(taskStore.createTask).toHaveBeenCalledWith(expect.objectContaining({
source: { sourceType: "api" },
}));
});
});
describe("createMemoryTools", () => {

View File

@@ -1252,6 +1252,10 @@ describe("CronRunner", () => {
column: "todo",
modelProvider: "anthropic",
modelId: "claude-sonnet-4-5",
source: {
sourceType: "cron",
sourceMetadata: { scheduleId: "test-schedule-id", stepId: expect.any(String) },
},
});
});

View File

@@ -213,6 +213,14 @@ describe("PrCommentHandler", () => {
description: expect.stringContaining("FN-001"),
column: "triage",
dependencies: ["FN-001"],
source: {
sourceType: "api",
sourceParentTaskId: "FN-001",
sourceMetadata: {
prNumber: 42,
prUrl: "https://github.com/owner/repo/pull/42",
},
},
});
});

View File

@@ -1387,6 +1387,7 @@ describe("taskCreate tool model inheritance", () => {
modelId: parentTaskResult?.modelId,
validatorModelProvider: parentTaskResult?.validatorModelProvider,
validatorModelId: parentTaskResult?.validatorModelId,
source: { sourceType: "agent_heartbeat", sourceParentTaskId: parentTaskId },
});
expect(store.getTask).toHaveBeenCalledWith("FN-001");
@@ -1435,6 +1436,7 @@ describe("taskCreate tool model inheritance", () => {
modelId: parentTask?.modelId,
validatorModelProvider: parentTask?.validatorModelProvider,
validatorModelId: parentTask?.validatorModelId,
source: { sourceType: "agent_heartbeat", sourceParentTaskId: parentTaskId },
});
expect(store.getTask).toHaveBeenCalledWith("FN-NONEXISTENT");