Stop counting initializing agents as running

This commit is contained in:
Mohamed Boudra
2026-06-04 00:53:38 +07:00
parent f6c0b60b7c
commit b345ef1242
10 changed files with 35 additions and 19 deletions
+1 -1
View File
@@ -324,7 +324,7 @@ export function AgentList({
const handleAgentLongPress = useCallback( const handleAgentLongPress = useCallback(
(agent: AggregatedAgent) => { (agent: AggregatedAgent) => {
const isRunning = agent.status === "running" || agent.status === "initializing"; const isRunning = agent.status === "running";
if (isRunning) { if (isRunning) {
setActionAgent(agent); setActionAgent(agent);
return; return;
@@ -420,7 +420,7 @@ describe("deriveAgentScreenViewState", () => {
expect(transitions.join(" -> ")).not.toContain("loading -> idle"); expect(transitions.join(" -> ")).not.toContain("loading -> idle");
}); });
it("keeps optimistic running status while authoritative agent is initializing", () => { it("uses authoritative initializing status instead of optimistic running status", () => {
const memory = createBaseMemory(); const memory = createBaseMemory();
const input: AgentScreenMachineInput = { const input: AgentScreenMachineInput = {
...createBaseInput(), ...createBaseInput(),
@@ -431,8 +431,8 @@ describe("deriveAgentScreenViewState", () => {
const result = deriveAgentScreenViewState({ input, memory }); const result = deriveAgentScreenViewState({ input, memory });
const ready = expectReadyState(result.state); const ready = expectReadyState(result.state);
expect(ready.source).toBe("optimistic"); expect(ready.source).toBe("authoritative");
expect(ready.agent.status).toBe("running"); expect(ready.agent.status).toBe("initializing");
}); });
it("hands off to authoritative once agent reaches running", () => { it("hands off to authoritative once agent reaches running", () => {
@@ -100,8 +100,7 @@ function updateInitialSyncFailureMemory(args: {
function shouldUseOptimisticCreateFlowAgent(input: AgentScreenMachineInput): boolean { function shouldUseOptimisticCreateFlowAgent(input: AgentScreenMachineInput): boolean {
return ( return (
input.continuity.kind === "optimistic-create" && input.continuity.kind === "optimistic-create" && (!input.agent || input.agent.status === "idle")
(!input.agent || input.agent.status === "initializing" || input.agent.status === "idle")
); );
} }
@@ -2404,7 +2404,7 @@ function WorkspaceScreenContent({
const agent = const agent =
useSessionStore.getState().sessions[normalizedServerId]?.agents?.get(agentId) ?? null; useSessionStore.getState().sessions[normalizedServerId]?.agents?.get(agentId) ?? null;
const closePolicy = resolveCloseAgentTabPolicy(agent); const closePolicy = resolveCloseAgentTabPolicy(agent);
const isRunning = agent?.status === "running" || agent?.status === "initializing"; const isRunning = agent?.status === "running";
if (isRunning && closePolicy.kind === "archive-on-close") { if (isRunning && closePolicy.kind === "archive-on-close") {
const confirmed = await confirmDialog({ const confirmed = await confirmDialog({
@@ -68,16 +68,15 @@ describe("resolveArchiveSubagentDialog", () => {
}); });
}); });
it("uses running copy for initializing subagents", () => { it("does not use running copy for initializing subagents", () => {
expect( expect(
resolveArchiveSubagentDialog({ resolveArchiveSubagentDialog({
title: "Starting child", title: "Starting child",
status: "initializing", status: "initializing",
}), }),
).toEqual({ ).toEqual({
title: "Archive running subagent?", title: "Archive subagent?",
message: message: "Remove Starting child from the track. The subagent will be archived.",
"Starting child is still running. Archiving it will stop the subagent and remove it from the track.",
confirmLabel: "Archive", confirmLabel: "Archive",
cancelLabel: "Cancel", cancelLabel: "Cancel",
destructive: true, destructive: true,
@@ -24,7 +24,7 @@ export function resolveArchiveSubagentDialog(
input: ResolveArchiveSubagentDialogInput, input: ResolveArchiveSubagentDialogInput,
): ConfirmDialogInput { ): ConfirmDialogInput {
const subagentLabel = resolveSubagentLabel(input.title) ?? "this subagent"; const subagentLabel = resolveSubagentLabel(input.title) ?? "this subagent";
const isRunning = input.status === "running" || input.status === "initializing"; const isRunning = input.status === "running";
return { return {
title: isRunning ? "Archive running subagent?" : "Archive subagent?", title: isRunning ? "Archive running subagent?" : "Archive subagent?",
@@ -35,7 +35,7 @@ describe("deriveSidebarStateBucket", () => {
).toBe("attention"); ).toBe("attention");
}); });
it("treats initializing agents as running", () => { it("does not count initializing agents as running", () => {
expect( expect(
deriveSidebarStateBucket({ deriveSidebarStateBucket({
status: "initializing", status: "initializing",
@@ -43,6 +43,6 @@ describe("deriveSidebarStateBucket", () => {
requiresAttention: false, requiresAttention: false,
attentionReason: null, attentionReason: null,
}), }),
).toBe("running"); ).toBe("done");
}); });
}); });
@@ -50,7 +50,7 @@ describe("deriveAgentStateBucket", () => {
).toBe("attention"); ).toBe("attention");
}); });
it("treats initializing agents as running for workspace buckets", () => { it("does not count initializing agents as running for workspace buckets", () => {
expect( expect(
deriveAgentStateBucket({ deriveAgentStateBucket({
status: "initializing", status: "initializing",
@@ -58,7 +58,7 @@ describe("deriveAgentStateBucket", () => {
requiresAttention: false, requiresAttention: false,
attentionReason: null, attentionReason: null,
}), }),
).toBe("running"); ).toBe("done");
}); });
}); });
+1 -1
View File
@@ -26,7 +26,7 @@ export function deriveAgentStateBucket(input: AgentStateBucketInput): WorkspaceS
if (input.status === "error" || input.attentionReason === "error") { if (input.status === "error" || input.attentionReason === "error") {
return "failed"; return "failed";
} }
if (input.status === "running" || input.status === "initializing") { if (input.status === "running") {
return "running"; return "running";
} }
if (input.requiresAttention) { if (input.requiresAttention) {
@@ -4201,7 +4201,25 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi
expect(descriptor.statusEnteredAt).toBe(updatedAt); expect(descriptor.statusEnteredAt).toBe(updatedAt);
} }
// 3. Highest-priority across all buckets: a "needs_input" agent beats // 3. A root agent that is still initializing does not make the workspace
// look like it is actively working.
{
const { session, workspace } = setupSession();
const updatedAt = "2026-05-12T09:45:00.000Z";
session.listAgentPayloads = async () => [
makeAgent({
id: "agent-initializing",
cwd: workspace.cwd,
status: "initializing",
updatedAt,
}),
];
const descriptor = await buildDescriptor(session, workspace.workspaceId);
expect(descriptor.status).toBe("done");
expect(descriptor.statusEnteredAt).toBe(updatedAt);
}
// 4. Highest-priority across all buckets: a "needs_input" agent beats
// a "running" agent beats a "done" agent. statusEnteredAt is the winning // a "running" agent beats a "done" agent. statusEnteredAt is the winning
// bucket's newest agent timestamp. // bucket's newest agent timestamp.
{ {
@@ -4235,7 +4253,7 @@ test("buildWorkspaceDescriptorMap computes statusEnteredAt from runtime agent fi
expect(descriptor.statusEnteredAt).toBe(needsInputUpdatedAt); expect(descriptor.statusEnteredAt).toBe(needsInputUpdatedAt);
} }
// 4. Same-bucket: keep the previous bucket entry time even when newer // 5. Same-bucket: keep the previous bucket entry time even when newer
// agents contribute to the same winning bucket. // agents contribute to the same winning bucket.
{ {
const { session, workspace } = setupSession(); const { session, workspace } = setupSession();