diff --git a/.changeset/fix-task-chat-ephemeral-agent-working.md b/.changeset/fix-task-chat-ephemeral-agent-working.md new file mode 100644 index 0000000000..6842db64aa --- /dev/null +++ b/.changeset/fix-task-chat-ephemeral-agent-working.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Fix the task detail chat always showing "No agent is working on this task" for in-progress tasks. The active-session check required a persistent `assignedAgentId`/`checkedOutBy`, but in the default ephemeral-agents mode the scheduler never sets those fields, so an actively-executing task always read as idle. An assignment is now sufficient-but-not-necessary: a non-blocked, non-`queued` in-progress task counts as a live agent session on its own (`queued` stays assignment-gated, in-review is unchanged). diff --git a/packages/dashboard/app/components/TaskChatTab.tsx b/packages/dashboard/app/components/TaskChatTab.tsx index ac5d77d10b..3d8421e85f 100644 --- a/packages/dashboard/app/components/TaskChatTab.tsx +++ b/packages/dashboard/app/components/TaskChatTab.tsx @@ -172,8 +172,20 @@ function isActiveAgentSession(task: Task | TaskDetail, opts: { sessionLive?: boo const statusAllowsReviewSteering = !task.status || REVIEW_STEERABLE_STATUSES.has(task.status); const columnAllowsSteering = (task.column === "in-progress" && statusAllowsProgressSteering) || (task.column === "in-review" && statusAllowsReviewSteering); + // In the default ephemeral-agents mode the scheduler never writes + // `assignedAgentId`/`checkedOutBy` — those are only set when + // `ephemeralAgentsEnabled === false` (scheduler.ts). An actively-executing + // in-progress task therefore has no assignment field yet IS being worked, so + // requiring `hasAssignedAgent` made the chat always show "no agent is working" + // for default-mode tasks. Treat assignment as sufficient-but-not-necessary: + // a non-blocked, non-`queued` in-progress task is a live session on its own. + // `queued` is the documented waiting/blocked marker (self-healing.ts), so it + // stays assignment-gated; in-review keeps requiring an assignment. + const inProgressExecuting = task.column === "in-progress" + && statusAllowsProgressSteering + && task.status !== "queued"; return columnAllowsSteering - && hasAssignedAgent; + && (hasAssignedAgent || inProgressExecuting); } function isToolLikeEntry(entry: AgentLogEntry): boolean { diff --git a/packages/dashboard/app/components/__tests__/TaskChatTab.test.tsx b/packages/dashboard/app/components/__tests__/TaskChatTab.test.tsx index 0d043c7a8d..ea046c0cba 100644 --- a/packages/dashboard/app/components/__tests__/TaskChatTab.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskChatTab.test.tsx @@ -1802,6 +1802,40 @@ describe("TaskChatTab", () => { expectComposerSendableAfterDraft(); }); + it.each([undefined, "planning", "merging", "merging-fix"])( + "treats an actively-executing in-progress task as an active session even without an assignment (ephemeral mode): %s status", + (status) => { + // In the default ephemeral-agents mode the scheduler never writes + // assignedAgentId/checkedOutBy, so a running in-progress task has no + // assignment field yet IS being worked. It must NOT show the idle + // "no agent is working" hint. + render( + , + ); + + expectActiveSessionCopy(); + expect(screen.getByLabelText("Message active agent session")).not.toBeDisabled(); + }, + ); + + it("keeps a queued (waiting) unassigned in-progress task idle in ephemeral mode", () => { + render( + , + ); + + expectIdleSessionHint(); + }); + it.each(["busy", "ready", "starting", "waitingOnInput"] as const)("treats %s CLI sessions as live", (agentState) => { expect(isCliSessionLive(makeCliSession(agentState))).toBe(true); });