fix: unify subagent model display with footer formatting (#863)

This commit is contained in:
Charles Packer
2026-02-07 23:37:18 -08:00
committed by GitHub
parent 395ecb1bf4
commit ff64d0ef41
4 changed files with 138 additions and 5 deletions

View File

@@ -18,7 +18,11 @@
import { Box, useInput } from "ink";
import { memo, useSyncExternalStore } from "react";
import { useAnimation } from "../contexts/AnimationContext.js";
import { formatStats, getTreeChars } from "../helpers/subagentDisplay.js";
import {
formatStats,
getSubagentModelDisplay,
getTreeChars,
} from "../helpers/subagentDisplay.js";
import {
getSnapshot,
type SubagentState,
@@ -78,6 +82,7 @@ const AgentRow = memo(
agent.totalTokens,
isRunning,
);
const modelDisplay = getSubagentModelDisplay(agent.model);
const lastTool = agent.toolCalls[agent.toolCalls.length - 1];
// Condensed mode: simplified view to reduce re-renders when overflowing
@@ -101,8 +106,23 @@ const AgentRow = memo(
<Text dimColor>
{" · "}
{agent.type.toLowerCase()}
{agent.model ? ` · ${agent.model}` : ""}
</Text>
{modelDisplay && (
<>
<Text dimColor>{` · ${modelDisplay.label}`}</Text>
{modelDisplay.isByokProvider && (
<Text
color={
modelDisplay.isOpenAICodexProvider
? "#74AA9C"
: "yellow"
}
>
{" ▲"}
</Text>
)}
</>
)}
</Text>
</Box>
{/* Simple status line */}
@@ -142,7 +162,22 @@ const AgentRow = memo(
<Text dimColor>
{" · "}
{agent.type.toLowerCase()}
{agent.model ? ` · ${agent.model}` : ""}
</Text>
{modelDisplay && (
<>
<Text dimColor>{` · ${modelDisplay.label}`}</Text>
{modelDisplay.isByokProvider && (
<Text
color={
modelDisplay.isOpenAICodexProvider ? "#74AA9C" : "yellow"
}
>
{" ▲"}
</Text>
)}
</>
)}
<Text dimColor>
{" · "}
{stats}
</Text>

View File

@@ -15,7 +15,11 @@
import { Box } from "ink";
import { memo } from "react";
import { formatStats, getTreeChars } from "../helpers/subagentDisplay.js";
import {
formatStats,
getSubagentModelDisplay,
getTreeChars,
} from "../helpers/subagentDisplay.js";
import { useTerminalWidth } from "../hooks/useTerminalWidth.js";
import { colors } from "./colors.js";
import { Text } from "./Text";
@@ -59,6 +63,7 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
const isRunning = agent.status === "running";
const shouldDim = isRunning && !agent.isBackground;
const stats = formatStats(agent.toolCount, agent.totalTokens, isRunning);
const modelDisplay = getSubagentModelDisplay(agent.model);
return (
<Box flexDirection="column">
@@ -75,7 +80,22 @@ const AgentRow = memo(({ agent, isLast }: AgentRowProps) => {
<Text dimColor>
{" · "}
{agent.type.toLowerCase()}
{agent.model ? ` · ${agent.model}` : ""}
</Text>
{modelDisplay && (
<>
<Text dimColor>{` · ${modelDisplay.label}`}</Text>
{modelDisplay.isByokProvider && (
<Text
color={
modelDisplay.isOpenAICodexProvider ? "#74AA9C" : "yellow"
}
>
{" ▲"}
</Text>
)}
</>
)}
<Text dimColor>
{" · "}
{stats}
</Text>

View File

@@ -3,6 +3,8 @@
*
* Used by both SubagentGroupDisplay (live) and SubagentGroupStatic (frozen).
*/
import { getModelShortName, resolveModel } from "../../agent/model";
import { OPENAI_CODEX_PROVIDER_NAME } from "../../providers/openai-codex-provider";
/**
* Format tool count and token statistics for display
@@ -46,3 +48,35 @@ export function getTreeChars(isLast: boolean): {
continueChar: isLast ? " " : "│ ",
};
}
export interface SubagentModelDisplay {
label: string;
isByokProvider: boolean;
isOpenAICodexProvider: boolean;
}
/**
* Format a subagent model identifier using the same logic as the input footer:
* short label (if known) + provider-based BYOK marker eligibility.
*/
export function getSubagentModelDisplay(
model: string | undefined,
): SubagentModelDisplay | null {
if (!model) return null;
// Normalize model IDs (e.g. "haiku") to handles before formatting.
const normalized = resolveModel(model) ?? model;
const slashIndex = normalized.indexOf("/");
const provider =
slashIndex >= 0 ? normalized.slice(0, slashIndex) : normalized;
const isOpenAICodexProvider = provider === OPENAI_CODEX_PROVIDER_NAME;
const isByokProvider = provider.startsWith("lc-") || isOpenAICodexProvider;
const label =
getModelShortName(normalized) ?? normalized.split("/").pop() ?? normalized;
return {
label,
isByokProvider,
isOpenAICodexProvider,
};
}

View File

@@ -0,0 +1,44 @@
import { describe, expect, test } from "bun:test";
import { getSubagentModelDisplay } from "../../cli/helpers/subagentDisplay";
describe("getSubagentModelDisplay", () => {
test("formats known model IDs using short labels", () => {
const display = getSubagentModelDisplay("haiku");
expect(display).toEqual({
label: "Haiku 4.5",
isByokProvider: false,
isOpenAICodexProvider: false,
});
});
test("formats non-BYOK handles using short labels", () => {
const display = getSubagentModelDisplay(
"anthropic/claude-haiku-4-5-20251001",
);
expect(display).toEqual({
label: "Haiku 4.5",
isByokProvider: false,
isOpenAICodexProvider: false,
});
});
test("marks lc-* handles as BYOK", () => {
const display = getSubagentModelDisplay(
"lc-anthropic/claude-haiku-4-5-20251001",
);
expect(display).toEqual({
label: "claude-haiku-4-5-20251001",
isByokProvider: true,
isOpenAICodexProvider: false,
});
});
test("marks chatgpt-plus-pro handles as BYOK", () => {
const display = getSubagentModelDisplay("chatgpt-plus-pro/gpt-5.2-codex");
expect(display).toEqual({
label: "GPT-5.2 Codex",
isByokProvider: true,
isOpenAICodexProvider: true,
});
});
});