mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
fix(ui): label stopped Swarm outcomes accurately (#149508)
Describe the existing combined failure, timeout, and cancellation count as failed or stopped. Keep authoritative totals and protocol unchanged, cover active and terminal summaries, and clarify the combined count in the Swarm docs.
This commit is contained in:
parent
7bcb0a2e8e
commit
ca9c4d54d2
3 changed files with 55 additions and 28 deletions
|
|
@ -382,9 +382,10 @@ Keep the parent session open in Chat while a swarm is active. The Control UI and
|
|||
native Android, iOS, and macOS chat surfaces show a compact Swarm progress widget
|
||||
between the transcript and composer.
|
||||
|
||||
In the Control UI, cards show queued, running, completed, and failed counts with
|
||||
visible status markers. Click or tap **Child details**, or activate it with the
|
||||
keyboard, to expand available child names, status icons, and run durations. The
|
||||
In the Control UI, cards show queued, running, completed, and **failed or stopped**
|
||||
counts with visible status markers. The combined count includes failures, timeouts,
|
||||
and cancelled children; the summary does not report these outcomes separately.
|
||||
Click or tap **Child details**, or activate it with the keyboard, to expand available child names, status icons, and run durations. The
|
||||
view shows up to four active groups plus the latest completed group, with an
|
||||
explicit count when more groups are active. Each card displays at most 64 markers
|
||||
and 64 child details. Its counts include every accepted group member.
|
||||
|
|
@ -392,16 +393,16 @@ and 64 child details. Its counts include every accepted group member.
|
|||
The latest completed group's counts remain visible after the children finish,
|
||||
including when the parent fails before writing its final response. Groups whose
|
||||
children all succeed use a compact completion row. Activate the row to expand
|
||||
child details and the final-response reminder. Running, queued, and failed groups
|
||||
keep their visible status markers and counts. These are
|
||||
child outcomes, not confirmation that the parent produced a synthesis. Counts
|
||||
child details and the final-response reminder. Groups with running, queued,
|
||||
failed, or stopped children keep their visible status markers and counts. These
|
||||
are child outcomes, not confirmation that the parent produced a synthesis. Counts
|
||||
come from retained collector records, so reloading the page or cleaning up a
|
||||
child session does not reduce the reported total. They expire with the existing
|
||||
collector retention policy. This is not a permanent execution archive.
|
||||
|
||||
Native Android, iOS, and macOS chat surfaces still show active-only phase-grouped
|
||||
grids, capped at 256 markers per phase with an overflow count. Accessible labels
|
||||
identify each child's status. All clients present killed and timed-out children
|
||||
identify each child's status. Native clients present killed and timed-out children
|
||||
as failed. Native groups leave the widget when none of their children are queued
|
||||
or running. The native widget disappears when no active groups remain.
|
||||
|
||||
|
|
|
|||
|
|
@ -2836,8 +2836,8 @@ export const en: TranslationMap & {
|
|||
groupTitle: "Parallel tasks",
|
||||
defaultPhase: "Unphased",
|
||||
progress: "{complete} of {total}",
|
||||
active: "{running} running · {queued} queued · {failed} failed",
|
||||
finished: "{done} completed · {failed} failed",
|
||||
active: "{running} running · {queued} queued · {failed} failed or stopped",
|
||||
finished: "{done} completed · {failed} failed or stopped",
|
||||
completed: "{done} completed",
|
||||
childOutcome: "Child runs finished. Check the conversation for the final response.",
|
||||
childOutcomeProcessing: "Child runs finished. The parent is processing their results.",
|
||||
|
|
|
|||
|
|
@ -279,27 +279,53 @@ describe("chat Swarm progress", () => {
|
|||
expect(container.querySelector("[data-test-id=chat-swarm]")).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps completed and failed child outcomes visible after the group finishes", () => {
|
||||
const running = session({ key: "running", status: "running" });
|
||||
const completed = session({ key: "completed", status: "done", hasActiveRun: true });
|
||||
const failed = session({ key: "failed", status: "failed", hasActiveRun: true });
|
||||
const container = renderProgress([running, completed, failed]);
|
||||
it.each([
|
||||
{ name: "failed", statuses: ["failed"], completed: 1 },
|
||||
{ name: "stopped", statuses: Array.from({ length: 9 }, () => "killed" as const), completed: 0 },
|
||||
{ name: "mixed", statuses: ["failed", "killed", "timeout"], completed: 1 },
|
||||
] as const)(
|
||||
"labels $name outcomes as a combined count through completion",
|
||||
({ statuses, completed }) => {
|
||||
const terminal = [
|
||||
...Array.from({ length: completed }, (_, index) =>
|
||||
session({ key: `completed-${index}`, status: "done", hasActiveRun: true }),
|
||||
),
|
||||
...statuses.map((status, index) =>
|
||||
session({ key: `unsuccessful-${index}`, status, hasActiveRun: true }),
|
||||
),
|
||||
];
|
||||
const container = renderProgress([
|
||||
session({ key: "running", status: "running" }),
|
||||
...terminal,
|
||||
]);
|
||||
const activeCounts = `1 running · 0 queued · ${statuses.length} failed or stopped`;
|
||||
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--running")).toHaveLength(1);
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--done")).toHaveLength(1);
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--failed")).toHaveLength(1);
|
||||
expect(container.querySelector(".chat-swarm__counts")?.textContent).toBe(activeCounts);
|
||||
expect(container.querySelector(".chat-swarm__markers")?.getAttribute("aria-label")).toBe(
|
||||
activeCounts,
|
||||
);
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--running")).toHaveLength(1);
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--done")).toHaveLength(completed);
|
||||
expect(container.querySelectorAll(".chat-swarm__task-icon--failed")).toHaveLength(
|
||||
statuses.length,
|
||||
);
|
||||
|
||||
render(
|
||||
renderChatSwarmProgress({
|
||||
sessionKey: parentSessionKey,
|
||||
sessions: withSummary([completed, failed]),
|
||||
}),
|
||||
container,
|
||||
);
|
||||
expect(container.querySelector("[data-test-id=chat-swarm]")).not.toBeNull();
|
||||
expect(container.textContent).toContain("1 completed · 1 failed");
|
||||
expect(container.textContent).toContain("Check the conversation for the final response");
|
||||
});
|
||||
render(
|
||||
renderChatSwarmProgress({
|
||||
sessionKey: parentSessionKey,
|
||||
sessions: withSummary(terminal),
|
||||
}),
|
||||
container,
|
||||
);
|
||||
const finishedCounts = `${completed} completed · ${statuses.length} failed or stopped`;
|
||||
expect(container.querySelector("[data-test-id=chat-swarm]")).not.toBeNull();
|
||||
expect(container.querySelector(".chat-swarm__counts")?.textContent).toBe(finishedCounts);
|
||||
expect(container.querySelector(".chat-swarm__markers")?.getAttribute("aria-label")).toBe(
|
||||
finishedCounts,
|
||||
);
|
||||
expect(container.textContent).toContain("Check the conversation for the final response");
|
||||
},
|
||||
);
|
||||
|
||||
it("says the parent is processing while child runs are finished but the parent is still active", () => {
|
||||
const completed = session({ key: "completed", status: "done", hasActiveRun: true });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue