| author | |
| committer | |
| log | 9146ed2f49a094aa8afee7d3a66987e2a82aaaf6 |
| tree | 1998debaf5e0b1e6fd9a96d702bbba344419ece1 |
| parent | f0f16e4f6e8e923dcb17fc1c25d4fb1e442f80a5 |
| signature | Signed by PGP key B5690EEEBB952194 |
2 files changed, 30 insertions(+), 24 deletions(-)
apps/web/src/components/chat/TraitsPicker.test.ts+20-12| ... | ... | @@ -35,39 +35,48 @@ const CONTEXT_WINDOW = selectDescriptor( |
| 35 | 35 | |
| 36 | 36 | const CODEX = ProviderDriverKind.make("codex"); |
| 37 | 37 | |
| 38 | function display(descriptors: ReadonlyArray<ProviderOptionDescriptor>, fastModeEnabled: boolean) { | |
| 38 | function display(descriptors: ReadonlyArray<ProviderOptionDescriptor>) { | |
| 39 | 39 | return buildTraitsTriggerDisplay({ |
| 40 | 40 | provider: CODEX, |
| 41 | 41 | descriptors, |
| 42 | 42 | primarySelectDescriptorId: "reasoningEffort", |
| 43 | 43 | ultrathinkPromptControlled: false, |
| 44 | fastModeEnabled, | |
| 45 | 44 | }); |
| 46 | 45 | } |
| 47 | 46 | |
| 48 | 47 | describe("buildTraitsTriggerDisplay", () => { |
| 49 | 48 | it("omits fast mode from the label entirely when it is off", () => { |
| 50 | expect(display([EFFORT, fastModeDescriptor(false), CONTEXT_WINDOW], false)).toEqual({ | |
| 49 | expect(display([EFFORT, fastModeDescriptor(false), CONTEXT_WINDOW])).toEqual({ | |
| 51 | 50 | label: "High · 1M", |
| 52 | 51 | showFastModeIcon: false, |
| 53 | 52 | }); |
| 54 | 53 | }); |
| 55 | 54 | |
| 56 | 55 | it("shows the bolt instead of a text label when fast mode is on", () => { |
| 57 | expect(display([EFFORT, fastModeDescriptor(true), CONTEXT_WINDOW], true)).toEqual({ | |
| 56 | expect(display([EFFORT, fastModeDescriptor(true), CONTEXT_WINDOW])).toEqual({ | |
| 58 | 57 | label: "High · 1M", |
| 59 | 58 | showFastModeIcon: true, |
| 60 | 59 | }); |
| 61 | 60 | }); |
| 62 | 61 | |
| 63 | it("omits Codex's default Standard tier beside reasoning", () => { | |
| 62 | it("renders Codex's Standard and Fast service tiers as fast mode", () => { | |
| 64 | 63 | const serviceTier = selectDescriptor( |
| 65 | 64 | "serviceTier", |
| 66 | [{ id: "default", label: "Standard", isDefault: true }], | |
| 65 | [ | |
| 66 | { id: "default", label: "Standard", isDefault: true }, | |
| 67 | { id: "priority", label: "Fast" }, | |
| 68 | ], | |
| 67 | 69 | "default", |
| 68 | 70 | ); |
| 69 | 71 | |
| 70 | expect(display([EFFORT, serviceTier], false).label).toBe("High"); | |
| 72 | expect(display([EFFORT, serviceTier])).toEqual({ | |
| 73 | label: "High", | |
| 74 | showFastModeIcon: false, | |
| 75 | }); | |
| 76 | expect(display([EFFORT, { ...serviceTier, currentValue: "priority" }])).toEqual({ | |
| 77 | label: "High", | |
| 78 | showFastModeIcon: true, | |
| 79 | }); | |
| 71 | 80 | }); |
| 72 | 81 | |
| 73 | 82 | it("keeps non-fastMode booleans as text labels", () => { |
| ... | ... | @@ -77,18 +86,18 @@ describe("buildTraitsTriggerDisplay", () => { |
| 77 | 86 | type: "boolean", |
| 78 | 87 | currentValue: true, |
| 79 | 88 | }; |
| 80 | expect(display([EFFORT, thinking], false)).toEqual({ | |
| 89 | expect(display([EFFORT, thinking])).toEqual({ | |
| 81 | 90 | label: "High · Thinking On", |
| 82 | 91 | showFastModeIcon: false, |
| 83 | 92 | }); |
| 84 | 93 | }); |
| 85 | 94 | |
| 86 | 95 | it("falls back to a text label when fast mode is the only trait", () => { |
| 87 | expect(display([fastModeDescriptor(true)], true)).toEqual({ | |
| 96 | expect(display([fastModeDescriptor(true)])).toEqual({ | |
| 88 | 97 | label: "Fast", |
| 89 | 98 | showFastModeIcon: false, |
| 90 | 99 | }); |
| 91 | expect(display([fastModeDescriptor(false)], false)).toEqual({ | |
| 100 | expect(display([fastModeDescriptor(false)])).toEqual({ | |
| 92 | 101 | label: "Normal", |
| 93 | 102 | showFastModeIcon: false, |
| 94 | 103 | }); |
| ... | ... | @@ -107,7 +116,7 @@ describe("buildTraitsTriggerDisplay", () => { |
| 107 | 116 | { id: "high", label: "High" }, |
| 108 | 117 | ], |
| 109 | 118 | }; |
| 110 | expect(display([unresolved], false)).toEqual({ label: "", showFastModeIcon: false }); | |
| 119 | expect(display([unresolved])).toEqual({ label: "", showFastModeIcon: false }); | |
| 111 | 120 | }); |
| 112 | 121 | |
| 113 | 122 | it("still renders the prompt-controlled ultrathink label alongside the bolt", () => { |
| ... | ... | @@ -117,7 +126,6 @@ describe("buildTraitsTriggerDisplay", () => { |
| 117 | 126 | descriptors: [EFFORT, fastModeDescriptor(true)], |
| 118 | 127 | primarySelectDescriptorId: "reasoningEffort", |
| 119 | 128 | ultrathinkPromptControlled: true, |
| 120 | fastModeEnabled: true, | |
| 121 | 129 | }), |
| 122 | 130 | ).toEqual({ label: "Ultrathink", showFastModeIcon: true }); |
| 123 | 131 | }); |
apps/web/src/components/chat/TraitsPicker.tsx+10-12| ... | ... | @@ -134,8 +134,6 @@ function getSelectedTraits( |
| 134 | 134 | : getDescriptorStringValue(primarySelectDescriptor)) ?? null; |
| 135 | 135 | const thinkingEnabled = |
| 136 | 136 | typeof thinkingDescriptor?.currentValue === "boolean" ? thinkingDescriptor.currentValue : null; |
| 137 | const fastModeEnabled = | |
| 138 | typeof fastModeDescriptor?.currentValue === "boolean" ? fastModeDescriptor.currentValue : false; | |
| 139 | 137 | const contextWindow = getDescriptorStringValue(contextWindowDescriptor); |
| 140 | 138 | const selectedAgent = getDescriptorStringValue(agentDescriptor); |
| 141 | 139 | const selectedAgentLabel = agentDescriptor |
| ... | ... | @@ -154,7 +152,6 @@ function getSelectedTraits( |
| 154 | 152 | thinkingDescriptor, |
| 155 | 153 | effort, |
| 156 | 154 | thinkingEnabled, |
| 157 | fastModeEnabled, | |
| 158 | 155 | contextWindow, |
| 159 | 156 | ultrathinkPromptControlled, |
| 160 | 157 | ultrathinkInBodyText, |
| ... | ... | @@ -392,24 +389,26 @@ export function buildTraitsTriggerDisplay(input: { |
| 392 | 389 | descriptors: ReadonlyArray<ProviderOptionDescriptor>; |
| 393 | 390 | primarySelectDescriptorId: string | null; |
| 394 | 391 | ultrathinkPromptControlled: boolean; |
| 395 | fastModeEnabled: boolean; | |
| 396 | 392 | }): { label: string; showFastModeIcon: boolean } { |
| 397 | 393 | let hasFastMode = false; |
| 394 | let fastModeEnabled = false; | |
| 398 | 395 | const labels: Array<string> = []; |
| 399 | 396 | for (const descriptor of input.descriptors) { |
| 400 | 397 | if (descriptor.id === "fastMode" && descriptor.type === "boolean") { |
| 401 | 398 | hasFastMode = true; |
| 399 | fastModeEnabled = descriptor.currentValue === true; | |
| 402 | 400 | continue; |
| 403 | 401 | } |
| 404 | 402 | if ( |
| 405 | 403 | input.provider === "codex" && |
| 406 | 404 | descriptor.id === "serviceTier" && |
| 407 | descriptor.type === "select" && | |
| 408 | input.descriptors.some(({ id }) => id === "reasoningEffort") | |
| 405 | descriptor.type === "select" | |
| 409 | 406 | ) { |
| 410 | 407 | const currentValue = getProviderOptionCurrentValue(descriptor); |
| 411 | const currentOption = descriptor.options.find((option) => option.id === currentValue); | |
| 412 | if (currentOption?.id === "default" && currentOption.isDefault === true) { | |
| 408 | const fastTier = descriptor.options.find(({ label }) => label === "Fast"); | |
| 409 | if (fastTier && (currentValue === "default" || currentValue === fastTier.id)) { | |
| 410 | hasFastMode = true; | |
| 411 | fastModeEnabled = currentValue === fastTier.id; | |
| 413 | 412 | continue; |
| 414 | 413 | } |
| 415 | 414 | } |
| ... | ... | @@ -428,9 +427,9 @@ export function buildTraitsTriggerDisplay(input: { |
| 428 | 427 | // off an empty label list alone would also catch descriptors that resolved to |
| 429 | 428 | // no label at all, printing a bogus "Normal" for a model without fast mode. |
| 430 | 429 | if (labels.length === 0 && hasFastMode) { |
| 431 | return { label: input.fastModeEnabled ? "Fast" : "Normal", showFastModeIcon: false }; | |
| 430 | return { label: fastModeEnabled ? "Fast" : "Normal", showFastModeIcon: false }; | |
| 432 | 431 | } |
| 433 | return { label: labels.join(" · "), showFastModeIcon: input.fastModeEnabled }; | |
| 432 | return { label: labels.join(" · "), showFastModeIcon: fastModeEnabled }; | |
| 434 | 433 | } |
| 435 | 434 | |
| 436 | 435 | export const TraitsPicker = memo(function TraitsPicker({ |
| ... | ... | @@ -447,7 +446,7 @@ export const TraitsPicker = memo(function TraitsPicker({ |
| 447 | 446 | ...persistence |
| 448 | 447 | }: TraitsMenuContentProps & TraitsPersistence) { |
| 449 | 448 | const [isMenuOpen, setIsMenuOpen] = useState(false); |
| 450 | const { descriptors, primarySelectDescriptor, ultrathinkPromptControlled, fastModeEnabled } = | |
| 449 | const { descriptors, primarySelectDescriptor, ultrathinkPromptControlled } = | |
| 451 | 450 | getTraitsSectionVisibility({ |
| 452 | 451 | provider, |
| 453 | 452 | models, |
| ... | ... | @@ -474,7 +473,6 @@ export const TraitsPicker = memo(function TraitsPicker({ |
| 474 | 473 | descriptors, |
| 475 | 474 | primarySelectDescriptorId: primarySelectDescriptor?.id ?? null, |
| 476 | 475 | ultrathinkPromptControlled, |
| 477 | fastModeEnabled, | |
| 478 | 476 | }); |
| 479 | 477 | const fastModeIcon = showFastModeIcon ? ( |
| 480 | 478 | <> |