From 7f15a8e673d6fbf83a3efdb6edc799ae278f3d42 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Tue, 30 Jun 2026 17:25:36 -0700 Subject: [PATCH 1/3] Restore the ultrathink frame border effect (#3625) (cherry picked from commit 7b9eef7ac29f9d4819c6411dfb1c5f04fef50264) --- apps/web/src/index.css | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/web/src/index.css b/apps/web/src/index.css index a48a00c9bc7..8ba440e095c 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -707,12 +707,35 @@ label:has(> select#reasoning-effort) select { #ec4899 90%, #ff6b6b 100% ); + position: relative; + background: transparent; +} + +.ultrathink-frame::before { + content: ""; + position: absolute; + inset: 0; + border-radius: inherit; + padding: 2px; background-image: var(--ultrathink-spectrum); background-size: 220% 220%; + pointer-events: none; filter: saturate(0.82) brightness(0.92); + -webkit-mask: + linear-gradient(#000 0 0) content-box, + linear-gradient(#000 0 0); + -webkit-mask-composite: xor; + mask: + linear-gradient(#000 0 0) content-box, + linear-gradient(#000 0 0); + mask-composite: exclude; animation: ultrathink-rainbow 10s linear infinite; } +.ultrathink-frame > * { + position: relative; +} + .ultrathink-chroma { animation: ultrathink-chroma-shift 10s linear infinite; } From 2c0c51dd78f36572a433e944a4bd2de7b262c059 Mon Sep 17 00:00:00 2001 From: "cursor[bot]" <206951365+cursor[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 12:52:13 -0700 Subject: [PATCH 2/3] Stabilize composer provider state while typing (#3507) Co-authored-by: Cursor Agent Co-authored-by: Julius Marminge (cherry picked from commit f5f98cf0ae48a14b524480a0942f9ce37190656c) --- apps/web/src/components/chat/ChatComposer.tsx | 9 ++++++-- .../chat/composerProviderState.test.tsx | 22 ++++++++++++------- .../components/chat/composerProviderState.tsx | 12 +++++++--- apps/web/src/modelSelection.ts | 2 -- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/apps/web/src/components/chat/ChatComposer.tsx b/apps/web/src/components/chat/ChatComposer.tsx index c54b3386166..5fa79868c88 100644 --- a/apps/web/src/components/chat/ChatComposer.tsx +++ b/apps/web/src/components/chat/ChatComposer.tsx @@ -71,6 +71,7 @@ import { ComposerPlanFollowUpBanner } from "./ComposerPlanFollowUpBanner"; import { resolveComposerMenuActiveItemId } from "./composerMenuHighlight"; import { searchSlashMenuItems } from "./composerSlashMenuSearch"; import { + getComposerPromptInjectionState, getComposerProviderState, renderProviderTraitsMenuContent, renderProviderTraitsPicker, @@ -747,18 +748,22 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) [selectedProviderEntry], ); + const composerPromptInjectionState = useMemo( + () => getComposerPromptInjectionState(prompt), + [prompt], + ); const composerProviderState = useMemo( () => getComposerProviderState({ provider: selectedProvider, model: selectedModel, models: selectedProviderModels, - prompt, + promptInjectionState: composerPromptInjectionState, modelOptions: composerModelOptions?.[selectedInstanceId], }), [ composerModelOptions, - prompt, + composerPromptInjectionState, selectedInstanceId, selectedModel, selectedProvider, diff --git a/apps/web/src/components/chat/composerProviderState.test.tsx b/apps/web/src/components/chat/composerProviderState.test.tsx index 07eec55de2c..067e71ef1bf 100644 --- a/apps/web/src/components/chat/composerProviderState.test.tsx +++ b/apps/web/src/components/chat/composerProviderState.test.tsx @@ -6,6 +6,7 @@ import { type ServerProviderModel, } from "@t3tools/contracts"; import { + getComposerPromptInjectionState, getComposerProviderState, renderProviderTraitsMenuContent, renderProviderTraitsPicker, @@ -61,6 +62,13 @@ const ULTRATHINK_FRAME_CLASSES = { } as const; describe("getComposerProviderState", () => { + it("derives a stable prompt injection state for ordinary prompt edits", () => { + expect(getComposerPromptInjectionState("Investigate this failure")).toBe("none"); + expect(getComposerPromptInjectionState("Ultrathink:\nInvestigate this failure")).toBe( + "ultrathink", + ); + }); + it("returns descriptor defaults when no selections are provided", () => { const state = getComposerProviderState({ provider: PROVIDER, @@ -71,7 +79,6 @@ describe("getComposerProviderState", () => { { id: "high", label: "High", isDefault: true }, ]), ]), - prompt: "", modelOptions: undefined, }); @@ -93,7 +100,6 @@ describe("getComposerProviderState", () => { ]), booleanDescriptor("fastMode"), ]), - prompt: "", modelOptions: selections(["effort", "low"], ["fastMode", true]), }); @@ -112,7 +118,6 @@ describe("getComposerProviderState", () => { selectDescriptor("effort", [{ id: "high", label: "High", isDefault: true }]), booleanDescriptor("fastMode"), ]), - prompt: "", modelOptions: selections(["effort", "high"], ["fastMode", false]), }); @@ -126,7 +131,6 @@ describe("getComposerProviderState", () => { provider: PROVIDER, model: MODEL, models: modelWith([booleanDescriptor("thinking")]), - prompt: "", modelOptions: selections(["effort", "max"], ["thinking", false]), }); @@ -152,7 +156,6 @@ describe("getComposerProviderState", () => { { id: "plan", label: "Plan" }, ]), ]), - prompt: "", modelOptions: selections(["agent", "plan"]), }); @@ -167,7 +170,6 @@ describe("getComposerProviderState", () => { provider: PROVIDER, model: MODEL, models: modelWith([]), - prompt: "", modelOptions: selections(["anything", "value"]), }); @@ -193,7 +195,9 @@ describe("getComposerProviderState", () => { ["ultrathink"], ), ]), - prompt: "Ultrathink:\nInvestigate this failure", + promptInjectionState: getComposerPromptInjectionState( + "Ultrathink:\nInvestigate this failure", + ), modelOptions: selections(["effort", "medium"]), }); @@ -212,7 +216,9 @@ describe("getComposerProviderState", () => { models: modelWith([ selectDescriptor("effort", [{ id: "high", label: "High", isDefault: true }]), ]), - prompt: "Ultrathink:\nInvestigate this failure", + promptInjectionState: getComposerPromptInjectionState( + "Ultrathink:\nInvestigate this failure", + ), modelOptions: undefined, }); diff --git a/apps/web/src/components/chat/composerProviderState.tsx b/apps/web/src/components/chat/composerProviderState.tsx index b5cc790538d..1349e2509b7 100644 --- a/apps/web/src/components/chat/composerProviderState.tsx +++ b/apps/web/src/components/chat/composerProviderState.tsx @@ -21,10 +21,12 @@ export type ComposerProviderStateInput = { provider: ProviderDriverKind; model: string; models: ReadonlyArray; - prompt: string; + promptInjectionState?: ComposerPromptInjectionState; modelOptions: ReadonlyArray | null | undefined; }; +export type ComposerPromptInjectionState = "none" | "ultrathink"; + export type ComposerProviderState = { provider: ProviderDriverKind; promptEffort: string | null; @@ -46,8 +48,12 @@ type TraitsRenderInput = { onPromptChange: (prompt: string) => void; }; +export function getComposerPromptInjectionState(prompt: string): ComposerPromptInjectionState { + return isClaudeUltrathinkPrompt(prompt) ? "ultrathink" : "none"; +} + export function getComposerProviderState(input: ComposerProviderStateInput): ComposerProviderState { - const { provider, model, models, prompt, modelOptions } = input; + const { provider, model, models, modelOptions, promptInjectionState = "none" } = input; const caps = getProviderModelCapabilities(models, model, provider); const descriptors = getProviderOptionDescriptors({ caps, selections: modelOptions }); const primarySelectDescriptor = descriptors.find( @@ -58,7 +64,7 @@ export function getComposerProviderState(input: ComposerProviderStateInput): Com const promptEffort = typeof primaryValue === "string" ? primaryValue : null; const ultrathinkActive = (primarySelectDescriptor?.promptInjectedValues?.length ?? 0) > 0 && - isClaudeUltrathinkPrompt(prompt); + promptInjectionState === "ultrathink"; return { provider, diff --git a/apps/web/src/modelSelection.ts b/apps/web/src/modelSelection.ts index 0fcf680b732..7ede9665ac9 100644 --- a/apps/web/src/modelSelection.ts +++ b/apps/web/src/modelSelection.ts @@ -303,7 +303,6 @@ export function resolveAppModelSelectionState( provider, model, models: entry.models, - prompt: "", modelOptions: selectedEntry ? selection.options : undefined, }); @@ -321,7 +320,6 @@ export function resolveAppModelSelectionState( provider, model, models: getProviderModels(providers, provider), - prompt: "", modelOptions: keptSelectedProvider ? selection.options : undefined, }); From 691a954c5d112ef480cc01fdfecf1a07bbe72a70 Mon Sep 17 00:00:00 2001 From: Sullaimon Date: Sat, 4 Jul 2026 07:46:14 -0400 Subject: [PATCH 3/3] Document composer prompt injection stability --- apps/web/src/components/chat/composerProviderState.test.tsx | 3 +++ apps/web/src/components/chat/composerProviderState.tsx | 1 + 2 files changed, 4 insertions(+) diff --git a/apps/web/src/components/chat/composerProviderState.test.tsx b/apps/web/src/components/chat/composerProviderState.test.tsx index 067e71ef1bf..b0bd2d20c99 100644 --- a/apps/web/src/components/chat/composerProviderState.test.tsx +++ b/apps/web/src/components/chat/composerProviderState.test.tsx @@ -67,6 +67,9 @@ describe("getComposerProviderState", () => { expect(getComposerPromptInjectionState("Ultrathink:\nInvestigate this failure")).toBe( "ultrathink", ); + expect(getComposerPromptInjectionState("Ultrathink:\nInvestigate this failure deeply")).toBe( + "ultrathink", + ); }); it("returns descriptor defaults when no selections are provided", () => { diff --git a/apps/web/src/components/chat/composerProviderState.tsx b/apps/web/src/components/chat/composerProviderState.tsx index 1349e2509b7..ed1c4fef8f1 100644 --- a/apps/web/src/components/chat/composerProviderState.tsx +++ b/apps/web/src/components/chat/composerProviderState.tsx @@ -21,6 +21,7 @@ export type ComposerProviderStateInput = { provider: ProviderDriverKind; model: string; models: ReadonlyArray; + // Coarse prompt-derived state keeps provider chrome stable across ordinary body edits. promptInjectionState?: ComposerPromptInjectionState; modelOptions: ReadonlyArray | null | undefined; };