diff --git a/CHANGELOG.md b/CHANGELOG.md index 160cbbd2e54..bbda027a48d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Docs: https://docs.openclaw.ai ### Fixes -- Control UI/sessions: nest subagent sessions under their parent session in the session picker dropdown using a visual `└─ ` prefix, making the parent-child relationship clear. Fixes #77628. +- Control UI/sessions: nest subagent sessions under their parent session in the session picker dropdown using a visual `└─ ` prefix, making the parent-child relationship clear. Fixes #77628. (#78623) Thanks @chinar-amrutkar. ### Changes diff --git a/ui/src/ui/app-render.helpers.node.test.ts b/ui/src/ui/app-render.helpers.node.test.ts index 2fc934aa44a..3e55f629811 100644 --- a/ui/src/ui/app-render.helpers.node.test.ts +++ b/ui/src/ui/app-render.helpers.node.test.ts @@ -676,7 +676,23 @@ describe("resolveSessionOptionGroups", () => { }); expect(labels).toContain("Spock"); - expect(labels).toContain("└─ subagent:f4ac7ef1-1234-5678-9abc-def012345678"); + expect(labels).toContain("└─ f4ac7ef1-1234-5678-9abc-def012345678"); + }); + + it("preserves sibling row order when nesting subagent sessions", () => { + const parentKey = "agent:main:main"; + const newerSubagentKey = "agent:main:subagent:newer"; + const olderSubagentKey = "agent:main:subagent:older"; + const labels = labelsForSessionOptions({ + sessionKey: parentKey, + sessions: [ + row({ key: newerSubagentKey, label: "Newer", spawnedBy: parentKey }), + row({ key: olderSubagentKey, label: "Older", spawnedBy: parentKey }), + row({ key: parentKey, label: "Spock" }), + ], + }); + + expect(labels).toEqual(["Spock", "└─ Newer", "└─ Older"]); }); }); diff --git a/ui/src/ui/chat/session-controls.ts b/ui/src/ui/chat/session-controls.ts index 8334ace6765..f0df9a8b1ed 100644 --- a/ui/src/ui/chat/session-controls.ts +++ b/ui/src/ui/chat/session-controls.ts @@ -731,16 +731,32 @@ export function resolveSessionOptionGroups( for (const group of groups.values()) { const options = group.options; - for (let i = options.length - 1; i >= 0; i--) { - const parentKey = options[i].parentKey; - if (parentKey) { - const parentIdx = options.findIndex((o) => o.key === parentKey); - if (parentIdx !== -1) { - const [child] = options.splice(i, 1); - options.splice(parentIdx + 1, 0, child); + const optionKeys = new Set(options.map((option) => option.key)); + const childrenByParent = new Map(); + for (const option of options) { + if (option.parentKey && optionKeys.has(option.parentKey)) { + const siblings = childrenByParent.get(option.parentKey); + if (siblings) { + siblings.push(option); + } else { + childrenByParent.set(option.parentKey, [option]); } } } + if (childrenByParent.size > 0) { + const reordered: SessionOptionEntry[] = []; + for (const option of options) { + if (option.parentKey && optionKeys.has(option.parentKey)) { + continue; + } + reordered.push(option); + const children = childrenByParent.get(option.key); + if (children) { + reordered.push(...children); + } + } + options.splice(0, options.length, ...reordered); + } } for (const group of groups.values()) {