Stop counting initializing agents as running
This commit is contained in:
@@ -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");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user