tui: show model context in run footer (#30380)

This commit is contained in:
Simon Klee 2026-06-02 13:09:03 +02:00 committed by GitHub
parent d5a0ddb520
commit 8936914e9d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 26 deletions

View File

@ -739,7 +739,11 @@ export class RunFooter implements FooterApi {
return
}
const previous = this.currentModel()
this.setCurrentModel(model)
if (!previous || previous.providerID !== model.providerID || previous.modelID !== model.modelID) {
this.setCurrentVariant(undefined)
}
void Promise.resolve()
.then(() => this.options.onModelSelect?.(model))
.then((result) => {

View File

@ -53,6 +53,7 @@ import type {
RunTuiConfig,
} from "./types"
import { RUN_THEME_FALLBACK, type RunTheme } from "./theme"
import { modelInfo } from "./variant.shared"
const EMPTY_BORDER = {
topLeft: "",
@ -160,7 +161,11 @@ export function RunFooterView(props: RunFooterViewProps) {
const queuedIndicator = createMemo(() => {
const count = queuedPrompts().length
if (count === 0) return
return { count, label: count === 1 ? "prompt" : "prompts" }
return { count }
})
const model = createMemo(() => {
const current = props.currentModel()
return current ? modelInfo(props.providers(), current) : { model: props.state().model, provider: undefined }
})
const detail = createMemo(() => {
const current = route()
@ -617,16 +622,33 @@ export function RunFooterView(props: RunFooterViewProps) {
{shell() ? "Shell" : props.agent}
</text>
<Show when={!shell()}>
<text
id="run-direct-footer-model"
fg={theme().text}
wrapMode="none"
truncate
flexGrow={1}
flexShrink={1}
>
{props.state().model}
</text>
<box id="run-direct-footer-model" flexDirection="row" gap={1} flexGrow={1} flexShrink={1}>
<text fg={theme().muted} wrapMode="none" flexShrink={0}>
·
</text>
<text fg={theme().text} wrapMode="none" truncate flexShrink={1}>
{model().model}
</text>
<Show when={model().provider}>
{(provider) => (
<text fg={theme().muted} wrapMode="none" truncate flexShrink={1}>
{provider()}
</text>
)}
</Show>
<Show when={props.currentVariant()}>
{(variant) => (
<>
<text fg={theme().muted} wrapMode="none" flexShrink={0}>
·
</text>
<text wrapMode="none" truncate flexShrink={1}>
<span style={{ fg: theme().warning, bold: true }}>{variant()}</span>
</text>
</>
)}
</Show>
</box>
</Show>
</box>
</Show>
@ -746,26 +768,18 @@ export function RunFooterView(props: RunFooterViewProps) {
<Show when={subagentIndicator()}>
{(info) => (
<text id="run-direct-footer-subagents-label" fg={theme().text} wrapMode="none" truncate>
<Show when={busy() || exiting() || duration().length > 0}>
<span style={{ fg: theme().muted }}>· </span>
</Show>
{info().count} <span style={{ fg: theme().muted }}>{info().label}</span>
<span style={{ fg: theme().muted }}> · </span>
<span style={{ fg: theme().highlight }}> </span>
{info().count} <span style={{ fg: theme().muted }}>{info().label} </span>
<span style={{ fg: theme().highlight }}>{subagentShortcut() || "leader+down"}</span>
<span style={{ fg: theme().muted }}> to view</span>
</text>
)}
</Show>
<Show when={queuedIndicator()}>
{(info) => (
<text id="run-direct-footer-queued-label" fg={theme().text} wrapMode="none" truncate>
<Show when={busy() || exiting() || duration().length > 0 || subagentIndicator()}>
<span style={{ fg: theme().muted }}>· </span>
</Show>
{info().count} <span style={{ fg: theme().muted }}>queued {info().label}</span>
<span style={{ fg: theme().muted }}> · </span>
<span style={{ fg: theme().warning }}> </span>
{info().count} <span style={{ fg: theme().muted }}>queued </span>
<span style={{ fg: theme().highlight }}>{queuedShortcut() || "leader+q"}</span>
<span style={{ fg: theme().muted }}> to edit/remove</span>
</text>
)}
</Show>

View File

@ -39,7 +39,7 @@ function variantKey(model: NonNullable<RunInput["model"]>): string {
return modelKey(model.providerID, model.modelID)
}
function modelInfo(providers: RunProvider[] | undefined, model: NonNullable<RunInput["model"]>) {
export function modelInfo(providers: RunProvider[] | undefined, model: NonNullable<RunInput["model"]>) {
const provider = providers?.find((item) => item.id === model.providerID)
return {
provider: provider?.name ?? model.providerID,

View File

@ -647,9 +647,10 @@ test("direct footer shows editable prompts and additional queued work while runn
try {
await app.renderOnce()
expect(app.captureCharFrame()).toContain("interrupt · 1 agent · ctrl+x down to view · 1 queued prompt · ctrl+x q")
expect(app.captureCharFrame()).toContain("interrupt • 1 agent ctrl+x down • 1 queued ctrl+x q")
expect(app.captureCharFrame()).toContain("2 queued")
expect(app.captureCharFrame()).not.toContain("agent · ·")
expect(app.captureCharFrame()).not.toContain("to view")
expect(app.captureCharFrame()).not.toContain("edit/remove")
} finally {
app.renderer.currentFocusedRenderable?.blur()
app.renderer.currentFocusedEditor?.blur()