fix: unify subagent model display with footer formatting (#863)
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
44
src/tests/cli/subagentDisplay.test.ts
Normal file
44
src/tests/cli/subagentDisplay.test.ts
Normal 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,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user