fix(tui): label only detached subagents as background (#37306)

This commit is contained in:
Kit Langton 2026-07-16 12:21:19 -04:00 committed by GitHub
commit 041cda905d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 19 additions and 6 deletions

View file

@ -2548,10 +2548,8 @@ function WebSearch(props: ToolProps) {
function Subagent(props: ToolProps) { function Subagent(props: ToolProps) {
const { navigate } = useRoute() const { navigate } = useRoute()
const data = useData() const data = useData()
const input = createMemo(() => (typeof props.part.state.input === "string" ? {} : props.part.state.input)) const sessionID = createMemo(() => stringValue(props.metadata.sessionID) ?? stringValue(props.metadata.sessionId))
const metadata = createMemo(() => (props.part.state.status === "streaming" ? {} : props.part.state.structured)) const description = createMemo(() => stringValue(props.input.description))
const sessionID = createMemo(() => stringValue(metadata().sessionID) ?? stringValue(metadata().sessionId))
const description = createMemo(() => stringValue(input().description))
const isRunning = createMemo(() => { const isRunning = createMemo(() => {
const id = sessionID() const id = sessionID()
return props.part.state.status === "running" || Boolean(id && data.session.status(id) === "running") return props.part.state.status === "running" || Boolean(id && data.session.status(id) === "running")
@ -2569,16 +2567,23 @@ function Subagent(props: ToolProps) {
if (id) navigate({ type: "session", sessionID: id }) if (id) navigate({ type: "session", sessionID: id })
}} }}
status={ status={
input().background === true || metadata().status === "running" ? ( isBackgroundSubagent(props.metadata, props.part.state.status) ? (
<StatusBadge>Background</StatusBadge> <StatusBadge>Background</StatusBadge>
) : undefined ) : undefined
} }
> >
{`${Locale.titlecase(stringValue(input().agent) ?? stringValue(input().subagent_type) ?? "General")} Subagent — ${description() ?? "Subagent"}`} {`${Locale.titlecase(stringValue(props.input.agent) ?? stringValue(props.input.subagent_type) ?? "General")} Subagent — ${description() ?? "Subagent"}`}
</InlineTool> </InlineTool>
) )
} }
export function isBackgroundSubagent(
metadata: Record<string, unknown>,
status: SessionMessageAssistantTool["state"]["status"],
) {
return status === "completed" && metadata.status === "running"
}
export function formatSubagentRetry(attempt: number, message: string) { export function formatSubagentRetry(attempt: number, message: string) {
return `Retrying (attempt ${attempt}) · ${message}` return `Retrying (attempt ${attempt}) · ${message}`
} }

View file

@ -4,6 +4,7 @@ import { testRender, type JSX } from "@opentui/solid"
import { import {
formatSubagentRetry, formatSubagentRetry,
InlineToolRow, InlineToolRow,
isBackgroundSubagent,
parseApplyPatchFiles, parseApplyPatchFiles,
parseDiagnostics, parseDiagnostics,
parseQuestionAnswers, parseQuestionAnswers,
@ -201,6 +202,13 @@ describe("TUI inline tool wrapping", () => {
expect(formatSubagentRetry(2, "Rate limited by provider")).toBe("Retrying (attempt 2) · Rate limited by provider") expect(formatSubagentRetry(2, "Rate limited by provider")).toBe("Retrying (attempt 2) · Rate limited by provider")
}) })
test("labels only detached or async subagents as background", () => {
expect(isBackgroundSubagent({ status: "running" }, "running")).toBeFalse()
expect(isBackgroundSubagent({ status: "running" }, "completed")).toBeTrue()
expect(isBackgroundSubagent({ status: "running" }, "error")).toBeFalse()
expect(isBackgroundSubagent({ status: "completed" }, "completed")).toBeFalse()
})
test("snapshots consecutive grep, glob, and read rows at a narrow width", async () => { test("snapshots consecutive grep, glob, and read rows at a narrow width", async () => {
expect(await renderFrame(() => <Fixture />, { width: 72, height: 12 })).toMatchSnapshot() expect(await renderFrame(() => <Fixture />, { width: 72, height: 12 })).toMatchSnapshot()
}) })