fix(tui): surface subagent retry status (#29591)

This commit is contained in:
Aiden Cline
2026-05-27 10:11:01 -05:00
committed by GitHub
parent f09c859974
commit 9814dc6526
@@ -54,6 +54,7 @@ import { useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
import { useSDK } from "@tui/context/sdk" import { useSDK } from "@tui/context/sdk"
import { useEditorContext } from "@tui/context/editor" import { useEditorContext } from "@tui/context/editor"
import { useDialog } from "../../ui/dialog" import { useDialog } from "../../ui/dialog"
import { DialogAlert } from "../../ui/dialog-alert"
import { TodoItem } from "../../component/todo-item" import { TodoItem } from "../../component/todo-item"
import { DialogMessage } from "./dialog-message" import { DialogMessage } from "./dialog-message"
import type { PromptInfo } from "../../component/prompt/history" import type { PromptInfo } from "../../component/prompt/history"
@@ -409,15 +410,19 @@ export function Session() {
const local = useLocal() const local = useLocal()
function enterChild(sessionID: string) {
navigate({
type: "session",
sessionID,
})
const status = sync.data.session_status[sessionID]
if (status?.type === "retry") void DialogAlert.show(dialog, "Retry Error", status.message)
}
function moveFirstChild() { function moveFirstChild() {
if (children().length === 1) return if (children().length === 1) return
const next = children().find((x) => !!x.parentID) const next = children().find((x) => !!x.parentID)
if (next) { if (next) enterChild(next.id)
navigate({
type: "session",
sessionID: next.id,
})
}
} }
function moveChild(direction: number) { function moveChild(direction: number) {
@@ -428,12 +433,7 @@ export function Session() {
if (next >= sessions.length) next = 0 if (next >= sessions.length) next = 0
if (next < 0) next = sessions.length - 1 if (next < 0) next = sessions.length - 1
if (sessions[next]) { if (sessions[next]) enterChild(sessions[next].id)
navigate({
type: "session",
sessionID: sessions[next].id,
})
}
} }
function childSessionHandler(func: () => void) { function childSessionHandler(func: () => void) {
@@ -1007,8 +1007,8 @@ export function Session() {
category: "Session", category: "Session",
hidden: true, hidden: true,
run: () => { run: () => {
moveFirstChild()
dialog.clear() dialog.clear()
moveFirstChild()
}, },
}, },
{ {
@@ -1035,8 +1035,8 @@ export function Session() {
hidden: true, hidden: true,
enabled: !!session()?.parentID, enabled: !!session()?.parentID,
run: childSessionHandler(() => { run: childSessionHandler(() => {
moveChild(1)
dialog.clear() dialog.clear()
moveChild(1)
}), }),
}, },
{ {
@@ -1046,8 +1046,8 @@ export function Session() {
hidden: true, hidden: true,
enabled: !!session()?.parentID, enabled: !!session()?.parentID,
run: childSessionHandler(() => { run: childSessionHandler(() => {
moveChild(-1)
dialog.clear() dialog.clear()
moveChild(-1)
}), }),
}, },
]) ])
@@ -1758,6 +1758,7 @@ function GenericTool(props: ToolProps<any>) {
function InlineTool(props: { function InlineTool(props: {
icon: string icon: string
iconColor?: RGBA iconColor?: RGBA
color?: RGBA
complete: any complete: any
pending: string pending: string
spinner?: boolean spinner?: boolean
@@ -1779,6 +1780,7 @@ function InlineTool(props: {
}) })
const fg = createMemo(() => { const fg = createMemo(() => {
if (props.color) return props.color
if (permission()) return theme.warning if (permission()) return theme.warning
if (hover() && props.onClick) return theme.text if (hover() && props.onClick) return theme.text
if (props.complete) return theme.textMuted if (props.complete) return theme.textMuted
@@ -2063,8 +2065,10 @@ function WebSearch(props: ToolProps<typeof WebSearchTool>) {
} }
function Task(props: ToolProps<typeof TaskTool>) { function Task(props: ToolProps<typeof TaskTool>) {
const { theme } = useTheme()
const { navigate } = useRoute() const { navigate } = useRoute()
const sync = useSync() const sync = useSync()
const dialog = useDialog()
onMount(() => { onMount(() => {
if (props.metadata.sessionId && !sync.data.message[props.metadata.sessionId]?.length) if (props.metadata.sessionId && !sync.data.message[props.metadata.sessionId]?.length)
@@ -2086,6 +2090,11 @@ function Task(props: ToolProps<typeof TaskTool>) {
) )
const isRunning = createMemo(() => props.part.state.status === "running") const isRunning = createMemo(() => props.part.state.status === "running")
const retry = createMemo(() => {
const status = sync.data.session_status[props.metadata.sessionId ?? ""]
if (status?.type !== "retry") return
return status
})
const duration = createMemo(() => { const duration = createMemo(() => {
const first = messages().find((x) => x.role === "user")?.time.created const first = messages().find((x) => x.role === "user")?.time.created
@@ -2100,7 +2109,10 @@ function Task(props: ToolProps<typeof TaskTool>) {
props.metadata.background === true ? `${props.input.description} (background)` : props.input.description props.metadata.background === true ? `${props.input.description} (background)` : props.input.description
let content = [`${Locale.titlecase(props.input.subagent_type ?? "General")} Task — ${description}`] let content = [`${Locale.titlecase(props.input.subagent_type ?? "General")} Task — ${description}`]
if (isRunning() && tools().length > 0) { const retrying = retry()
if (isRunning() && retrying) {
content.push(`${Locale.truncate(retrying.message, 80)} [retrying attempt #${retrying.attempt}]`)
} else if (isRunning() && tools().length > 0) {
// content[0] += ` · ${tools().length} toolcalls` // content[0] += ` · ${tools().length} toolcalls`
if (current()) { if (current()) {
const state = current()!.state const state = current()!.state
@@ -2123,6 +2135,7 @@ function Task(props: ToolProps<typeof TaskTool>) {
return ( return (
<InlineTool <InlineTool
icon="│" icon="│"
color={retry() ? theme.error : undefined}
spinner={isRunning()} spinner={isRunning()}
complete={props.input.description} complete={props.input.description}
pending="Delegating..." pending="Delegating..."
@@ -2131,6 +2144,8 @@ function Task(props: ToolProps<typeof TaskTool>) {
if (props.metadata.sessionId) { if (props.metadata.sessionId) {
navigate({ type: "session", sessionID: props.metadata.sessionId }) navigate({ type: "session", sessionID: props.metadata.sessionId })
} }
const status = retry()
if (status) void DialogAlert.show(dialog, "Retry Error", status.message)
}} }}
> >
{content()} {content()}