tui: show model context in run footer (#30380)
This commit is contained in:
@@ -739,7 +739,11 @@ export class RunFooter implements FooterApi {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const previous = this.currentModel()
|
||||||
this.setCurrentModel(model)
|
this.setCurrentModel(model)
|
||||||
|
if (!previous || previous.providerID !== model.providerID || previous.modelID !== model.modelID) {
|
||||||
|
this.setCurrentVariant(undefined)
|
||||||
|
}
|
||||||
void Promise.resolve()
|
void Promise.resolve()
|
||||||
.then(() => this.options.onModelSelect?.(model))
|
.then(() => this.options.onModelSelect?.(model))
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import type {
|
|||||||
RunTuiConfig,
|
RunTuiConfig,
|
||||||
} from "./types"
|
} from "./types"
|
||||||
import { RUN_THEME_FALLBACK, type RunTheme } from "./theme"
|
import { RUN_THEME_FALLBACK, type RunTheme } from "./theme"
|
||||||
|
import { modelInfo } from "./variant.shared"
|
||||||
|
|
||||||
const EMPTY_BORDER = {
|
const EMPTY_BORDER = {
|
||||||
topLeft: "",
|
topLeft: "",
|
||||||
@@ -160,7 +161,11 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
const queuedIndicator = createMemo(() => {
|
const queuedIndicator = createMemo(() => {
|
||||||
const count = queuedPrompts().length
|
const count = queuedPrompts().length
|
||||||
if (count === 0) return
|
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 detail = createMemo(() => {
|
||||||
const current = route()
|
const current = route()
|
||||||
@@ -617,16 +622,33 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
{shell() ? "Shell" : props.agent}
|
{shell() ? "Shell" : props.agent}
|
||||||
</text>
|
</text>
|
||||||
<Show when={!shell()}>
|
<Show when={!shell()}>
|
||||||
<text
|
<box id="run-direct-footer-model" flexDirection="row" gap={1} flexGrow={1} flexShrink={1}>
|
||||||
id="run-direct-footer-model"
|
<text fg={theme().muted} wrapMode="none" flexShrink={0}>
|
||||||
fg={theme().text}
|
·
|
||||||
wrapMode="none"
|
</text>
|
||||||
truncate
|
<text fg={theme().text} wrapMode="none" truncate flexShrink={1}>
|
||||||
flexGrow={1}
|
{model().model}
|
||||||
flexShrink={1}
|
</text>
|
||||||
>
|
<Show when={model().provider}>
|
||||||
{props.state().model}
|
{(provider) => (
|
||||||
</text>
|
<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>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -746,26 +768,18 @@ export function RunFooterView(props: RunFooterViewProps) {
|
|||||||
<Show when={subagentIndicator()}>
|
<Show when={subagentIndicator()}>
|
||||||
{(info) => (
|
{(info) => (
|
||||||
<text id="run-direct-footer-subagents-label" fg={theme().text} wrapMode="none" truncate>
|
<text id="run-direct-footer-subagents-label" fg={theme().text} wrapMode="none" truncate>
|
||||||
<Show when={busy() || exiting() || duration().length > 0}>
|
<span style={{ fg: theme().highlight }}>• </span>
|
||||||
<span style={{ fg: theme().muted }}>· </span>
|
{info().count} <span style={{ fg: theme().muted }}>{info().label} </span>
|
||||||
</Show>
|
|
||||||
{info().count} <span style={{ fg: theme().muted }}>{info().label}</span>
|
|
||||||
<span style={{ fg: theme().muted }}> · </span>
|
|
||||||
<span style={{ fg: theme().highlight }}>{subagentShortcut() || "leader+down"}</span>
|
<span style={{ fg: theme().highlight }}>{subagentShortcut() || "leader+down"}</span>
|
||||||
<span style={{ fg: theme().muted }}> to view</span>
|
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={queuedIndicator()}>
|
<Show when={queuedIndicator()}>
|
||||||
{(info) => (
|
{(info) => (
|
||||||
<text id="run-direct-footer-queued-label" fg={theme().text} wrapMode="none" truncate>
|
<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().warning }}>• </span>
|
||||||
<span style={{ fg: theme().muted }}>· </span>
|
{info().count} <span style={{ fg: theme().muted }}>queued </span>
|
||||||
</Show>
|
|
||||||
{info().count} <span style={{ fg: theme().muted }}>queued {info().label}</span>
|
|
||||||
<span style={{ fg: theme().muted }}> · </span>
|
|
||||||
<span style={{ fg: theme().highlight }}>{queuedShortcut() || "leader+q"}</span>
|
<span style={{ fg: theme().highlight }}>{queuedShortcut() || "leader+q"}</span>
|
||||||
<span style={{ fg: theme().muted }}> to edit/remove</span>
|
|
||||||
</text>
|
</text>
|
||||||
)}
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function variantKey(model: NonNullable<RunInput["model"]>): string {
|
|||||||
return modelKey(model.providerID, model.modelID)
|
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)
|
const provider = providers?.find((item) => item.id === model.providerID)
|
||||||
return {
|
return {
|
||||||
provider: provider?.name ?? model.providerID,
|
provider: provider?.name ?? model.providerID,
|
||||||
|
|||||||
@@ -647,9 +647,10 @@ test("direct footer shows editable prompts and additional queued work while runn
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await app.renderOnce()
|
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()).toContain("2 queued")
|
||||||
expect(app.captureCharFrame()).not.toContain("agent · ·")
|
expect(app.captureCharFrame()).not.toContain("to view")
|
||||||
|
expect(app.captureCharFrame()).not.toContain("edit/remove")
|
||||||
} finally {
|
} finally {
|
||||||
app.renderer.currentFocusedRenderable?.blur()
|
app.renderer.currentFocusedRenderable?.blur()
|
||||||
app.renderer.currentFocusedEditor?.blur()
|
app.renderer.currentFocusedEditor?.blur()
|
||||||
|
|||||||
Reference in New Issue
Block a user