diff --git a/packages/cli/test/config.test.ts b/packages/cli/test/config.test.ts index aea7dc24c8..f0e2d31b81 100644 --- a/packages/cli/test/config.test.ts +++ b/packages/cli/test/config.test.ts @@ -131,7 +131,7 @@ test("updates a config draft while preserving JSONC comments", async () => { const service = yield* Config.Service return yield* service.update((draft) => { draft.prompt = { paste: "compact" } - draft.mini = { thinking: "hide", shell_output: "hide" } + draft.mini = { thinking: "hide", shell_output: "hide", turn_summary: "hide" } }) }), ) @@ -139,7 +139,7 @@ test("updates a config draft while preserving JSONC comments", async () => { expect(config).toEqual({ animations: true, prompt: { paste: "compact" }, - mini: { thinking: "hide", shell_output: "hide" }, + mini: { thinking: "hide", shell_output: "hide", turn_summary: "hide" }, }) expect(await Bun.file(path.join(directory, "cli.json")).text()).toContain("// Keep this comment") } finally { diff --git a/packages/tui/src/config/index.tsx b/packages/tui/src/config/index.tsx index 5e314bda55..447146e41e 100644 --- a/packages/tui/src/config/index.tsx +++ b/packages/tui/src/config/index.tsx @@ -130,6 +130,9 @@ export const Info = Schema.Struct({ shell_output: Schema.optional(Schema.Literals(["show", "hide"])).annotate({ description: "Show or hide raw shell tool output in Mini", }), + turn_summary: Schema.optional(Schema.Literals(["show", "hide"])).annotate({ + description: "Show or hide the agent, model, and duration summary in Mini scrollback", + }), }), ).annotate({ description: "Mini transcript presentation settings" }), hints: Schema.optional( diff --git a/packages/tui/src/mini/footer.command.tsx b/packages/tui/src/mini/footer.command.tsx index e4a161e9d9..1e18cb19af 100644 --- a/packages/tui/src/mini/footer.command.tsx +++ b/packages/tui/src/mini/footer.command.tsx @@ -657,6 +657,14 @@ export function RunSettingsBody(props: { keywords: `shell tool command output ${props.settings().shell_output}`, key: "shell_output", }, + { + category: "Transcript", + display: "Turn summary", + description: "agent, model, and duration", + footer: saving() === "turn_summary" ? "saving" : props.settings().turn_summary, + keywords: `turn summary agent model duration ${props.settings().turn_summary}`, + key: "turn_summary", + }, ]) const change = (item: SettingEntry) => { if (saving()) return diff --git a/packages/tui/src/mini/footer.ts b/packages/tui/src/mini/footer.ts index a8ae8f3c4a..08725f1bdf 100644 --- a/packages/tui/src/mini/footer.ts +++ b/packages/tui/src/mini/footer.ts @@ -384,6 +384,7 @@ export class RunFooter implements FooterApi { } if (next.type === "turn.duration") { + if (this.miniSettings().turn_summary === "hide") return const current = this.currentModel() this.flush() this.flushing = this.flushing diff --git a/packages/tui/src/mini/runtime.boot.ts b/packages/tui/src/mini/runtime.boot.ts index 5b2f640f09..1e9a004d2d 100644 --- a/packages/tui/src/mini/runtime.boot.ts +++ b/packages/tui/src/mini/runtime.boot.ts @@ -88,5 +88,6 @@ export function resolveMiniSettings(config?: { mini?: Partial }): return { thinking: config?.mini?.thinking ?? "hide", shell_output: config?.mini?.shell_output ?? "hide", + turn_summary: config?.mini?.turn_summary ?? "show", } } diff --git a/packages/tui/src/mini/types.ts b/packages/tui/src/mini/types.ts index 72cff6df14..8d0174ac5e 100644 --- a/packages/tui/src/mini/types.ts +++ b/packages/tui/src/mini/types.ts @@ -396,6 +396,7 @@ export type RunTuiConfig = Pick { subagent={subagents} theme={() => RUN_THEME_FALLBACK} tuiConfig={config} - miniSettings={() => ({ thinking: "hide", shell_output: "hide" })} + miniSettings={() => ({ thinking: "hide", shell_output: "hide", turn_summary: "show" })} onSubmit={() => true} onPermissionReply={() => {}} onFormReply={() => {}} diff --git a/packages/tui/test/mini/footer.view.test.tsx b/packages/tui/test/mini/footer.view.test.tsx index 20ebe797d2..c2aac3c6d4 100644 --- a/packages/tui/test/mini/footer.view.test.tsx +++ b/packages/tui/test/mini/footer.view.test.tsx @@ -130,7 +130,9 @@ async function renderFooter( ) const state = footerState(input.state) const config = input.tuiConfig ?? tuiConfig - const [miniSettings] = createSignal(input.miniSettings ?? { thinking: "hide", shell_output: "hide" }) + const [miniSettings] = createSignal( + input.miniSettings ?? { thinking: "hide", shell_output: "hide", turn_summary: "show" }, + ) function Harness() { return ( @@ -418,7 +420,11 @@ test("direct command panel renders grouped command palette", async () => { }) test("direct settings panel changes Mini transcript preferences", async () => { - const [settings, setSettings] = createSignal({ thinking: "hide", shell_output: "hide" }) + const [settings, setSettings] = createSignal({ + thinking: "hide", + shell_output: "hide", + turn_summary: "show", + }) const app = await testRender( () => ( @@ -440,12 +446,20 @@ test("direct settings panel changes Mini transcript preferences", async () => { expect(app.captureCharFrame()).toContain("Settings") expect(app.captureCharFrame()).toContain("Thinking") expect(app.captureCharFrame()).toContain("Shell tool output") + expect(app.captureCharFrame()).toContain("Turn summary") expect(app.captureCharFrame()).toContain("left/right change") app.mockInput.pressKey("ARROW_RIGHT") await app.renderOnce() - expect(settings()).toEqual({ thinking: "show", shell_output: "hide" }) + expect(settings()).toEqual({ thinking: "show", shell_output: "hide", turn_summary: "show" }) + + app.mockInput.pressKey("ARROW_DOWN") + app.mockInput.pressKey("ARROW_DOWN") + app.mockInput.pressKey("ARROW_RIGHT") + await app.renderOnce() + + expect(settings()).toEqual({ thinking: "show", shell_output: "hide", turn_summary: "hide" }) } finally { app.renderer.destroy() } @@ -1099,7 +1113,7 @@ test("direct footer shows authoritative pending work while running", async () => ]} theme={() => RUN_THEME_FALLBACK} tuiConfig={tuiConfig} - miniSettings={() => ({ thinking: "hide", shell_output: "hide" })} + miniSettings={() => ({ thinking: "hide", shell_output: "hide", turn_summary: "show" })} onSubmit={() => true} onPermissionReply={() => {}} onFormReply={() => {}} diff --git a/packages/tui/test/mini/runtime.boot.test.ts b/packages/tui/test/mini/runtime.boot.test.ts index d28ecee687..341dceaeff 100644 --- a/packages/tui/test/mini/runtime.boot.test.ts +++ b/packages/tui/test/mini/runtime.boot.test.ts @@ -103,10 +103,11 @@ describe("run runtime boot", () => { expect(result.theme).toEqual({ mode: "light" }) expect(result.leader.timeout).toBe(450) expect(result.session?.thinking).toBe("show") - expect(resolveMiniSettings(result)).toEqual({ thinking: "hide", shell_output: "hide" }) - expect(resolveMiniSettings({ mini: { thinking: "show", shell_output: "show" } })).toEqual({ + expect(resolveMiniSettings(result)).toEqual({ thinking: "hide", shell_output: "hide", turn_summary: "show" }) + expect(resolveMiniSettings({ mini: { thinking: "show", shell_output: "show", turn_summary: "hide" } })).toEqual({ thinking: "show", shell_output: "show", + turn_summary: "hide", }) })