From a906cb75ce9f077cc20282fbb4a0b7c35ff63d65 Mon Sep 17 00:00:00 2001 From: Val Alexander <68980965+BunsDev@users.noreply.github.com> Date: Tue, 5 May 2026 22:11:20 -0500 Subject: [PATCH] fix(ui): resolve session thinking defaults --- ui/src/ui/views/sessions.test.ts | 42 ++++++++++++++++++++++++++++++-- ui/src/ui/views/sessions.ts | 36 ++++++++++++++++++++++----- 2 files changed, 70 insertions(+), 8 deletions(-) diff --git a/ui/src/ui/views/sessions.test.ts b/ui/src/ui/views/sessions.test.ts index 9f231788df8..99a5f0b531b 100644 --- a/ui/src/ui/views/sessions.test.ts +++ b/ui/src/ui/views/sessions.test.ts @@ -5,12 +5,15 @@ import { describe, expect, it, vi } from "vitest"; import type { SessionsListResult } from "../types.ts"; import { renderSessions, type SessionsProps } from "./sessions.ts"; -function buildResult(session: SessionsListResult["sessions"][number]): SessionsListResult { +function buildResult( + session: SessionsListResult["sessions"][number], + defaults?: Partial, +): SessionsListResult { return { ts: Date.now(), path: "(multiple)", count: 1, - defaults: { modelProvider: null, model: null, contextTokens: null }, + defaults: { modelProvider: null, model: null, contextTokens: null, ...defaults }, sessions: [session], }; } @@ -268,6 +271,41 @@ describe("sessions view", () => { ).toBe("Override: adaptive"); }); + it("labels inherited thinking from list defaults when lightweight rows omit row defaults", async () => { + const container = document.createElement("div"); + render( + renderSessions( + buildProps( + buildResult( + { + key: "agent:main:main", + kind: "direct", + updatedAt: Date.now(), + }, + { + modelProvider: "openai-codex", + model: "gpt-5.5", + thinkingDefault: "high", + thinkingLevels: [ + { id: "off", label: "off" }, + { id: "high", label: "high" }, + ], + }, + ), + ), + ), + container, + ); + await Promise.resolve(); + + const thinking = container.querySelector("tbody select") as HTMLSelectElement | null; + expect(thinking?.value).toBe(""); + expect(thinking?.options[0]?.textContent?.trim()).toBe("Inherited: high"); + expect(Array.from(thinking?.options ?? []).map((option) => option.textContent?.trim())).toEqual( + ["Inherited: high", "Off", "Override: high"], + ); + }); + it("keeps legacy binary thinking labels patching canonical ids", async () => { const container = document.createElement("div"); const onPatch = vi.fn(); diff --git a/ui/src/ui/views/sessions.ts b/ui/src/ui/views/sessions.ts index c44b498f93f..85a39664203 100644 --- a/ui/src/ui/views/sessions.ts +++ b/ui/src/ui/views/sessions.ts @@ -92,16 +92,37 @@ function getAgentIdentity( : null; } +function rowMatchesSessionDefaults( + row: GatewaySessionRow, + defaults: SessionsListResult["defaults"] | undefined, +): boolean { + return ( + (!row.modelProvider || row.modelProvider === defaults?.modelProvider) && + (!row.model || row.model === defaults?.model) + ); +} + function resolveThinkLevelOptions( row: GatewaySessionRow, + defaults?: SessionsListResult["defaults"], ): readonly { value: string; label: string }[] { - const defaultLabel = formatInheritedThinkingLabel(row.thinkingDefault); + const sessionModelMatchesDefaults = rowMatchesSessionDefaults(row, defaults); + const defaultLabel = formatInheritedThinkingLabel( + row.thinkingDefault ?? (sessionModelMatchesDefaults ? defaults?.thinkingDefault : undefined), + ); const options: readonly GatewayThinkingLevelOption[] = row.thinkingLevels?.length ? row.thinkingLevels - : (row.thinkingOptions?.length ? row.thinkingOptions : DEFAULT_THINK_LEVELS).map((label) => ({ - id: normalizeThinkingOptionValue(label), - label, - })); + : sessionModelMatchesDefaults && defaults?.thinkingLevels?.length + ? defaults.thinkingLevels + : (row.thinkingOptions?.length + ? row.thinkingOptions + : sessionModelMatchesDefaults && defaults?.thinkingOptions?.length + ? defaults.thinkingOptions + : DEFAULT_THINK_LEVELS + ).map((label) => ({ + id: normalizeThinkingOptionValue(label), + label, + })); return [ { value: "", label: defaultLabel }, ...options.map((option) => ({ @@ -684,7 +705,10 @@ function renderRows(row: GatewaySessionRow, props: SessionsProps) { const updated = row.updatedAt ? formatRelativeTimestamp(row.updatedAt) : t("common.na"); const rawThinking = row.thinkingLevel ?? ""; const thinking = rawThinking ? normalizeThinkingOptionValue(rawThinking) : ""; - const thinkLevels = withCurrentLabeledOption(resolveThinkLevelOptions(row), thinking); + const thinkLevels = withCurrentLabeledOption( + resolveThinkLevelOptions(row, props.result?.defaults), + thinking, + ); const fastMode = row.fastMode === true ? "on" : row.fastMode === false ? "off" : ""; const fastLevels = withCurrentLabeledOption(buildFastLevelOptions(), fastMode); const verbose = row.verboseLevel ?? "";