diff --git a/packages/kilo-vscode/tests/unit/task-tool-state.test.ts b/packages/kilo-vscode/tests/unit/task-tool-state.test.ts new file mode 100644 index 00000000000..18aba7ca79e --- /dev/null +++ b/packages/kilo-vscode/tests/unit/task-tool-state.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from "bun:test" +import { taskBackground } from "../../webview-ui/src/components/chat/task-tool-state" + +describe("taskBackground", () => { + it("reads the background flag from the streamed input", () => { + expect(taskBackground({ background: true }, undefined, undefined)).toBe(true) + }) + + it("reads the background flag from part or state metadata", () => { + expect(taskBackground({}, { background: true }, undefined)).toBe(true) + expect(taskBackground(undefined, undefined, { background: true })).toBe(true) + }) + + it("prefers part metadata over state metadata", () => { + expect(taskBackground({}, { background: false }, { background: true })).toBe(false) + expect(taskBackground({}, { background: true }, { background: false })).toBe(true) + }) + + it("is false without an explicit true flag", () => { + expect(taskBackground({}, {}, {})).toBe(false) + expect(taskBackground(undefined, undefined, undefined)).toBe(false) + expect(taskBackground({ background: "yes" }, {}, {})).toBe(false) + }) +}) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx index 86552bb7b62..d0051227599 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/TaskToolExpanded.tsx @@ -24,7 +24,14 @@ import { useWorktreeMode } from "../../context/worktree-mode" import { childID, latestTaskPart } from "../../context/session-utils" import { useConfig } from "../../context/config" import { openSubagent } from "./open-subagent" -import { showChildPromotion, taskAvatarStatus, taskResult, taskRunning, taskVisible } from "./task-tool-state" +import { + showChildPromotion, + taskAvatarStatus, + taskBackground, + taskResult, + taskRunning, + taskVisible, +} from "./task-tool-state" const TaskToolRenderer: Component = (props) => { const i18n = useI18n() @@ -63,12 +70,7 @@ const TaskToolRenderer: Component = (props) => { // "Starting..." status, which would flicker the transcript as the child runs. // The input carries `background` from the first part update; promoted tasks // only gain the state metadata flag later. - const backgroundTask = createMemo( - () => - props.input.background === true || - ((props.partMetadata as Record | undefined)?.background ?? - (props.metadata as Record | undefined)?.background) === true, - ) + const backgroundTask = createMemo(() => taskBackground(props.input, props.partMetadata, props.metadata)) const avatar = createMemo(() => { const id = childSessionId() return taskAvatarStatus(id, props.status, session.allStatusMap()) @@ -115,11 +117,11 @@ const TaskToolRenderer: Component = (props) => { } createEffect(() => { if (touched()) return - if (backgroundTask()) { - setOpen(false) + if (auto()) { + setOpen(true) return } - if (props.status === "running") setOpen(true) + if (backgroundTask()) setOpen(false) }) let synced: string | undefined diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/task-tool-state.ts b/packages/kilo-vscode/webview-ui/src/components/chat/task-tool-state.ts index 7014587d2fa..6543ae4c5c0 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/task-tool-state.ts +++ b/packages/kilo-vscode/webview-ui/src/components/chat/task-tool-state.ts @@ -19,6 +19,19 @@ export function taskAvatarStatus( return undefined } +/** + * True when a Task part is a background child. The streamed input carries the + * flag from the first part update; part metadata wins over state metadata. + */ +export function taskBackground( + input: Record | undefined, + part: Record | undefined, + state: Record | undefined, +) { + if (input?.background === true) return true + return (part?.background ?? state?.background) === true +} + export function childForeground( id: string | undefined, part: Record | undefined,