Kaynağa Gözat

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

Kit Langton 4 hafta önce
ebeveyn
işleme
041cda905d

+ 11 - 6
packages/tui/src/routes/session/index.tsx

@@ -2548,10 +2548,8 @@ function WebSearch(props: ToolProps) {
 function Subagent(props: ToolProps) {
   const { navigate } = useRoute()
   const data = useData()
-  const input = createMemo(() => (typeof props.part.state.input === "string" ? {} : props.part.state.input))
-  const metadata = createMemo(() => (props.part.state.status === "streaming" ? {} : props.part.state.structured))
-  const sessionID = createMemo(() => stringValue(metadata().sessionID) ?? stringValue(metadata().sessionId))
-  const description = createMemo(() => stringValue(input().description))
+  const sessionID = createMemo(() => stringValue(props.metadata.sessionID) ?? stringValue(props.metadata.sessionId))
+  const description = createMemo(() => stringValue(props.input.description))
   const isRunning = createMemo(() => {
     const id = sessionID()
     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 })
       }}
       status={
-        input().background === true || metadata().status === "running" ? (
+        isBackgroundSubagent(props.metadata, props.part.state.status) ? (
           <StatusBadge>Background</StatusBadge>
         ) : 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>
   )
 }
 
+export function isBackgroundSubagent(
+  metadata: Record<string, unknown>,
+  status: SessionMessageAssistantTool["state"]["status"],
+) {
+  return status === "completed" && metadata.status === "running"
+}
+
 export function formatSubagentRetry(attempt: number, message: string) {
   return `Retrying (attempt ${attempt}) · ${message}`
 }

+ 8 - 0
packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx

@@ -4,6 +4,7 @@ import { testRender, type JSX } from "@opentui/solid"
 import {
   formatSubagentRetry,
   InlineToolRow,
+  isBackgroundSubagent,
   parseApplyPatchFiles,
   parseDiagnostics,
   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")
   })
 
+  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 () => {
     expect(await renderFrame(() => <Fixture />, { width: 72, height: 12 })).toMatchSnapshot()
   })