From b1734a492f71ee31a310d87bb08b814ae4b5f4f7 Mon Sep 17 00:00:00 2001 From: nntrivi2001 Date: Thu, 27 Aug 2026 13:33:55 +0700 Subject: [PATCH] feat(run): tool-aware model picker and run panel labels for codex lanes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model dropdown now shows curated Claude vs Codex models per lane's tool, and the run panel title/subtitle/binary-missing text switch between "Chạy Claude"/"Chạy Codex" accordingly. --- client/src/components/run/LaneConsolePane.tsx | 9 ++++--- client/src/components/run/RunSetup.tsx | 21 ++++++++++----- .../run/__tests__/LaneConsolePane.test.tsx | 1 + .../run/__tests__/RunSetup.test.tsx | 4 +-- client/src/i18n/locales/en/run.json | 8 +++--- client/src/i18n/locales/vi/run.json | 8 +++--- client/src/lib/api.ts | 26 ++++++++++--------- .../screens.snapshot.test.tsx.snap | 2 +- 8 files changed, 47 insertions(+), 32 deletions(-) diff --git a/client/src/components/run/LaneConsolePane.tsx b/client/src/components/run/LaneConsolePane.tsx index 50989b05..7bab72e5 100644 --- a/client/src/components/run/LaneConsolePane.tsx +++ b/client/src/components/run/LaneConsolePane.tsx @@ -88,6 +88,7 @@ export function LaneConsolePane({ const currentLane = laneId !== null ? lanes.find((l) => l.id === laneId) : null; const laneTool = currentLane?.tool ?? "claude"; + const toolLabel = laneTool === "codex" ? "Codex" : "Claude"; useEffect(() => { onHasActiveRunChange?.(handle !== null); @@ -419,7 +420,9 @@ export function LaneConsolePane({
-

{t("title")}

+

+ {t("title", { tool: toolLabel })} +

{wsConnected ? ( @@ -432,7 +435,7 @@ export function LaneConsolePane({ )}
-

{t("subtitle")}

+

{t("subtitle", { tool: toolLabel })}

- {t("binary.missing")} + {t("binary.missing", { cli: laneTool, tool: toolLabel })} )} diff --git a/client/src/components/run/RunSetup.tsx b/client/src/components/run/RunSetup.tsx index d323a33d..bf0de199 100644 --- a/client/src/components/run/RunSetup.tsx +++ b/client/src/components/run/RunSetup.tsx @@ -42,7 +42,7 @@ import { RotateCcw, Lock, } from "lucide-react"; -import { api, RUN_MODEL_CHOICES, RUN_EFFORT_CHOICES } from "../../lib/api"; +import { api, RUN_MODEL_CHOICES, RUN_MODEL_CHOICES_CODEX, RUN_EFFORT_CHOICES } from "../../lib/api"; import type { CwdSuggestion, DashboardRunHistoryItem, @@ -233,7 +233,7 @@ export function RunSetup(props: RunSetupProps) { )} - + {props.tool === "codex" ? ( <> @@ -712,10 +712,19 @@ function SessionPicker({ // the "inherit from settings" choice, so use a non-empty marker. const MODEL_CUSTOM = "__custom__"; -function ModelPicker({ value, onChange }: { value: string; onChange: (s: string) => void }) { +function ModelPicker({ + value, + onChange, + tool, +}: { + value: string; + onChange: (s: string) => void; + tool: LaneTool; +}) { const { t } = useTranslation("run"); + const choices = tool === "codex" ? RUN_MODEL_CHOICES_CODEX : RUN_MODEL_CHOICES; // "Custom" is selected when the value isn't one of our curated IDs. - const knownIds = useMemo(() => RUN_MODEL_CHOICES.map((c) => c.id), []); + const knownIds = useMemo(() => choices.map((c) => c.id), [choices]); const isCustom = value !== "" && !knownIds.includes(value); const [showCustom, setShowCustom] = useState(isCustom); @@ -724,14 +733,14 @@ function ModelPicker({ value, onChange }: { value: string; onChange: (s: string) // a browser-native