# Files changed · PR \#23040 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/23040/diffs)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

[perf\(web\): typing no longer re-renders the traits picker or attach button](https://git.cafe/pingdotgg/t3code/pull/23040.md)

Version: 7

Head commit: ec8a0878b4c9eb31ff47432a143893d0fedba6d9

Base commit: 0bdf33a34dc520d3ab1364cd116686b3492184bd

Comparison base: 9179178fdff5ac750c29ef8d6234d5e75538c124

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## apps/web/src/components/chat/ChatComposer.tsx

Status: modified; +87; −80

```diff
@@ -290,6 +290,7 @@
   renderProviderTraitsMenuContent,
   renderProviderTraitsPicker,
 } from "./composerProviderState";
+import { readPromptUltrathink } from "./TraitsPicker";
 import {
   providerSupportsManualCompaction,
   resolveContextWindowModelDisplayName,
@@ -2307,7 +2308,10 @@
         activePendingProgress.activeQuestion?.allowCustomAnswer !== false));
   const composerFooterHasWideActions = showPlanFollowUpPrompt || activePendingProgress !== null;
 
+  const editPromptFromTraits = (edit: (prompt: string) => string) => {
-  const setPromptFromTraits = (nextPrompt: string) => {
+    const currentPrompt = getComposerDraft(composerDraftTarget)?.prompt ?? "";
+    const nextPrompt = edit(currentPrompt);
+    if (nextPrompt === currentPrompt) return;
     if (nextPrompt === promptRef.current) {
       scheduleComposerFocus();
       return;
@@ -2319,7 +2323,8 @@
     setComposerTrigger(detectComposerTrigger(nextPrompt, nextPrompt.length));
     scheduleComposerFocus();
   };
+  const editPromptFromTraitsStable = useStableCallback(editPromptFromTraits);
+  const promptUltrathink = readPromptUltrathink(prompt);
-  const setPromptFromTraitsStable = useStableCallback(setPromptFromTraits);
 
   const providerTraitsMenuContent = renderProviderTraitsMenuContent({
     provider: selectedProvider,
@@ -2330,8 +2335,8 @@
     models: selectedProviderModels,
     modelOptions: composerModelOptions?.[selectedInstanceId],
     reportedModelSelection,
+    promptUltrathink,
+    onPromptEdit: editPromptFromTraitsStable,
-    prompt,
-    onPromptChange: setPromptFromTraitsStable,
     planModeEnabled: settings.planModeEnabled,
   });
   const providerTraitsPickerInput = {
@@ -2343,8 +2348,8 @@
     models: selectedProviderModels,
     modelOptions: composerModelOptions?.[selectedInstanceId],
     reportedModelSelection,
+    promptUltrathink,
-    prompt,
-    onPromptChange: setPromptFromTraitsStable,
+    onPromptEdit: editPromptFromTraitsStable,
     planModeEnabled: settings.planModeEnabled,
     isComposerOwned: true,
   } satisfies Parameters<typeof renderProviderTraitsPicker>[0];
@@ -4736,6 +4741,82 @@
     terminalOpen,
   ]);
 
+  const insertComposerText = (
+    text: string,
+    position: "cursor" | "end",
+    options?: {
+      ensureLeadingBoundary?: boolean;
+      citationCommentAnchor?: AssistantCitationSourceAnchor;
+      clipboardData?: DataTransfer;
+    },
+  ): boolean => {
+    if (
+      text.length === 0 ||
+      isConnecting ||
+      activePendingIsResponding ||
+      (pendingUserInputs.length > 0 && !activePendingProgress?.activeQuestion) ||
+      projectSelectionRequired ||
+      (options?.citationCommentAnchor && !composerEditorRef.current)
+    ) {
+      return false;
+    }
+    if (options?.clipboardData) {
+      text = importPastedComposerText(options.clipboardData, importContextFragment);
+    }
+    const prompt = promptRef.current;
+    const cursor = position === "cursor" ? readComposerSnapshot().expandedCursor : prompt.length;
+    const needsLeadingSpace =
+      (options?.ensureLeadingBoundary ?? false) &&
+      cursor > 0 &&
+      !/\s/.test(prompt[cursor - 1] ?? "");
+    const rangeEnd = extendReplacementRangeForTrailingSpace(prompt, cursor, text);
+    return applyPromptReplacement(
+      cursor,
+      rangeEnd,
+      needsLeadingSpace ? ` ${text}` : text,
+      options?.citationCommentAnchor
+        ? {
+            citationComment: {
+              start: cursor + (needsLeadingSpace ? 1 : 0),
+              sourceAnchor: options.citationCommentAnchor,
+              insertedSpaces: { before: needsLeadingSpace, after: rangeEnd === cursor },
+            },
+            focusEditorAfterReplace: false,
+          }
+        : undefined,
+    );
+  };
+  const insertComposerTextStable = useStableCallback(insertComposerText);
+
+  const insertAttachmentReferences = (
+    references: ReadonlyArray<ComposerContextReference>,
+    selection?: { start: number; end: number },
+  ): boolean => {
+    if (references.length === 0) return false;
+    // Question answers carry attachments beside the answer, never as chips. Falling back to
+    // the thread prompt here would hide the file behind a reference the question never shows.
+    if (questionAttachmentTarget) return false;
+    return insertAttachmentReferencesForDraft({
+      target: composerDraftTarget,
+      liveAttachmentTargetKey: attachmentTargetKeyRef.current,
+      references,
+      insertReferences: () => {
+        if (selection) {
+          const edit = inlineContextReferenceReplacement(promptRef.current, selection, references);
+          return applyPromptReplacementStable(edit.start, edit.end, edit.text);
+        }
+        const text = references.map(formatInlineContextReference).join(" ");
+        const inserted = insertComposerTextStable(`${text} `, "cursor", {
+          ensureLeadingBoundary: true,
+        });
+        if (!inserted) {
+          setPrompt(ensureInlineContextReferences(promptRef.current, references));
+        }
+        return true;
+      },
+    });
+  };
+
   const addComposerAttachments = async (
     files: File[],
     options?: {
@@ -4944,33 +5025,6 @@
     });
   };
 
-  const insertAttachmentReferences = (
-    references: ReadonlyArray<ComposerContextReference>,
-    selection?: { start: number; end: number },
-  ): boolean => {
-    if (references.length === 0) return false;
-    // Question answers carry attachments beside the answer, never as chips. Falling back to
-    // the thread prompt here would hide the file behind a reference the question never shows.
-    if (questionAttachmentTarget) return false;
-    return insertAttachmentReferencesForDraft({
-      target: composerDraftTarget,
-      liveAttachmentTargetKey: attachmentTargetKeyRef.current,
-      references,
-      insertReferences: () => {
-        if (selection) {
-          const edit = inlineContextReferenceReplacement(promptRef.current, selection, references);
-          return applyPromptReplacement(edit.start, edit.end, edit.text);
-        }
-        const text = references.map(formatInlineContextReference).join(" ");
-        const inserted = insertComposerText(`${text} `, "cursor", { ensureLeadingBoundary: true });
-        if (!inserted) {
-          setPrompt(ensureInlineContextReferences(promptRef.current, references));
-        }
-        return true;
-      },
-    });
-  };
-
   const removeComposerImage = (imageId: string) => {
     const image = composerImagesRef.current.find((candidate) => candidate.id === imageId);
     const referenced = collectInlineContextIds(promptRef.current).includes(
@@ -5075,53 +5129,6 @@
     () => resolveActiveComposerTrigger().trigger?.kind === "path",
   );
 
-  const insertComposerText = (
-    text: string,
-    position: "cursor" | "end",
-    options?: {
-      ensureLeadingBoundary?: boolean;
-      citationCommentAnchor?: AssistantCitationSourceAnchor;
-      clipboardData?: DataTransfer;
-    },
-  ): boolean => {
-    if (
-      text.length === 0 ||
-      isConnecting ||
-      activePendingIsResponding ||
-      (pendingUserInputs.length > 0 && !activePendingProgress?.activeQuestion) ||
-      projectSelectionRequired ||
-      (options?.citationCommentAnchor && !composerEditorRef.current)
-    ) {
-      return false;
-    }
-    if (options?.clipboardData) {
-      text = importPastedComposerText(options.clipboardData, importContextFragment);
-    }
-    const prompt = promptRef.current;
-    const cursor = position === "cursor" ? readComposerSnapshot().expandedCursor : prompt.length;
-    const needsLeadingSpace =
-      (options?.ensureLeadingBoundary ?? false) &&
-      cursor > 0 &&
-      !/\s/.test(prompt[cursor - 1] ?? "");
-    const rangeEnd = extendReplacementRangeForTrailingSpace(prompt, cursor, text);
-    return applyPromptReplacement(
-      cursor,
-      rangeEnd,
-      needsLeadingSpace ? ` ${text}` : text,
-      options?.citationCommentAnchor
-        ? {
-            citationComment: {
-              start: cursor + (needsLeadingSpace ? 1 : 0),
-              sourceAnchor: options.citationCommentAnchor,
-              insertedSpaces: { before: needsLeadingSpace, after: rangeEnd === cursor },
-            },
-            focusEditorAfterReplace: false,
-          }
-        : undefined,
-    );
-  };
-  const insertComposerTextStable = useStableCallback(insertComposerText);
-
   const insertComposerTextAtEnd: ChatComposerHandle["insertTextAtEnd"] = (text, options) => {
     const inserted = insertComposerText(text, "end", options);
     if (inserted && isComposerCollapsedMobile) {
```

## apps/web/src/components/chat/TraitsPicker.tsx

Status: modified; +39; −24

```diff
@@ -1,7 +1,6 @@
 import {
   buildTraitsTriggerDisplay,
   getDescriptorStringValue,
-  getPromptControlledTraits,
   getTraitSelectChange,
   replaceDescriptorCurrentValue,
   selectableProviderOptionChoices,
@@ -21,6 +20,7 @@
   buildProviderOptionSelectionsFromDescriptors,
   getProviderOptionCurrentLabel,
   getProviderOptionDescriptors,
+  isClaudeUltrathinkPrompt,
   normalizeModelSlug,
 } from "@t3tools/shared/model";
 import { memo } from "react";
@@ -49,7 +49,18 @@
 import { useComposerMenuState } from "./useComposerMenuState";
 
 type ProviderOptions = ReadonlyArray<ProviderOptionSelection>;
+
+/**
+ * All the picker reads from the prompt while rendering. Passing this instead of
+ * the prompt keeps the picker from re-rendering on every keystroke.
+ */
+export type PromptUltrathink = "none" | "prefix" | "body";
 
+export function readPromptUltrathink(prompt: string): PromptUltrathink {
+  if (!isClaudeUltrathinkPrompt(prompt)) return "none";
+  return isClaudeUltrathinkPrompt(prompt.replace(/^Ultrathink:\s*/i, "")) ? "body" : "prefix";
+}
+
 const SAVED_OPTION_LABELS: Readonly<Record<string, string>> = {
   agent: "Agent",
   effort: "Effort",
@@ -108,7 +119,7 @@
   provider: ProviderDriverKind,
   models: ReadonlyArray<ServerProviderModel>,
   model: string | null | undefined,
-  prompt: string,
+  promptUltrathink: PromptUltrathink,
   modelOptions: ProviderOptions | null | undefined,
   allowPromptInjectedEffort: boolean,
   planModeEnabled: boolean,
@@ -144,11 +155,11 @@
   const thinkingDescriptor =
     booleanDescriptors.find((descriptor) => descriptor.id === "thinking") ?? null;
 
-  const { ultrathinkPromptControlled, ultrathinkInBodyText } = getPromptControlledTraits(
-    descriptors,
-    prompt,
-    allowPromptInjectedEffort,
-  );
+  const ultrathinkPromptControlled =
+    allowPromptInjectedEffort &&
+    (primarySelectDescriptor?.promptInjectedValues?.length ?? 0) > 0 &&
+    promptUltrathink !== "none";
+  const ultrathinkInBodyText = ultrathinkPromptControlled && promptUltrathink === "body";
   const effort =
     (ultrathinkPromptControlled
       ? "ultrathink"
@@ -186,7 +197,7 @@
   provider: ProviderDriverKind;
   models: ReadonlyArray<ServerProviderModel>;
   model: string | null | undefined;
-  prompt: string;
+  promptUltrathink?: PromptUltrathink | undefined;
   modelOptions: ProviderOptions | null | undefined;
   allowPromptInjectedEffort?: boolean;
   planModeEnabled: boolean;
@@ -195,7 +206,7 @@
     input.provider,
     input.models,
     input.model,
-    input.prompt,
+    input.promptUltrathink ?? "none",
     input.modelOptions,
     input.allowPromptInjectedEffort ?? true,
     input.planModeEnabled,
@@ -244,7 +255,7 @@
     input.provider,
     input.models,
     input.model,
-    input.prompt,
+    readPromptUltrathink(input.prompt),
     input.modelOptions,
     true,
     input.planModeEnabled,
@@ -291,7 +302,7 @@
   provider: ProviderDriverKind;
   models: ReadonlyArray<ServerProviderModel>;
   model: string | null | undefined;
+  promptUltrathink?: PromptUltrathink | undefined;
-  prompt: string;
   modelOptions: ProviderOptions | null | undefined;
   allowPromptInjectedEffort?: boolean;
   planModeEnabled: boolean;
@@ -304,8 +315,9 @@
   instanceId?: ProviderInstanceId;
   models: ReadonlyArray<ServerProviderModel>;
   model: string | null | undefined;
-  prompt: string;
-  onPromptChange: (prompt: string) => void;
+  promptUltrathink?: PromptUltrathink | undefined;
+  /** Receives an edit of the live prompt; the picker never holds the prompt text itself. */
+  onPromptEdit?: (edit: (prompt: string) => string) => void;
   modelOptions?: ProviderOptions | null | undefined;
   reportedModelSelection?: ModelSelection | null | undefined;
   allowPromptInjectedEffort?: boolean;
@@ -319,8 +331,8 @@
   instanceId,
   models,
   model,
-  prompt,
-  onPromptChange,
+  promptUltrathink,
+  onPromptEdit,
   modelOptions,
   reportedModelSelection,
   allowPromptInjectedEffort = true,
@@ -349,7 +361,7 @@
     provider,
     models,
     model,
-    prompt,
+    promptUltrathink,
     modelOptions,
     allowPromptInjectedEffort,
     planModeEnabled,
@@ -372,9 +384,12 @@
     descriptor: Extract<ProviderOptionDescriptor, { type: "select" }>,
     value: string,
   ) => {
-    const change = getTraitSelectChange(selected, descriptor, prompt, value);
+    // Whether a pick applies, and the options it writes, do not depend on the prompt text.
+    const change = getTraitSelectChange(selected, descriptor, "", value);
     if (!change) return;
+    onPromptEdit?.(
-    if (change.prompt !== prompt) onPromptChange(change.prompt);
+      (prompt) => getTraitSelectChange(selected, descriptor, prompt, value)?.prompt ?? prompt,
+    );
     if ("modelOptions" in change) updateModelOptions(change.modelOptions);
   };
 
@@ -500,8 +515,8 @@
   instanceId,
   models,
   model,
-  prompt,
-  onPromptChange,
+  promptUltrathink,
+  onPromptEdit,
   modelOptions,
   reportedModelSelection,
   allowPromptInjectedEffort = true,
@@ -525,7 +540,7 @@
       provider,
       models,
       model,
+      promptUltrathink,
-      prompt,
       modelOptions,
       allowPromptInjectedEffort,
       planModeEnabled,
@@ -535,7 +550,7 @@
       provider,
       models,
       model,
-      prompt,
+      promptUltrathink,
       modelOptions,
       allowPromptInjectedEffort,
       planModeEnabled,
@@ -611,8 +626,8 @@
           {...(instanceId ? { instanceId } : {})}
           models={models}
           model={model}
+          promptUltrathink={promptUltrathink}
-          prompt={prompt}
+          {...(onPromptEdit ? { onPromptEdit } : {})}
-          onPromptChange={onPromptChange}
           modelOptions={modelOptions}
           reportedModelSelection={reportedModelSelection}
           allowPromptInjectedEffort={allowPromptInjectedEffort}
```

## apps/web/src/components/chat/composerProviderState.test.tsx

Status: modified; +10; −0

```diff
@@ -11,6 +11,7 @@
   getComposerReasoningStep,
   withImplicitFastModeDefault,
 } from "./composerProviderState";
+import { readPromptUltrathink } from "./TraitsPicker";
 
 const PROVIDER: ProviderDriverKind = ProviderDriverKind.make("codex");
 const MODEL = "test-model";
@@ -238,6 +239,15 @@
   });
 });
 
+describe("readPromptUltrathink", () => {
+  it("tells the Ultrathink prefix apart from the word in the body", () => {
+    expect(readPromptUltrathink("Fix the bug")).toBe("none");
+    expect(readPromptUltrathink("Ultrathink: Fix the bug")).toBe("prefix");
+    expect(readPromptUltrathink("ultrathink about the bug")).toBe("body");
+    expect(readPromptUltrathink("Ultrathink: ultrathink harder")).toBe("body");
+  });
+});
+
 describe("getComposerReasoningStep", () => {
   const LEVELS = [
     { id: "low", label: "Low" },
```

## apps/web/src/components/chat/composerProviderState.tsx

Status: modified; +8; −7

```diff
@@ -24,6 +24,7 @@
   shouldRenderTraitsControls,
   TraitsMenuContent,
   TraitsPicker,
+  type PromptUltrathink,
 } from "./TraitsPicker";
 
 export type ComposerProviderStateInput = {
@@ -55,8 +56,8 @@
   models: ReadonlyArray<ServerProviderModel>;
   modelOptions: ReadonlyArray<ProviderOptionSelection> | undefined;
   reportedModelSelection?: ModelSelection | null | undefined;
-  prompt: string;
-  onPromptChange: (prompt: string) => void;
+  promptUltrathink: PromptUltrathink;
+  onPromptEdit: (edit: (prompt: string) => string) => void;
   planModeEnabled: boolean;
   size?: ComposerControlSize;
   hidden?: boolean;
@@ -230,8 +231,8 @@
     models,
     modelOptions,
     reportedModelSelection,
-    prompt,
+    promptUltrathink,
+    onPromptEdit,
-    onPromptChange,
     planModeEnabled,
     size,
     hidden,
@@ -253,7 +254,7 @@
       models,
       model,
       modelOptions: resolvedModelOptions,
-      prompt,
+      promptUltrathink,
       planModeEnabled,
     })
   ) {
@@ -269,8 +270,8 @@
       model={model}
       modelOptions={resolvedModelOptions}
       reportedModelSelection={reportedModelSelection}
+      promptUltrathink={promptUltrathink}
-      prompt={prompt}
+      onPromptEdit={onPromptEdit}
-      onPromptChange={onPromptChange}
       planModeEnabled={planModeEnabled}
       {...(size !== undefined ? { size } : {})}
       {...(hidden !== undefined ? { hidden } : {})}
```

## apps/web/src/components/settings/ProjectDefaultsSettings.tsx

Status: modified; +0; −2

```diff
@@ -191,8 +191,6 @@
                 provider={activeEntry.driverKind}
                 models={activeEntry.models}
                 model={selection.model}
-                prompt=""
-                onPromptChange={() => {}}
                 modelOptions={selection.options ?? []}
                 allowPromptInjectedEffort={false}
                 planModeEnabled={settings.planModeEnabled}
```

## apps/web/src/components/settings/SettingsPanels.tsx

Status: modified; +0; −2

```diff
@@ -1853,8 +1853,6 @@
                     provider={textGenProvider}
                     models={textGenInstanceEntry?.models ?? []}
                     model={textGenModel}
-                    prompt=""
-                    onPromptChange={() => {}}
                     modelOptions={textGenModelOptions}
                     allowPromptInjectedEffort={false}
                     planModeEnabled={
```

## apps/web/src/components/settings/SourceControlWritingSettings.tsx

Status: modified; +0; −4

```diff
@@ -397,8 +397,6 @@
                   provider={writerInstanceEntry.driverKind}
                   models={writerInstanceEntry.models}
                   model={activeSelection.model}
-                  prompt=""
-                  onPromptChange={() => {}}
                   modelOptions={activeSelection.options ?? []}
                   allowPromptInjectedEffort={false}
                   planModeEnabled={
@@ -503,8 +501,6 @@
                       provider={reviewGuideInstanceEntry.driverKind}
                       models={reviewGuideInstanceEntry.models}
                       model={reviewGuideSelection.model}
-                      prompt=""
-                      onPromptChange={() => {}}
                       modelOptions={reviewGuideSelection.options ?? []}
                       allowPromptInjectedEffort={false}
                       planModeEnabled={
```
