Repository navigation
fix(web-shell): sync background agent status #7561
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ytahdn
merged 2 commits into
QwenLM:main
from
chiga0:codex/fix-background-agent-status-and-sidebar
Jul 23, 2026
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # Background agent status and details | ||
|
|
||
| ## Problem | ||
|
|
||
| An Agent tool call returns as soon as a background agent is launched. Its transcript block therefore has a terminal tool event whose payload says `status: background`. The Web Shell intentionally maps that launch result back to a pending tool card, but nothing later reconciles the card with the live background-task registry. The footer task list reaches a terminal state while the original Agent card remains running. | ||
|
|
||
| Foreground agents already open in the shared subagent detail panel. Background agents have the same `toolUseId`, task registry entry, JSONL transcript, and virtual-session resolver, but this path lacks explicit coverage. | ||
|
|
||
| ## Design | ||
|
|
||
| Keep the launch projection unchanged: a launch result with `status: background` remains pending until authoritative task state arrives. The daemon already emits terminal background-agent notifications over the session SSE stream with the task `status` and `toolUseId`. The Web Shell consumes that hidden notification metadata and reconciles it back into the projected Agent tool card. | ||
|
|
||
| - `completed` and `cancelled` complete the card. | ||
| - `failed` fails the card. | ||
| - The notification timestamp becomes the card end time. | ||
| - Notifications without `toolUseId`, non-agent notifications, and unrelated tool calls do not directly change messages. | ||
|
|
||
| The existing subagent detail provider remains the only UI path. Background Agent cards stay clickable while pending and after terminal reconciliation. The virtual-session resolver continues to stream the task JSONL and obtain live status from the task registry without filtering on foreground/background mode. For legacy tasks without `toolUseId`, it matches the launch record to the persisted sidecar and keeps a terminal sidecar status when the original background launch result still says `running`. | ||
|
|
||
| While detached work is active, its main-list card uses a dedicated static `background task` label instead of the foreground `running` label. The card does not use the running shimmer or a ticking elapsed timer. Terminal notifications replace that label with the normal completed, failed, or cancelled presentation. | ||
|
|
||
| Background agents are omitted from the bottom status bar because their progress is available from the clickable card and detail panel. They remain in the full Tasks panel. Other background task kinds, including shell commands, remain in the bottom status bar and retain their existing polling. A background Agent by itself does not activate bottom-bar task polling. | ||
|
|
||
| Persisted notification records do not always retain a `toolUseId`. When a loaded transcript contains an active background Agent card, the Web Shell therefore resolves each pending card through the existing subagent endpoint after transcript catch-up. It repeats this one-shot check after a reconnect and when any terminal Agent notification arrives, even if that notification cannot identify the card directly. It never starts an interval. Input focus and ordinary streaming do not change the pending Agent call IDs or terminal-notification key and therefore do not trigger another request. | ||
|
|
||
| The docked detail panel expands from the right edge so the chat is pushed left continuously instead of resizing before a separate panel motion. Reduced-motion preferences disable the docked animation. Panel tabs keep a fixed width, truncate long titles, and scroll horizontally when the tab list exceeds the available space. | ||
|
|
||
| ## Scope | ||
|
|
||
| This change updates the Web Shell projection and the daemon's virtual-subagent status resolver. It does not rewrite persisted parent transcripts, alter the task lifecycle, add task polling for background agents, remove agents from the full Tasks panel, or add a second subagent viewer. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -128,6 +128,25 @@ function normalizeTaskStatus(status: unknown): string | undefined { | |
| return status; | ||
| } | ||
|
|
||
| function isTerminalTaskStatus(status: string | undefined): boolean { | ||
| return ( | ||
| status === 'completed' || | ||
| status === 'failed' || | ||
| status === 'cancelled' || | ||
| status === 'canceled' | ||
| ); | ||
| } | ||
|
|
||
| export function preferTerminalTaskStatus( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] Good — the general — qwen3.8-max-preview via Qwen Code /review |
||
| metricsStatus: string | undefined, | ||
| selectedStatus: string, | ||
| ): string { | ||
| return !isTerminalTaskStatus(metricsStatus) && | ||
| isTerminalTaskStatus(selectedStatus) | ||
| ? selectedStatus | ||
| : (metricsStatus ?? selectedStatus); | ||
| } | ||
|
|
||
| function durationBetween(start: string, end?: string): number | undefined { | ||
| if (!end) return undefined; | ||
| const startTime = Date.parse(start); | ||
|
|
@@ -849,7 +868,7 @@ export class VirtualSubagentSessions { | |
| const metrics = findToolCallMetrics(parentRecords, toolCallId); | ||
| return { | ||
| ...selected, | ||
| status: metrics.status ?? selected.status, | ||
| status: preferTerminalTaskStatus(metrics.status, selected.status), | ||
| durationMs: metrics.durationMs ?? selected.durationMs, | ||
| totalTokens: metrics.totalTokens ?? selected.totalTokens, | ||
| inputTokens: metrics.inputTokens ?? selected.inputTokens, | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The unit test only exercises the direction where
metricsStatusis non-terminal andselectedStatusis terminal; the reverse direction — a terminalmetricsStatusover a non-terminalselectedStatus(themetricsStatus ?? selectedStatusfallback path) — has no direct coverage. — Concrete cost: a regression simplifyingpreferTerminalTaskStatusto always returnselectedStatuswould pass both existing parametrized cases (selectedStatusis'completed'in each). In production, when the parent transcript metrics already record a terminal status (e.g.'failed') but the sidecar/registry status is still'running', the function would silently return'running'instead of'failed'.— qwen3.8-max-preview via Qwen Code /review